001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.compiler;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.List;
021: import java.util.Locale;
022:
023: import junit.textui.TestRunner;
024:
025: import org.apache.commons.jxpath.ClassFunctions;
026: import org.apache.commons.jxpath.ExpressionContext;
027: import org.apache.commons.jxpath.Function;
028: import org.apache.commons.jxpath.FunctionLibrary;
029: import org.apache.commons.jxpath.Functions;
030: import org.apache.commons.jxpath.JXPathContext;
031: import org.apache.commons.jxpath.JXPathTestCase;
032: import org.apache.commons.jxpath.PackageFunctions;
033: import org.apache.commons.jxpath.Pointer;
034: import org.apache.commons.jxpath.TestBean;
035: import org.apache.commons.jxpath.Variables;
036: import org.apache.commons.jxpath.ri.model.NodePointer;
037:
038: /**
039: * Test extension functions.
040: *
041: * @author Dmitri Plotnikov
042: * @version $Revision: 1.16 $ $Date: 2004/04/04 23:16:24 $
043: */
044:
045: public class ExtensionFunctionTest extends JXPathTestCase {
046: private Functions functions;
047: private JXPathContext context;
048:
049: public static void main(String[] args) {
050: TestRunner.run(ExtensionFunctionTest.class);
051: }
052:
053: /**
054: * Construct a new instance of this test case.
055: *
056: * @param name Name of the test case
057: */
058: public ExtensionFunctionTest(String name) {
059: super (name);
060: }
061:
062: public void setUp() {
063: if (context == null) {
064: context = JXPathContext.newContext(new TestBean());
065: Variables vars = context.getVariables();
066: vars.declareVariable("test", new TestFunctions(4, "test"));
067:
068: FunctionLibrary lib = new FunctionLibrary();
069: lib.addFunctions(new ClassFunctions(TestFunctions.class,
070: "test"));
071: lib.addFunctions(new ClassFunctions(TestFunctions2.class,
072: "test"));
073: lib.addFunctions(new PackageFunctions("", "call"));
074: lib.addFunctions(new PackageFunctions(
075: "org.apache.commons.jxpath.ri.compiler.",
076: "jxpathtest"));
077: lib.addFunctions(new PackageFunctions("", null));
078: context.setFunctions(lib);
079: }
080: functions = new ClassFunctions(TestFunctions.class, "test");
081: }
082:
083: public void testConstructorLookup() {
084: Object[] args = new Object[] { new Integer(1), "x" };
085: Function func = functions.getFunction("test", "new", args);
086:
087: assertEquals("test:new(1, x)", func.invoke(new Context(null),
088: args).toString(), "foo=1; bar=x");
089: }
090:
091: public void testConstructorLookupWithExpressionContext() {
092: Object[] args = new Object[] { "baz" };
093: Function func = functions.getFunction("test", "new", args);
094: assertEquals("test:new('baz')", func.invoke(
095: new Context(new Integer(1)), args).toString(),
096: "foo=1; bar=baz");
097: }
098:
099: public void testStaticMethodLookup() {
100: Object[] args = new Object[] { new Integer(1), "x" };
101: Function func = functions.getFunction("test", "build", args);
102: assertEquals("test:build(1, x)", func.invoke(new Context(null),
103: args).toString(), "foo=1; bar=x");
104: }
105:
106: public void testStaticMethodLookupWithConversion() {
107: Object[] args = new Object[] { "7", new Integer(1) };
108: Function func = functions.getFunction("test", "build", args);
109: assertEquals("test:build('7', 1)", func.invoke(
110: new Context(null), args).toString(), "foo=7; bar=1");
111: }
112:
113: public void testMethodLookup() {
114: Object[] args = new Object[] { new TestFunctions() };
115: Function func = functions.getFunction("test", "getFoo", args);
116: assertEquals("test:getFoo($test, 1, x)", func.invoke(
117: new Context(null), args).toString(), "0");
118: }
119:
120: public void testStaticMethodLookupWithExpressionContext() {
121: Object[] args = new Object[0];
122: Function func = functions.getFunction("test", "path", args);
123: assertEquals("test:path()", func.invoke(new Context(
124: new Integer(1)), args), "1");
125: }
126:
127: public void testMethodLookupWithExpressionContext() {
128: Object[] args = new Object[] { new TestFunctions() };
129: Function func = functions.getFunction("test", "instancePath",
130: args);
131: assertEquals("test:instancePath()", func.invoke(new Context(
132: new Integer(1)), args), "1");
133: }
134:
135: public void testMethodLookupWithExpressionContextAndArgument() {
136: Object[] args = new Object[] { new TestFunctions(), "*" };
137: Function func = functions.getFunction("test", "pathWithSuffix",
138: args);
139: assertEquals("test:pathWithSuffix('*')", func.invoke(
140: new Context(new Integer(1)), args), "1*");
141: }
142:
143: public void testAllocation() {
144:
145: // Allocate new object using the default constructor
146: assertXPathValue(context, "string(test:new())",
147: "foo=0; bar=null");
148:
149: // Allocate new object using PackageFunctions and class name
150: assertXPathValue(context,
151: "string(jxpathtest:TestFunctions.new())",
152: "foo=0; bar=null");
153:
154: // Allocate new object using a fully qualified class name
155: assertXPathValue(context, "string("
156: + TestFunctions.class.getName() + ".new())",
157: "foo=0; bar=null");
158:
159: // Allocate new object using a custom constructor
160: assertXPathValue(context, "string(test:new(3, 'baz'))",
161: "foo=3; bar=baz");
162:
163: // Allocate new object using a custom constructor - type conversion
164: assertXPathValue(context, "string(test:new('3', 4))",
165: "foo=3; bar=4.0");
166:
167: context.getVariables().declareVariable("A", "baz");
168: assertXPathValue(context, "string(test:new(2, $A, false))",
169: "foo=2; bar=baz");
170: }
171:
172: public void testMethodCall() {
173: assertXPathValue(context, "length('foo')", new Integer(3));
174:
175: // We are just calling a method - prefix is ignored
176: assertXPathValue(context, "call:substring('foo', 1, 2)", "o");
177:
178: // Invoke a function implemented as a regular method
179: assertXPathValue(context, "string(test:getFoo($test))", "4");
180:
181: // Note that the prefix is ignored anyway, we are just calling a method
182: assertXPathValue(context, "string(call:getFoo($test))", "4");
183:
184: // We don't really need to supply a prefix in this case
185: assertXPathValue(context, "string(getFoo($test))", "4");
186:
187: // Method with two arguments
188: assertXPathValue(context,
189: "string(test:setFooAndBar($test, 7, 'biz'))",
190: "foo=7; bar=biz");
191: }
192:
193: public void testCollectionMethodCall() {
194:
195: List list = new ArrayList();
196: list.add("foo");
197: context.getVariables().declareVariable("myList", list);
198:
199: assertXPathValue(context, "size($myList)", new Integer(1));
200:
201: assertXPathValue(context, "size(beans)", new Integer(2));
202:
203: context.getValue("add($myList, 'hello')");
204: assertEquals("After adding an element", 2, list.size());
205: }
206:
207: public void testStaticMethodCall() {
208:
209: assertXPathValue(context, "string(test:build(8, 'goober'))",
210: "foo=8; bar=goober");
211:
212: // Call a static method using PackageFunctions and class name
213: assertXPathValue(context,
214: "string(jxpathtest:TestFunctions.build(8, 'goober'))",
215: "foo=8; bar=goober");
216:
217: // Call a static method with a fully qualified class name
218: assertXPathValue(context, "string("
219: + TestFunctions.class.getName()
220: + ".build(8, 'goober'))", "foo=8; bar=goober");
221:
222: // Two ClassFunctions are sharing the same prefix.
223: // This is TestFunctions2
224: assertXPathValue(context, "string(test:increment(8))", "9");
225:
226: // See that a NodeSet gets properly converted to a string
227: assertXPathValue(context, "test:string(/beans/name)", "Name 1");
228: }
229:
230: public void testExpressionContext() {
231: // Execute an extension function for each node while searching
232: // The function uses ExpressionContext to get to the current
233: // node.
234: assertXPathValue(context, "//.[test:isMap()]/Key1", "Value 1");
235:
236: // The function gets all
237: // nodes in the context that match the pattern.
238: assertXPathValue(context,
239: "count(//.[test:count(strings) = 3])", new Double(7));
240:
241: // The function receives a collection of strings
242: // and checks their type for testing purposes
243: assertXPathValue(context, "test:count(//strings)", new Integer(
244: 21));
245:
246: // The function receives a collection of pointers
247: // and checks their type for testing purposes
248: assertXPathValue(context, "test:countPointers(//strings)",
249: new Integer(21));
250:
251: // The function uses ExpressionContext to get to the current
252: // pointer and returns its path.
253: assertXPathValue(context,
254: "/beans[contains(test:path(), '[2]')]/name", "Name 2");
255: }
256:
257: public void testCollectionReturn() {
258: assertXPathValueIterator(context, "test:collection()/name",
259: list("foo", "bar"));
260:
261: assertXPathPointerIterator(context, "test:collection()/name",
262: list("/.[1]/name", "/.[2]/name"));
263:
264: assertXPathValue(context, "test:collection()/name", "foo");
265:
266: assertXPathValue(context, "test:collection()/@name", "foo");
267:
268: List list = new ArrayList();
269: list.add("foo");
270: list.add("bar");
271: context.getVariables().declareVariable("list", list);
272: Object values = context.getValue("test:items($list)");
273: assertTrue("Return type: ", values instanceof Collection);
274: assertEquals("Return values: ", list, new ArrayList(
275: (Collection) values));
276: }
277:
278: public void testNodeSetReturn() {
279: assertXPathValueIterator(context, "test:nodeSet()/name", list(
280: "Name 1", "Name 2"));
281:
282: assertXPathPointerIterator(context, "test:nodeSet()/name",
283: list("/beans[1]/name", "/beans[2]/name"));
284:
285: assertXPathValueAndPointer(context, "test:nodeSet()/name",
286: "Name 1", "/beans[1]/name");
287:
288: assertXPathValueAndPointer(context, "test:nodeSet()/@name",
289: "Name 1", "/beans[1]/@name");
290: }
291:
292: private static class Context implements ExpressionContext {
293: private Object object;
294:
295: public Context(Object object) {
296: this .object = object;
297: }
298:
299: public Pointer getContextNodePointer() {
300: return NodePointer.newNodePointer(null, object, Locale
301: .getDefault());
302: }
303:
304: public List getContextNodeList() {
305: return null;
306: }
307:
308: public JXPathContext getJXPathContext() {
309: return null;
310: }
311:
312: public int getPosition() {
313: return 0;
314: }
315: }
316: }
|