View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jxpath.ri;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  
22  import org.apache.commons.jxpath.AbstractJXPathTest;
23  import org.apache.commons.jxpath.JXPathContext;
24  import org.apache.commons.jxpath.ri.compiler.Constant;
25  import org.apache.commons.jxpath.ri.compiler.CoreFunction;
26  import org.apache.commons.jxpath.ri.compiler.CoreOperationAdd;
27  import org.apache.commons.jxpath.ri.compiler.CoreOperationAnd;
28  import org.apache.commons.jxpath.ri.compiler.CoreOperationDivide;
29  import org.apache.commons.jxpath.ri.compiler.CoreOperationEqual;
30  import org.apache.commons.jxpath.ri.compiler.CoreOperationGreaterThan;
31  import org.apache.commons.jxpath.ri.compiler.CoreOperationGreaterThanOrEqual;
32  import org.apache.commons.jxpath.ri.compiler.CoreOperationLessThan;
33  import org.apache.commons.jxpath.ri.compiler.CoreOperationLessThanOrEqual;
34  import org.apache.commons.jxpath.ri.compiler.CoreOperationMod;
35  import org.apache.commons.jxpath.ri.compiler.CoreOperationMultiply;
36  import org.apache.commons.jxpath.ri.compiler.CoreOperationNegate;
37  import org.apache.commons.jxpath.ri.compiler.CoreOperationNotEqual;
38  import org.apache.commons.jxpath.ri.compiler.CoreOperationOr;
39  import org.apache.commons.jxpath.ri.compiler.CoreOperationSubtract;
40  import org.apache.commons.jxpath.ri.compiler.CoreOperationUnion;
41  import org.apache.commons.jxpath.ri.compiler.ExpressionPath;
42  import org.apache.commons.jxpath.ri.compiler.ExtensionFunction;
43  import org.apache.commons.jxpath.ri.compiler.LocationPath;
44  import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
45  import org.apache.commons.jxpath.ri.compiler.VariableReference;
46  import org.junit.jupiter.api.Test;
47  
48  /**
49   * Test compiler.
50   */
51  public class JXPathCompiledExpressionTest extends AbstractJXPathTest {
52  
53      private void assertXPathExpression(final String xpath, final Class expectedClass) {
54          assertXPathExpression(xpath, expectedClass, xpath);
55      }
56  
57      /**
58       * Compiles the XPath into an Expression, checks the expression class, converts the expression to string and checks that the string matches the expected
59       * one.
60       */
61      private void assertXPathExpression(final String xpath, final Class expectedClass, final String expected) {
62          final JXPathCompiledExpression expression = (JXPathCompiledExpression) JXPathContext.compile(xpath);
63          assertEquals(expectedClass, expression.getExpression().getClass(), "Expression class for " + xpath);
64          assertEquals(expected, expression.getExpression().toString(), "Expression toString() for " + xpath);
65      }
66  
67      @Test
68      public void testConstant() {
69          assertXPathExpression("1", Constant.class);
70          assertXPathExpression("1.5", Constant.class);
71          assertXPathExpression("'foo'", Constant.class);
72      }
73  
74      @Test
75      public void testCoreFunction() {
76          assertXPathExpression("last()", CoreFunction.class);
77          assertXPathExpression("position()", CoreFunction.class);
78          assertXPathExpression("count(book)", CoreFunction.class);
79          assertXPathExpression("id(13)", CoreFunction.class);
80          assertXPathExpression("local-name()", CoreFunction.class);
81          assertXPathExpression("local-name(book)", CoreFunction.class);
82          assertXPathExpression("namespace-uri()", CoreFunction.class);
83          assertXPathExpression("namespace-uri(book)", CoreFunction.class);
84          assertXPathExpression("name()", CoreFunction.class);
85          assertXPathExpression("name(book)", CoreFunction.class);
86          assertXPathExpression("string(3)", CoreFunction.class);
87          assertXPathExpression("concat('a', 'b')", CoreFunction.class);
88          assertXPathExpression("starts-with('a', 'b')", CoreFunction.class);
89          assertXPathExpression("ends-with('a', 'b')", CoreFunction.class);
90          assertXPathExpression("contains('a', 'b')", CoreFunction.class);
91          assertXPathExpression("substring-before('a', 1)", CoreFunction.class);
92          assertXPathExpression("substring-after('a', 2)", CoreFunction.class);
93          assertXPathExpression("substring('a', 2)", CoreFunction.class);
94          assertXPathExpression("substring('a', 2, 3)", CoreFunction.class);
95          assertXPathExpression("string-length('a')", CoreFunction.class);
96          assertXPathExpression("normalize-space('a')", CoreFunction.class);
97          assertXPathExpression("translate('a', 'b', 'c')", CoreFunction.class);
98          assertXPathExpression("boolean('true')", CoreFunction.class);
99          assertXPathExpression("not(1)", CoreFunction.class);
100         assertXPathExpression("true()", CoreFunction.class);
101         assertXPathExpression("false()", CoreFunction.class);
102         assertXPathExpression("lang('fr')", CoreFunction.class);
103         assertXPathExpression("number('12')", CoreFunction.class);
104         assertXPathExpression("sum(book/price)", CoreFunction.class);
105         assertXPathExpression("floor(11.4)", CoreFunction.class);
106         assertXPathExpression("ceiling(11.4)", CoreFunction.class);
107         assertXPathExpression("round(11.4)", CoreFunction.class);
108         assertXPathExpression("key('title', 'Hobbit')", CoreFunction.class);
109         assertXPathExpression("format-number(12, '##')", CoreFunction.class);
110     }
111 
112     @Test
113     public void testCoreOperationAnd() {
114         assertXPathExpression("2 and 4", CoreOperationAnd.class);
115         assertXPathExpression("2 > 1 and 4 < 5", CoreOperationAnd.class);
116     }
117 
118     @Test
119     public void testCoreOperationDivide() {
120         assertXPathExpression("2 div 4", CoreOperationDivide.class);
121         assertXPathExpression("2|3 div -3", CoreOperationDivide.class, "2 | 3 div -3");
122     }
123 
124     @Test
125     public void testCoreOperationEqual() {
126         assertXPathExpression("2 = 4", CoreOperationEqual.class);
127         assertXPathExpression("2 + 1 = 3", CoreOperationEqual.class);
128     }
129 
130     @Test
131     public void testCoreOperationGreaterThan() {
132         assertXPathExpression("3>4", CoreOperationGreaterThan.class, "3 > 4");
133         assertXPathExpression("3>(2>=1)", CoreOperationGreaterThan.class, "3 > (2 >= 1)");
134         assertXPathExpression("1 > (1 and 2 <= (2 or 3) = 4)", CoreOperationGreaterThan.class);
135     }
136 
137     @Test
138     public void testCoreOperationGreaterThanOrEqual() {
139         assertXPathExpression("3>=4", CoreOperationGreaterThanOrEqual.class, "3 >= 4");
140         assertXPathExpression("3>=(2>=1)", CoreOperationGreaterThanOrEqual.class, "3 >= (2 >= 1)");
141     }
142 
143     @Test
144     public void testCoreOperationLessThan() {
145         assertXPathExpression("3<4", CoreOperationLessThan.class, "3 < 4");
146         assertXPathExpression("3<(2>=1)", CoreOperationLessThan.class, "3 < (2 >= 1)");
147     }
148 
149     @Test
150     public void testCoreOperationLessThanOrEqual() {
151         assertXPathExpression("3<=4", CoreOperationLessThanOrEqual.class, "3 <= 4");
152         assertXPathExpression("3<=(2>=1)", CoreOperationLessThanOrEqual.class, "3 <= (2 >= 1)");
153     }
154 
155     @Test
156     public void testCoreOperationMinus() {
157         assertXPathExpression("1 - 1", CoreOperationSubtract.class);
158         assertXPathExpression("1 - 1 - 2", CoreOperationSubtract.class);
159         assertXPathExpression("1 - (1 - 2)", CoreOperationSubtract.class);
160     }
161 
162     @Test
163     public void testCoreOperationMod() {
164         assertXPathExpression("2 mod 4", CoreOperationMod.class);
165         assertXPathExpression("2|3 mod -3", CoreOperationMod.class, "2 | 3 mod -3");
166     }
167 
168     @Test
169     public void testCoreOperationMultiply() {
170         assertXPathExpression("2*4", CoreOperationMultiply.class, "2 * 4");
171         assertXPathExpression("2*(3 + 1)", CoreOperationMultiply.class, "2 * (3 + 1)");
172     }
173 
174     @Test
175     public void testCoreOperationNameAttributeTest() {
176         assertXPathExpression("@name = 'bar'", NameAttributeTest.class);
177     }
178 
179     @Test
180     public void testCoreOperationNotEqual() {
181         assertXPathExpression("2 != 4", CoreOperationNotEqual.class);
182         assertXPathExpression("2 + 1 != 3", CoreOperationNotEqual.class);
183     }
184 
185     @Test
186     public void testCoreOperationOr() {
187         assertXPathExpression("2 or 4", CoreOperationOr.class);
188         assertXPathExpression("2 > 1 or 4 < 5", CoreOperationOr.class);
189         assertXPathExpression("1 > 1 and 2 <= 2 or 3 = 4", CoreOperationOr.class);
190     }
191 
192     @Test
193     public void testCoreOperationSum() {
194         assertXPathExpression("3 + 1 + 4", CoreOperationAdd.class);
195         assertXPathExpression("(3 + 1) + 4", CoreOperationAdd.class, "3 + 1 + 4");
196         assertXPathExpression("3 + (1 + 4)", CoreOperationAdd.class, "3 + 1 + 4");
197         assertXPathExpression("3 + -1", CoreOperationAdd.class, "3 + -1");
198         assertXPathExpression("2*-3 + -1", CoreOperationAdd.class, "2 * -3 + -1");
199     }
200 
201     @Test
202     public void testCoreOperationUnaryMinus() {
203         assertXPathExpression("-3", CoreOperationNegate.class);
204         assertXPathExpression("-(3 + 1)", CoreOperationNegate.class);
205     }
206 
207     @Test
208     public void testCoreOperationUnion() {
209         assertXPathExpression("3 | 1 | 4", CoreOperationUnion.class);
210     }
211 
212     @Test
213     public void testExpressionPath() {
214         assertXPathExpression("$x/foo/bar", ExpressionPath.class);
215         assertXPathExpression("(2 + 2)/foo/bar", ExpressionPath.class);
216         assertXPathExpression("$x[3][2 + 2]/foo/bar", ExpressionPath.class);
217     }
218 
219     @Test
220     public void testExtensionFunction() {
221         assertXPathExpression("my:function(3, other.function())", ExtensionFunction.class);
222     }
223 
224     @Test
225     public void testLocationPathAxisAttribute() {
226         assertXPathExpression("attribute::foo:bar", LocationPath.class, "@foo:bar");
227         assertXPathExpression("@foo:bar", LocationPath.class);
228         assertXPathExpression("../@foo:bar", LocationPath.class);
229         assertXPathExpression("@*", LocationPath.class);
230         assertXPathExpression("@*[last()]", LocationPath.class);
231     }
232 
233     @Test
234     public void testLocationPathAxisChild() {
235         assertXPathExpression("child::foo:bar", LocationPath.class, "foo:bar");
236         assertXPathExpression("foo:bar", LocationPath.class);
237         assertXPathExpression("/foo:bar", LocationPath.class);
238         assertXPathExpression("/foo/bar", LocationPath.class);
239         assertXPathExpression("*", LocationPath.class);
240         assertXPathExpression("foo:*", LocationPath.class);
241     }
242 
243     @Test
244     public void testLocationPathAxisDescendant() {
245         assertXPathExpression("descendant::foo:bar", LocationPath.class);
246     }
247 
248     @Test
249     public void testLocationPathAxisDescendantOrSelf() {
250         assertXPathExpression("descendant-or-self::foo:bar", LocationPath.class);
251         assertXPathExpression("//foo", LocationPath.class);
252         assertXPathExpression("foo//bar", LocationPath.class);
253     }
254 
255     @Test
256     public void testLocationPathAxisOther() {
257         assertXPathExpression("ancestor::foo:bar", LocationPath.class);
258         assertXPathExpression("ancestor-or-self::foo:bar", LocationPath.class);
259         assertXPathExpression("namespace::foo:bar", LocationPath.class);
260         assertXPathExpression("preceding::foo:bar", LocationPath.class);
261         assertXPathExpression("preceding-sibling::foo:bar", LocationPath.class);
262         assertXPathExpression("following::foo:bar", LocationPath.class);
263         assertXPathExpression("following-sibling::foo:bar", LocationPath.class);
264     }
265 
266     @Test
267     public void testLocationPathAxisParent() {
268         assertXPathExpression("parent::foo:bar", LocationPath.class);
269         assertXPathExpression("..", LocationPath.class);
270     }
271 
272     @Test
273     public void testLocationPathAxisSelf() {
274         assertXPathExpression("self::foo:bar", LocationPath.class);
275         assertXPathExpression(".", LocationPath.class);
276     }
277 
278     @Test
279     public void testLocationPathNodeTest() {
280         assertXPathExpression("node()", LocationPath.class);
281         assertXPathExpression("text()", LocationPath.class);
282         assertXPathExpression("comment()", LocationPath.class);
283         assertXPathExpression("processing-instruction()", LocationPath.class);
284         assertXPathExpression("processing-instruction('test')", LocationPath.class);
285     }
286 
287     @Test
288     public void testVariableReference() {
289         assertXPathExpression("$x", VariableReference.class);
290         assertXPathExpression("$x:y", VariableReference.class);
291     }
292 }