1   /*
2    * Copyright 1999-2004 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jxpath.ri;
17  
18  import org.apache.commons.jxpath.JXPathContext;
19  import org.apache.commons.jxpath.JXPathTestCase;
20  import org.apache.commons.jxpath.ri.compiler.Constant;
21  import org.apache.commons.jxpath.ri.compiler.CoreFunction;
22  import org.apache.commons.jxpath.ri.compiler.CoreOperationAdd;
23  import org.apache.commons.jxpath.ri.compiler.CoreOperationAnd;
24  import org.apache.commons.jxpath.ri.compiler.CoreOperationDivide;
25  import org.apache.commons.jxpath.ri.compiler.CoreOperationEqual;
26  import org.apache.commons.jxpath.ri.compiler.CoreOperationGreaterThan;
27  import org.apache.commons.jxpath.ri.compiler.CoreOperationGreaterThanOrEqual;
28  import org.apache.commons.jxpath.ri.compiler.CoreOperationLessThan;
29  import org.apache.commons.jxpath.ri.compiler.CoreOperationLessThanOrEqual;
30  import org.apache.commons.jxpath.ri.compiler.CoreOperationMod;
31  import org.apache.commons.jxpath.ri.compiler.CoreOperationMultiply;
32  import org.apache.commons.jxpath.ri.compiler.CoreOperationNegate;
33  import org.apache.commons.jxpath.ri.compiler.CoreOperationNotEqual;
34  import org.apache.commons.jxpath.ri.compiler.CoreOperationOr;
35  import org.apache.commons.jxpath.ri.compiler.CoreOperationSubtract;
36  import org.apache.commons.jxpath.ri.compiler.CoreOperationUnion;
37  import org.apache.commons.jxpath.ri.compiler.ExpressionPath;
38  import org.apache.commons.jxpath.ri.compiler.ExtensionFunction;
39  import org.apache.commons.jxpath.ri.compiler.LocationPath;
40  import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
41  import org.apache.commons.jxpath.ri.compiler.VariableReference;
42  
43  /***
44   * Test compiler.
45   *
46   * @author Dmitri Plotnikov
47   * @version $Revision: 1.5 $ $Date: 2004/02/29 14:17:44 $
48   */
49  
50  public class JXPathCompiledExpressionTest extends JXPathTestCase {
51      
52      /***
53       * Construct a new instance of this test case.
54       *
55       * @param name Name of the test case
56       */
57      public JXPathCompiledExpressionTest(String name) {
58          super(name);
59      }
60  
61      public void testConstant() {
62          assertXPathExpression("1", Constant.class);
63          assertXPathExpression("1.5", Constant.class);
64          assertXPathExpression("'foo'", Constant.class);
65      }
66      
67      public void testCoreFunction() {
68          assertXPathExpression("last()", CoreFunction.class);
69          assertXPathExpression("position()", CoreFunction.class);
70          assertXPathExpression("count(book)", CoreFunction.class);
71          assertXPathExpression("id(13)", CoreFunction.class);
72          assertXPathExpression("local-name()", CoreFunction.class);
73          assertXPathExpression("local-name(book)", CoreFunction.class);
74          assertXPathExpression("namespace-uri()", CoreFunction.class);
75          assertXPathExpression("namespace-uri(book)", CoreFunction.class);
76          assertXPathExpression("name()", CoreFunction.class);
77          assertXPathExpression("name(book)", CoreFunction.class);
78          assertXPathExpression("string(3)", CoreFunction.class);
79          assertXPathExpression("concat('a', 'b')", CoreFunction.class);
80          assertXPathExpression("starts-with('a', 'b')", CoreFunction.class);
81          assertXPathExpression("contains('a', 'b')", CoreFunction.class);
82          assertXPathExpression("substring-before('a', 1)", CoreFunction.class);
83          assertXPathExpression("substring-after('a', 2)", CoreFunction.class);
84          assertXPathExpression("substring('a', 2)", CoreFunction.class);
85          assertXPathExpression("substring('a', 2, 3)", CoreFunction.class);
86          assertXPathExpression("string-length('a')", CoreFunction.class);
87          assertXPathExpression("normalize-space('a')", CoreFunction.class);
88          assertXPathExpression("translate('a', 'b', 'c')", CoreFunction.class);
89          assertXPathExpression("boolean('true')", CoreFunction.class);
90          assertXPathExpression("not(1)", CoreFunction.class);
91          assertXPathExpression("true()", CoreFunction.class);
92          assertXPathExpression("false()", CoreFunction.class);
93          assertXPathExpression("lang('fr')", CoreFunction.class);
94          assertXPathExpression("number('12')", CoreFunction.class);
95          assertXPathExpression("sum(book/price)", CoreFunction.class);
96          assertXPathExpression("floor(11.4)", CoreFunction.class);
97          assertXPathExpression("ceiling(11.4)", CoreFunction.class);
98          assertXPathExpression("round(11.4)", CoreFunction.class);
99          assertXPathExpression("key('title', 'Hobbit')", CoreFunction.class);
100         assertXPathExpression("format-number(12, '##')", CoreFunction.class);
101     }
102     
103     public void testCoreOperationAnd() {
104         assertXPathExpression(
105             "2 and 4",
106             CoreOperationAnd.class);
107 
108         assertXPathExpression(
109             "2 > 1 and 4 < 5",
110             CoreOperationAnd.class);            
111     }
112         
113     public void testCoreOperationOr() {
114         assertXPathExpression(
115             "2 or 4",
116             CoreOperationOr.class);
117 
118         assertXPathExpression(
119             "2 > 1 or 4 < 5",
120             CoreOperationOr.class);
121 
122         assertXPathExpression(
123             "1 > 1 and 2 <= 2 or 3 = 4",
124             CoreOperationOr.class);
125     }
126 
127     public void testCoreOperationEqual() {
128         assertXPathExpression(
129             "2 = 4",
130             CoreOperationEqual.class);
131 
132         assertXPathExpression(
133             "2 + 1 = 3",
134             CoreOperationEqual.class);
135     }
136     
137     public void testCoreOperationNameAttributeTest() {
138         assertXPathExpression(
139             "@name = 'bar'",
140             NameAttributeTest.class);
141     }
142 
143     public void testCoreOperationNotEqual() {
144         assertXPathExpression(
145             "2 != 4",
146             CoreOperationNotEqual.class);
147 
148         assertXPathExpression(
149             "2 + 1 != 3",
150             CoreOperationNotEqual.class);
151     }
152 
153     public void testCoreOperationLessThan() {
154         assertXPathExpression(
155             "3<4",
156             CoreOperationLessThan.class,
157             "3 < 4");
158 
159         assertXPathExpression(
160             "3<(2>=1)",
161             CoreOperationLessThan.class,
162             "3 < (2 >= 1)");
163     }
164     
165     public void testCoreOperationLessThanOrEqual() {
166         assertXPathExpression(
167             "3<=4",
168             CoreOperationLessThanOrEqual.class,
169             "3 <= 4");
170 
171         assertXPathExpression(
172             "3<=(2>=1)",
173             CoreOperationLessThanOrEqual.class,
174             "3 <= (2 >= 1)");
175     }
176 
177     public void testCoreOperationGreaterThan() {
178         assertXPathExpression(
179             "3>4",
180             CoreOperationGreaterThan.class,
181             "3 > 4");
182 
183         assertXPathExpression(
184             "3>(2>=1)",
185             CoreOperationGreaterThan.class,
186             "3 > (2 >= 1)");
187 
188         assertXPathExpression(
189             "1 > (1 and 2 <= (2 or 3) = 4)",
190             CoreOperationGreaterThan.class);
191     }
192     
193     public void testCoreOperationGreaterThanOrEqual() {
194         assertXPathExpression(
195             "3>=4",
196             CoreOperationGreaterThanOrEqual.class,
197             "3 >= 4");
198 
199         assertXPathExpression(
200             "3>=(2>=1)",
201             CoreOperationGreaterThanOrEqual.class,
202             "3 >= (2 >= 1)");
203     }
204 
205     public void testCoreOperationDivide() {
206         assertXPathExpression(
207             "2 div 4",
208             CoreOperationDivide.class);
209 
210         assertXPathExpression(
211             "2|3 div -3",
212             CoreOperationDivide.class,
213             "2 | 3 div -3");
214     }
215 
216     public void testCoreOperationMod() {
217         assertXPathExpression(
218             "2 mod 4",
219             CoreOperationMod.class);
220 
221         assertXPathExpression(
222             "2|3 mod -3",
223             CoreOperationMod.class,
224             "2 | 3 mod -3");
225     }
226 
227     public void testCoreOperationMultiply() {
228         assertXPathExpression(
229             "2*4",
230             CoreOperationMultiply.class,
231             "2 * 4");
232             
233         assertXPathExpression(
234             "2*(3 + 1)",
235             CoreOperationMultiply.class,
236             "2 * (3 + 1)");
237     }
238     
239     public void testCoreOperationMinus() {
240         assertXPathExpression(
241             "1 - 1",
242             CoreOperationSubtract.class);
243             
244         assertXPathExpression(
245             "1 - 1 - 2",
246             CoreOperationSubtract.class);
247             
248         assertXPathExpression(
249             "1 - (1 - 2)",
250             CoreOperationSubtract.class);
251     }
252     
253     public void testCoreOperationSum() {
254         assertXPathExpression(
255             "3 + 1 + 4", 
256             CoreOperationAdd.class);
257             
258         assertXPathExpression(
259             "(3 + 1) + 4",
260             CoreOperationAdd.class,
261             "3 + 1 + 4");
262             
263         assertXPathExpression(
264             "3 + (1 + 4)",
265             CoreOperationAdd.class,
266             "3 + 1 + 4");
267             
268         assertXPathExpression(
269             "3 + -1", 
270             CoreOperationAdd.class, 
271             "3 + -1");
272             
273         assertXPathExpression(
274             "2*-3 + -1",
275             CoreOperationAdd.class,
276             "2 * -3 + -1");
277     }
278     
279     public void testCoreOperationUnaryMinus() {
280         assertXPathExpression("-3", CoreOperationNegate.class);
281         assertXPathExpression("-(3 + 1)", CoreOperationNegate.class);
282     }
283 
284     public void testCoreOperationUnion() {
285         assertXPathExpression(
286             "3 | 1 | 4",
287             CoreOperationUnion.class);
288     }
289     
290     public void testExpressionPath() {
291         assertXPathExpression(
292             "$x/foo/bar",
293             ExpressionPath.class);        
294         assertXPathExpression(
295             "(2 + 2)/foo/bar",
296             ExpressionPath.class);        
297         assertXPathExpression(
298             "$x[3][2 + 2]/foo/bar",
299             ExpressionPath.class);        
300     }
301     
302     public void testExtensionFunction() {
303         assertXPathExpression(
304             "my:function(3, other.function())",
305             ExtensionFunction.class);        
306     }
307  
308     public void testLocationPathAxisSelf() {
309         assertXPathExpression(
310             "self::foo:bar",
311             LocationPath.class);
312                  
313         assertXPathExpression(
314             ".",
315             LocationPath.class);     
316     }
317     
318     public void testLocationPathAxisChild() {
319         assertXPathExpression(
320             "child::foo:bar",
321             LocationPath.class,
322             "foo:bar");
323                  
324         assertXPathExpression(
325             "foo:bar",
326             LocationPath.class);
327                  
328         assertXPathExpression(
329             "/foo:bar",
330             LocationPath.class);
331                  
332         assertXPathExpression(
333             "/foo/bar",
334             LocationPath.class);     
335 
336         assertXPathExpression(
337             "*",
338             LocationPath.class);
339                  
340         assertXPathExpression(
341             "foo:*",
342             LocationPath.class);
343                  
344     }
345     
346     public void testLocationPathAxisParent() {
347         assertXPathExpression(
348             "parent::foo:bar",
349             LocationPath.class);
350                  
351         assertXPathExpression(
352             "..",
353             LocationPath.class);     
354     }
355     
356     public void testLocationPathAxisAttribute() {
357         assertXPathExpression(
358             "attribute::foo:bar",
359             LocationPath.class,
360             "@foo:bar");
361 
362         assertXPathExpression(
363             "@foo:bar",
364             LocationPath.class);
365 
366         assertXPathExpression(
367             "../@foo:bar",
368             LocationPath.class);
369 
370         assertXPathExpression(
371             "@*",
372             LocationPath.class);
373 
374         assertXPathExpression(
375             "@*[last()]",
376             LocationPath.class);
377     }
378     
379     public void testLocationPathAxisDescendant() {
380         assertXPathExpression(
381             "descendant::foo:bar",
382             LocationPath.class);
383     }
384     
385     public void testLocationPathAxisDescendantOrSelf() {
386         assertXPathExpression(
387             "descendant-or-self::foo:bar",
388             LocationPath.class);
389 
390         assertXPathExpression(
391             "//foo", 
392             LocationPath.class);
393 
394         assertXPathExpression(
395             "foo//bar", 
396             LocationPath.class);
397     }
398     
399     public void testLocationPathAxisOther() {
400         assertXPathExpression(
401             "ancestor::foo:bar",
402             LocationPath.class);
403             
404         assertXPathExpression(
405             "ancestor-or-self::foo:bar",
406             LocationPath.class);
407             
408         assertXPathExpression(
409             "namespace::foo:bar",
410             LocationPath.class);
411 
412         assertXPathExpression(
413             "preceding::foo:bar",
414             LocationPath.class);
415 
416         assertXPathExpression(
417             "preceding-sibling::foo:bar",
418             LocationPath.class);
419 
420         assertXPathExpression(
421             "following::foo:bar",
422             LocationPath.class);
423 
424         assertXPathExpression(
425             "following-sibling::foo:bar",
426             LocationPath.class);
427     }
428     
429     public void testLocationPathNodeTest() {
430         assertXPathExpression(
431             "node()",
432             LocationPath.class);
433 
434         assertXPathExpression(
435             "text()",
436             LocationPath.class);
437 
438         assertXPathExpression(
439             "comment()",
440             LocationPath.class);
441 
442         assertXPathExpression(
443             "processing-instruction()",
444             LocationPath.class);
445 
446         assertXPathExpression(
447             "processing-instruction('test')",
448             LocationPath.class);
449     }
450     
451     public void testVariableReference() {
452         assertXPathExpression(
453             "$x",
454             VariableReference.class);                
455 
456         assertXPathExpression(
457             "$x:y",
458             VariableReference.class);
459     }
460     
461     /***
462      * Compiles the xpath into an Expression, checks the expression
463      * class, converts the expression to string and checks that the string
464      * matches the expected one.
465      */
466     private void assertXPathExpression(
467         String xpath,
468         Class expectedClass,
469         String expected) 
470     {
471         JXPathCompiledExpression expression =
472             (JXPathCompiledExpression) JXPathContext.compile(xpath);
473         
474         assertEquals(
475             "Expression class for " + xpath,
476             expectedClass,
477             expression.getExpression().getClass());
478             
479         assertEquals(
480             "Expression toString() for " + xpath,
481             expected,
482             expression.getExpression().toString());
483     }
484     
485     private void assertXPathExpression(
486         String xpath,
487         Class expectedClass) 
488     {
489         assertXPathExpression(xpath, expectedClass, xpath);
490     }
491     
492 }