1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jxpath.ri.compiler;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.Locale;
23
24 import org.apache.commons.jxpath.ClassFunctions;
25 import org.apache.commons.jxpath.ExpressionContext;
26 import org.apache.commons.jxpath.Function;
27 import org.apache.commons.jxpath.FunctionLibrary;
28 import org.apache.commons.jxpath.Functions;
29 import org.apache.commons.jxpath.JXPathContext;
30 import org.apache.commons.jxpath.JXPathTestCase;
31 import org.apache.commons.jxpath.NodeSet;
32 import org.apache.commons.jxpath.PackageFunctions;
33 import org.apache.commons.jxpath.Pointer;
34 import org.apache.commons.jxpath.TestBean;
35 import org.apache.commons.jxpath.Variables;
36 import org.apache.commons.jxpath.ri.model.NodePointer;
37 import org.apache.commons.jxpath.util.JXPath11CompatibleTypeConverter;
38 import org.apache.commons.jxpath.util.TypeConverter;
39 import org.apache.commons.jxpath.util.TypeUtils;
40
41
42
43
44
45
46
47 public class ExtensionFunctionTest extends JXPathTestCase {
48 private Functions functions;
49 private JXPathContext context;
50 private TestBean testBean;
51 private TypeConverter typeConverter;
52
53 public void setUp() {
54 if (context == null) {
55 testBean = new TestBean();
56 context = JXPathContext.newContext(testBean);
57 Variables vars = context.getVariables();
58 vars.declareVariable("test", new TestFunctions(4, "test"));
59
60 FunctionLibrary lib = new FunctionLibrary();
61 lib.addFunctions(new ClassFunctions(TestFunctions.class, "test"));
62 lib.addFunctions(new ClassFunctions(TestFunctions2.class, "test"));
63 lib.addFunctions(new PackageFunctions("", "call"));
64 lib.addFunctions(
65 new PackageFunctions(
66 "org.apache.commons.jxpath.ri.compiler.",
67 "jxpathtest"));
68 lib.addFunctions(new PackageFunctions("", null));
69 context.setFunctions(lib);
70 context.getVariables().declareVariable("List.class", List.class);
71 context.getVariables().declareVariable("NodeSet.class", NodeSet.class);
72 }
73 functions = new ClassFunctions(TestFunctions.class, "test");
74 typeConverter = TypeUtils.getTypeConverter();
75 }
76
77 public void tearDown() {
78 TypeUtils.setTypeConverter(typeConverter);
79 }
80
81 public void testConstructorLookup() {
82 Object[] args = new Object[] { new Integer(1), "x" };
83 Function func = functions.getFunction("test", "new", args);
84
85 assertEquals(
86 "test:new(1, x)",
87 func.invoke(new Context(null), args).toString(),
88 "foo=1; bar=x");
89 }
90
91 public void testConstructorLookupWithExpressionContext() {
92 Object[] args = new Object[] { "baz" };
93 Function func = functions.getFunction("test", "new", args);
94 assertEquals(
95 "test:new('baz')",
96 func.invoke(new Context(new Integer(1)), args).toString(),
97 "foo=1; bar=baz");
98 }
99
100 public void testStaticMethodLookup() {
101 Object[] args = new Object[] { new Integer(1), "x" };
102 Function func = functions.getFunction("test", "build", args);
103 assertEquals(
104 "test:build(1, x)",
105 func.invoke(new Context(null), args).toString(),
106 "foo=1; bar=x");
107 }
108
109 public void testStaticMethodLookupWithConversion() {
110 Object[] args = new Object[] { "7", new Integer(1)};
111 Function func = functions.getFunction("test", "build", args);
112 assertEquals(
113 "test:build('7', 1)",
114 func.invoke(new Context(null), args).toString(),
115 "foo=7; bar=1");
116 }
117
118 public void testMethodLookup() {
119 Object[] args = new Object[] { new TestFunctions()};
120 Function func = functions.getFunction("test", "getFoo", args);
121 assertEquals(
122 "test:getFoo($test, 1, x)",
123 func.invoke(new Context(null), args).toString(),
124 "0");
125 }
126
127 public void testStaticMethodLookupWithExpressionContext() {
128 Object[] args = new Object[0];
129 Function func = functions.getFunction("test", "path", args);
130 assertEquals(
131 "test:path()",
132 func.invoke(new Context(new Integer(1)), args),
133 "1");
134 }
135
136 public void testMethodLookupWithExpressionContext() {
137 Object[] args = new Object[] { new TestFunctions()};
138 Function func = functions.getFunction("test", "instancePath", args);
139 assertEquals(
140 "test:instancePath()",
141 func.invoke(new Context(new Integer(1)), args),
142 "1");
143 }
144
145 public void testMethodLookupWithExpressionContextAndArgument() {
146 Object[] args = new Object[] { new TestFunctions(), "*" };
147 Function func = functions.getFunction("test", "pathWithSuffix", args);
148 assertEquals(
149 "test:pathWithSuffix('*')",
150 func.invoke(new Context(new Integer(1)), args),
151 "1*");
152 }
153
154 public void testAllocation() {
155
156
157 assertXPathValue(context, "string(test:new())", "foo=0; bar=null");
158
159
160 assertXPathValue(
161 context,
162 "string(jxpathtest:TestFunctions.new())",
163 "foo=0; bar=null");
164
165
166 assertXPathValue(
167 context,
168 "string(" + TestFunctions.class.getName() + ".new())",
169 "foo=0; bar=null");
170
171
172 assertXPathValue(
173 context,
174 "string(test:new(3, 'baz'))",
175 "foo=3; bar=baz");
176
177
178 assertXPathValue(context, "string(test:new('3', 4))", "foo=3; bar=4.0");
179
180 context.getVariables().declareVariable("A", "baz");
181 assertXPathValue(
182 context,
183 "string(test:new(2, $A, false))",
184 "foo=2; bar=baz");
185 }
186
187 public void testMethodCall() {
188 assertXPathValue(context, "length('foo')", new Integer(3));
189
190
191 assertXPathValue(context, "call:substring('foo', 1, 2)", "o");
192
193
194 assertXPathValue(context, "string(test:getFoo($test))", "4");
195
196
197 assertXPathValue(context, "string(call:getFoo($test))", "4");
198
199
200 assertXPathValue(context, "string(getFoo($test))", "4");
201
202
203 assertXPathValue(
204 context,
205 "string(test:setFooAndBar($test, 7, 'biz'))",
206 "foo=7; bar=biz");
207 }
208
209 public void testCollectionMethodCall() {
210
211 List list = new ArrayList();
212 list.add("foo");
213 context.getVariables().declareVariable("myList", list);
214
215 assertXPathValue(
216 context,
217 "size($myList)",
218 new Integer(1));
219
220 assertXPathValue(
221 context,
222 "size(beans)",
223 new Integer(2));
224
225 context.getValue("add($myList, 'hello')");
226 assertEquals("After adding an element", 2, list.size());
227
228 JXPathContext context = JXPathContext.newContext(new ArrayList());
229 assertEquals("Extension function on root collection", "0", String
230 .valueOf(context.getValue("size(/)")));
231 }
232
233 public void testStaticMethodCall() {
234
235 assertXPathValue(
236 context,
237 "string(test:build(8, 'goober'))",
238 "foo=8; bar=goober");
239
240
241 assertXPathValue(
242 context,
243 "string(jxpathtest:TestFunctions.build(8, 'goober'))",
244 "foo=8; bar=goober");
245
246
247 assertXPathValue(
248 context,
249 "string(" + TestFunctions.class.getName() + ".build(8, 'goober'))",
250 "foo=8; bar=goober");
251
252
253
254 assertXPathValue(context, "string(test:increment(8))", "9");
255
256
257 assertXPathValue(context, "test:string(/beans/name)", "Name 1");
258 }
259
260 public void testExpressionContext() {
261
262
263
264 assertXPathValue(
265 context,
266 "//.[test:isMap()]/Key1",
267 "Value 1");
268
269
270
271 assertXPathValue(
272 context,
273 "count(//.[test:count(strings) = 3])",
274 new Double(7));
275
276
277
278 assertXPathValue(
279 context,
280 "test:count(//strings)",
281 new Integer(21));
282
283
284
285
286 assertXPathValue(
287 context,
288 "test:countPointers(//strings)",
289 new Integer(21));
290
291
292
293 assertXPathValue(
294 context,
295 "/beans[contains(test:path(), '[2]')]/name",
296 "Name 2");
297 }
298
299 public void testCollectionReturn() {
300 assertXPathValueIterator(
301 context,
302 "test:collection()/name",
303 list("foo", "bar"));
304
305 assertXPathPointerIterator(
306 context,
307 "test:collection()/name",
308 list("/.[1]/name", "/.[2]/name"));
309
310 assertXPathValue(
311 context,
312 "test:collection()/name",
313 "foo");
314
315 assertXPathValue(
316 context,
317 "test:collection()/@name",
318 "foo");
319
320 List list = new ArrayList();
321 list.add("foo");
322 list.add("bar");
323 context.getVariables().declareVariable("list", list);
324 Object values = context.getValue("test:items($list)");
325 assertTrue("Return type: ", values instanceof Collection);
326 assertEquals(
327 "Return values: ",
328 list,
329 new ArrayList((Collection) values));
330 }
331
332 public void testNodeSetReturn() {
333 assertXPathValueIterator(
334 context,
335 "test:nodeSet()/name",
336 list("Name 1", "Name 2"));
337
338 assertXPathValueIterator(
339 context,
340 "test:nodeSet()",
341 list(testBean.getBeans()[0], testBean.getBeans()[1]));
342
343 assertXPathPointerIterator(
344 context,
345 "test:nodeSet()/name",
346 list("/beans[1]/name", "/beans[2]/name"));
347
348 assertXPathValueAndPointer(
349 context,
350 "test:nodeSet()/name",
351 "Name 1",
352 "/beans[1]/name");
353
354 assertXPathValueAndPointer(
355 context,
356 "test:nodeSet()/@name",
357 "Name 1",
358 "/beans[1]/@name");
359
360 assertEquals(2, ((Number) context.getValue("count(test:nodeSet())")).intValue());
361
362 assertXPathValue(context, "test:nodeSet()", testBean.getBeans()[0]);
363 }
364
365 public void testEstablishNodeSetBaseline() {
366 assertXPathValue(
367 context,
368 "test:isInstance(//strings, $List.class)",
369 Boolean.TRUE);
370 assertXPathValue(
371 context,
372 "test:isInstance(//strings, $NodeSet.class)",
373 Boolean.FALSE);
374 }
375
376 public void testBCNodeSetHack() {
377 TypeUtils.setTypeConverter(new JXPath11CompatibleTypeConverter());
378 assertXPathValue(
379 context,
380 "test:isInstance(//strings, $List.class)",
381 Boolean.FALSE);
382 assertXPathValue(
383 context,
384 "test:isInstance(//strings, $NodeSet.class)",
385 Boolean.TRUE);
386 }
387
388 private static class Context implements ExpressionContext {
389 private Object object;
390
391 public Context(Object object) {
392 this.object = object;
393 }
394
395 public Pointer getContextNodePointer() {
396 return NodePointer
397 .newNodePointer(null, object, Locale.getDefault());
398 }
399
400 public List getContextNodeList() {
401 return null;
402 }
403
404 public JXPathContext getJXPathContext() {
405 return null;
406 }
407
408 public int getPosition() {
409 return 0;
410 }
411 }
412 }