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.compiler;
19  
20  import java.text.DecimalFormatSymbols;
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.apache.commons.jxpath.AbstractJXPathTest;
25  import org.apache.commons.jxpath.ExtendedKeyManager;
26  import org.apache.commons.jxpath.JXPathContext;
27  import org.apache.commons.jxpath.NodeSet;
28  import org.apache.commons.jxpath.Pointer;
29  import org.apache.commons.jxpath.TestMixedModelBean;
30  import org.apache.commons.jxpath.Variables;
31  import org.apache.commons.jxpath.ri.model.NodePointer;
32  import org.junit.jupiter.api.BeforeEach;
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * Test basic functionality of JXPath - core functions.
37   */
38  public class CoreFunctionTest extends AbstractJXPathTest {
39  
40      private JXPathContext context;
41  
42      @Override
43      @BeforeEach
44      public void setUp() {
45          if (context == null) {
46              context = JXPathContext.newContext(new TestMixedModelBean());
47              final Variables vars = context.getVariables();
48              vars.declareVariable("nan", Double.NaN);
49              vars.declareVariable("bool_true", Boolean.TRUE);
50              vars.declareVariable("bool_false", Boolean.FALSE);
51          }
52      }
53  
54      @Test
55      public void testCoreFunctions() {
56          assertXPathValue(context, "string(2)", "2");
57          assertXPathValue(context, "string($nan)", "NaN");
58          assertXPathValue(context, "string(-$nan)", "NaN");
59          assertXPathValue(context, "string(-2 div 0)", "-Infinity");
60          assertXPathValue(context, "string(2 div 0)", "Infinity");
61          assertXPathValue(context, "concat('a', 'b', 'c')", "abc");
62          assertXPathValue(context, "starts-with('abc', 'ab')", Boolean.TRUE);
63          assertXPathValue(context, "starts-with('xabc', 'ab')", Boolean.FALSE);
64          assertXPathValue(context, "ends-with('abc', 'bc')", Boolean.TRUE);
65          assertXPathValue(context, "ends-with('xabc', 'ab')", Boolean.FALSE);
66          assertXPathValue(context, "contains('xabc', 'ab')", Boolean.TRUE);
67          assertXPathValue(context, "contains('xabc', 'ba')", Boolean.FALSE);
68          assertXPathValue(context, "substring-before('1999/04/01', '/')", "1999");
69          assertXPathValue(context, "substring-after('1999/04/01', '/')", "04/01");
70          assertXPathValue(context, "substring('12345', 2, 3)", "234");
71          assertXPathValue(context, "substring('12345', 2)", "2345");
72          assertXPathValue(context, "substring('12345', 1.5, 2.6)", "234");
73          assertXPathValue(context, "substring('12345', 0, 3)", "12");
74          assertXPathValue(context, "substring('12345', 0 div 0, 3)", "");
75          assertXPathValue(context, "substring('12345', 1, 0 div 0)", "");
76          assertXPathValue(context, "substring('12345', -42, 1 div 0)", "12345");
77          assertXPathValue(context, "substring('12345', -1 div 0, 1 div 0)", "");
78          assertXPathValue(context, "substring('12345', 6, 6)", "");
79          assertXPathValue(context, "substring('12345', 7, 8)", "");
80          assertXPathValue(context, "substring('12345', 7)", "");
81          assertXPathValue(context, "string-length('12345')", Double.valueOf(5));
82          assertXPathValue(context, "normalize-space(' abc  def  ')", "abc def");
83          assertXPathValue(context, "normalize-space('abc def')", "abc def");
84          assertXPathValue(context, "normalize-space('   ')", "");
85          assertXPathValue(context, "translate('--aaa--', 'abc-', 'ABC')", "AAA");
86          assertXPathValue(context, "boolean(1)", Boolean.TRUE);
87          assertXPathValue(context, "boolean(0)", Boolean.FALSE);
88          assertXPathValue(context, "boolean('x')", Boolean.TRUE);
89          assertXPathValue(context, "boolean('')", Boolean.FALSE);
90          assertXPathValue(context, "boolean(/list)", Boolean.TRUE);
91          assertXPathValue(context, "boolean(/list[position() < 1])", Boolean.FALSE);
92          assertXPathValue(context, "true()", Boolean.TRUE);
93          assertXPathValue(context, "false()", Boolean.FALSE);
94          assertXPathValue(context, "not(false())", Boolean.TRUE);
95          assertXPathValue(context, "not(true())", Boolean.FALSE);
96          assertXPathValue(context, "null()", null);
97          assertXPathValue(context, "number('1')", Double.valueOf(1));
98          assertXPathValue(context, "number($bool_true)", Double.valueOf(1));
99          assertXPathValue(context, "number($bool_false)", Double.valueOf(0));
100         assertXPathValue(context, "floor(1.5)", Double.valueOf(1));
101         assertXPathValue(context, "floor(-1.5)", Double.valueOf(-2));
102         assertXPathValue(context, "ceiling(1.5)", Double.valueOf(2));
103         assertXPathValue(context, "ceiling(-1.5)", Double.valueOf(-1));
104         assertXPathValue(context, "round(1.5)", Double.valueOf(2));
105         assertXPathValue(context, "round(-1.5)", Double.valueOf(-1));
106         assertXPathValue(context, "floor('NaN')", Double.valueOf(Double.NaN));
107         assertXPathValue(context, "floor(-2 div 0)", Double.valueOf(Double.NEGATIVE_INFINITY));
108         assertXPathValue(context, "floor(2 div 0)", Double.valueOf(Double.POSITIVE_INFINITY));
109         assertXPathValue(context, "ceiling('NaN')", Double.valueOf(Double.NaN));
110         assertXPathValue(context, "ceiling(-2 div 0)", Double.valueOf(Double.NEGATIVE_INFINITY));
111         assertXPathValue(context, "ceiling(2 div 0)", Double.valueOf(Double.POSITIVE_INFINITY));
112         assertXPathValue(context, "round('NaN')", Double.valueOf(Double.NaN));
113         assertXPathValue(context, "round(-2 div 0)", Double.valueOf(Double.NEGATIVE_INFINITY));
114         assertXPathValue(context, "round(2 div 0)", Double.valueOf(Double.POSITIVE_INFINITY));
115     }
116 
117     @Test
118     public void testExtendedKeyFunction() {
119         context.setKeyManager(new ExtendedKeyManager() {
120 
121             @Override
122             public NodeSet getNodeSetByKey(final JXPathContext context, final String keyName, final Object keyValue) {
123                 return new NodeSet() {
124 
125                     @Override
126                     public List getNodes() {
127                         return Arrays.asList("53", "64");
128                     }
129 
130                     @Override
131                     public List getPointers() {
132                         return Arrays.asList(NodePointer.newNodePointer(null, "53", null), NodePointer.newNodePointer(null, "64", null));
133                     }
134 
135                     @Override
136                     public List getValues() {
137                         return Arrays.asList("53", "64");
138                     }
139                 };
140             }
141 
142             @Override
143             public Pointer getPointerByKey(final JXPathContext context, final String key, final String value) {
144                 return NodePointer.newNodePointer(null, "incorrect", null);
145             }
146         });
147         assertXPathValue(context, "key('a', 'b')", "53");
148         assertXPathValue(context, "key('a', 'b')[1]", "53");
149         assertXPathValue(context, "key('a', 'b')[2]", "64");
150         assertXPathValueIterator(context, "key('a', 'b')", list("53", "64"));
151         assertXPathValueIterator(context, "'x' | 'y'", list("x", "y"));
152         assertXPathValueIterator(context, "key('a', 'x' | 'y')", list("53", "64", "53", "64"));
153         assertXPathValueIterator(context, "key('a', /list[position() < 4])", list("53", "64", "53", "64", "53", "64"));
154         context.getVariables().declareVariable("ints", new int[] { 0, 0 });
155         assertXPathValueIterator(context, "key('a', $ints)", list("53", "64", "53", "64"));
156     }
157 
158     @Test
159     public void testFormatNumberFunction() {
160         final DecimalFormatSymbols symbols = new DecimalFormatSymbols();
161         symbols.setDigit('D');
162         context.setDecimalFormatSymbols("test", symbols);
163         assertXPathValue(context, "format-number(123456789, '#.000000000')", "123456789.000000000");
164         assertXPathValue(context, "format-number(123456789, '#.0')", "123456789.0");
165         assertXPathValue(context, "format-number(0.123456789, '##%')", "12%");
166         assertXPathValue(context, "format-number(123456789, '################')", "123456789");
167         assertXPathValue(context, "format-number(123456789, 'D.0', 'test')", "123456789.0");
168         assertXPathValue(context, "format-number(123456789, '$DDD,DDD,DDD.DD', 'test')", "$123,456,789");
169     }
170 
171     @Test
172     public void testIDFunction() {
173         context.setIdentityManager((context, id) -> {
174             NodePointer ptr = (NodePointer) context.getPointer("/document");
175             ptr = ptr.getValuePointer();
176             return ptr.getPointerByID(context, id);
177         });
178         assertXPathValueAndPointer(context, "id(101)//street", "Tangerine Drive", "id('101')/address[1]/street[1]");
179         assertXPathPointerLenient(context, "id(105)/address/street", "id(105)/address/street");
180     }
181 
182     @Test
183     public void testKeyFunction() {
184         context.setKeyManager((context, key, value) -> NodePointer.newNodePointer(null, "42", null));
185         assertXPathValue(context, "key('a', 'b')", "42");
186     }
187 }