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.axes;
017:
018: import java.util.HashMap;
019:
020: import junit.framework.TestCase;
021:
022: import org.apache.commons.jxpath.JXPathContext;
023: import org.apache.commons.jxpath.NestedTestBean;
024: import org.apache.commons.jxpath.Pointer;
025: import org.apache.commons.jxpath.TestNull;
026: import org.apache.commons.jxpath.ri.model.NodePointer;
027: import org.apache.commons.jxpath.ri.model.VariablePointer;
028: import org.apache.commons.jxpath.ri.model.beans.BeanPointer;
029: import org.apache.commons.jxpath.ri.model.beans.BeanPropertyPointer;
030: import org.apache.commons.jxpath.ri.model.beans.CollectionPointer;
031: import org.apache.commons.jxpath.ri.model.beans.NullElementPointer;
032: import org.apache.commons.jxpath.ri.model.beans.NullPointer;
033: import org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer;
034: import org.apache.commons.jxpath.ri.model.beans.TestBeanFactory;
035: import org.apache.commons.jxpath.ri.model.dom.DOMNodePointer;
036: import org.apache.commons.jxpath.ri.model.dynamic.DynamicPointer;
037: import org.apache.commons.jxpath.ri.model.dynamic.DynamicPropertyPointer;
038:
039: public class SimplePathInterpreterTest extends TestCase {
040:
041: private TestBeanWithNode bean;
042: private JXPathContext context;
043:
044: /**
045: * Constructor for SimplePathInterpreterTest.
046: */
047: public SimplePathInterpreterTest(String name) {
048: super (name);
049: }
050:
051: public static void main(String[] args) {
052: junit.textui.TestRunner.run(SimplePathInterpreterTest.class);
053: }
054:
055: /**
056: * @see TestCase#setUp()
057: */
058: protected void setUp() throws Exception {
059: bean = TestBeanWithNode.createTestBeanWithDOM();
060: HashMap submap = new HashMap();
061: submap.put("key", new NestedTestBean("Name 9"));
062: submap.put("strings", bean.getNestedBean().getStrings());
063: bean.getList().add(new int[] { 1, 2 });
064: bean.getList().add(bean.getVendor());
065: bean.getMap().put(
066: "Key3",
067: new Object[] { new NestedTestBean("some"),
068: new Integer(2), bean.getVendor(), submap });
069: bean.getMap().put("Key4", bean.getVendor());
070: bean.getMap().put("Key5", submap);
071: bean.getMap().put("Key6", new Object[0]);
072: context = JXPathContext.newContext(null, bean);
073: context.setLenient(true);
074: context.setFactory(new TestBeanFactory());
075: }
076:
077: public void testDoStepNoPredicatesPropertyOwner() {
078: // Existing scalar property
079: assertValueAndPointer("/int", new Integer(1), "/int", "Bb",
080: "BbB");
081:
082: // self::
083: assertValueAndPointer("/./int", new Integer(1), "/int", "Bb",
084: "BbB");
085:
086: // Missing property
087: assertNullPointer("/foo", "/foo", "Bn");
088:
089: // existingProperty/existingScalarProperty
090: assertValueAndPointer("/nestedBean/int", new Integer(1),
091: "/nestedBean/int", "BbBb", "BbBbB");
092:
093: // existingProperty/collectionProperty
094: assertValueAndPointer("/nestedBean/strings", bean
095: .getNestedBean().getStrings(), "/nestedBean/strings",
096: "BbBb", "BbBbC");
097:
098: // existingProperty/missingProperty
099: assertNullPointer("/nestedBean/foo", "/nestedBean/foo", "BbBn");
100:
101: // map/missingProperty
102: assertNullPointer("/map/foo", "/map[@name='foo']", "BbDd");
103:
104: // Existing property by search in collection
105: assertValueAndPointer("/list/int", new Integer(1),
106: "/list[3]/int", "BbBb", "BbBbB");
107:
108: // Missing property by search in collection
109: assertNullPointer("/list/foo", "/list[1]/foo", "BbBn");
110:
111: // existingProperty/missingProperty/missingProperty
112: assertNullPointer("/nestedBean/foo/bar", "/nestedBean/foo/bar",
113: "BbBnNn");
114:
115: // collection/existingProperty/missingProperty
116: assertNullPointer("/list/int/bar", "/list[3]/int/bar", "BbBbBn");
117:
118: // collectionProperty/missingProperty/missingProperty
119: assertNullPointer("/list/foo/bar", "/list[1]/foo/bar", "BbBnNn");
120:
121: // map/missingProperty/anotherStep
122: assertNullPointer("/map/foo/bar", "/map[@name='foo']/bar",
123: "BbDdNn");
124:
125: // Existing dynamic property
126: assertValueAndPointer("/map/Key1", "Value 1",
127: "/map[@name='Key1']", "BbDd", "BbDdB");
128:
129: // collectionProperty
130: assertValueAndPointer("/integers", bean.getIntegers(),
131: "/integers", "Bb", "BbC");
132: }
133:
134: public void testDoStepNoPredicatesStandard() {
135: // Existing DOM node
136: assertValueAndPointer("/vendor/location/address/city",
137: "Fruit Market",
138: "/vendor/location[2]/address[1]/city[1]", "BbMMMM");
139:
140: // Missing DOM node
141: assertNullPointer("/vendor/location/address/pity",
142: "/vendor/location[1]/address[1]/pity", "BbMMMn");
143:
144: // Missing DOM node inside a missing element
145: assertNullPointer("/vendor/location/address/itty/bitty",
146: "/vendor/location[1]/address[1]/itty/bitty", "BbMMMnNn");
147:
148: // Missing DOM node by search for the best match
149: assertNullPointer("/vendor/location/address/city/pretty",
150: "/vendor/location[2]/address[1]/city[1]/pretty",
151: "BbMMMMn");
152: }
153:
154: public void testDoStepPredicatesPropertyOwner() {
155: // missingProperty[@name=foo]
156: assertNullPointer("/foo[@name='foo']", "/foo[@name='foo']",
157: "BnNn");
158:
159: // missingProperty[index]
160: assertNullPointer("/foo[3]", "/foo[3]", "Bn");
161: }
162:
163: public void testDoStepPredicatesStandard() {
164: // Looking for an actual XML attribute called "name"
165: // nodeProperty/name[@name=value]
166: assertValueAndPointer("/vendor/contact[@name='jack']", "Jack",
167: "/vendor/contact[2]", "BbMM");
168:
169: // Indexing in XML
170: assertValueAndPointer("/vendor/contact[2]", "Jack",
171: "/vendor/contact[2]", "BbMM");
172:
173: // Indexing in XML, no result
174: assertNullPointer("/vendor/contact[5]", "/vendor/contact[5]",
175: "BbMn");
176:
177: // Combination of search by name and indexing in XML
178: assertValueAndPointer("/vendor/contact[@name='jack'][2]",
179: "Jack Black", "/vendor/contact[4]", "BbMM");
180:
181: // Combination of search by name and indexing in XML
182: assertValueAndPointer("/vendor/contact[@name='jack'][2]",
183: "Jack Black", "/vendor/contact[4]", "BbMM");
184: }
185:
186: public void testDoPredicateName() {
187: // existingProperty[@name=existingProperty]
188: assertValueAndPointer("/nestedBean[@name='int']",
189: new Integer(1), "/nestedBean/int", "BbBb", "BbBbB");
190:
191: // /self::node()[@name=existingProperty]
192: assertValueAndPointer("/.[@name='int']", new Integer(1),
193: "/int", "Bb", "BbB");
194:
195: // dynamicProperty[@name=existingProperty]
196: assertValueAndPointer("/map[@name='Key1']", "Value 1",
197: "/map[@name='Key1']", "BbDd", "BbDdB");
198:
199: // existingProperty[@name=collectionProperty]
200: assertValueAndPointer("/nestedBean[@name='strings']", bean
201: .getNestedBean().getStrings(), "/nestedBean/strings",
202: "BbBb", "BbBbC");
203:
204: // existingProperty[@name=missingProperty]
205: assertNullPointer("/nestedBean[@name='foo']",
206: "/nestedBean[@name='foo']", "BbBn");
207:
208: // map[@name=collectionProperty]
209: assertValueAndPointer("/map[@name='Key3']", bean.getMap().get(
210: "Key3"), "/map[@name='Key3']", "BbDd", "BbDdC");
211:
212: // map[@name=missingProperty]
213: assertNullPointer("/map[@name='foo']", "/map[@name='foo']",
214: "BbDd");
215:
216: // collectionProperty[@name=...] (find node)
217: assertValueAndPointer("/list[@name='fruitco']", context
218: .getValue("/vendor"), "/list[5]", "BbCM");
219:
220: // collectionProperty[@name=...] (find map entry)
221: assertValueAndPointer("/map/Key3[@name='key']/name", "Name 9",
222: "/map[@name='Key3'][4][@name='key']/name", "BbDdCDdBb",
223: "BbDdCDdBbB");
224:
225: // map/collectionProperty[@name...]
226: assertValueAndPointer("map/Key3[@name='fruitco']", context
227: .getValue("/vendor"), "/map[@name='Key3'][3]", "BbDdCM");
228:
229: // Bean property -> DOM Node, name match
230: assertValueAndPointer("/vendor[@name='fruitco']", context
231: .getValue("/vendor"), "/vendor", "BbM");
232:
233: // Bean property -> DOM Node, name mismatch
234: assertNullPointer("/vendor[@name='foo']",
235: "/vendor[@name='foo']", "BbMn");
236:
237: assertNullPointer("/vendor[@name='foo'][3]",
238: "/vendor[@name='foo'][3]", "BbMn");
239:
240: // existingProperty(bean)[@name=missingProperty]/anotherStep
241: assertNullPointer("/nestedBean[@name='foo']/bar",
242: "/nestedBean[@name='foo']/bar", "BbBnNn");
243:
244: // map[@name=missingProperty]/anotherStep
245: assertNullPointer("/map[@name='foo']/bar",
246: "/map[@name='foo']/bar", "BbDdNn");
247:
248: // existingProperty(node)[@name=missingProperty]/anotherStep
249: assertNullPointer("/vendor[@name='foo']/bar",
250: "/vendor[@name='foo']/bar", "BbMnNn");
251:
252: // existingProperty(node)[@name=missingProperty][index]/anotherStep
253: assertNullPointer("/vendor[@name='foo'][3]/bar",
254: "/vendor[@name='foo'][3]/bar", "BbMnNn");
255:
256: // Existing dynamic property + existing property
257: assertValueAndPointer("/map[@name='Key2'][@name='name']",
258: "Name 6", "/map[@name='Key2']/name", "BbDdBb",
259: "BbDdBbB");
260:
261: // Existing dynamic property + existing property + index
262: assertValueAndPointer("/map[@name='Key2'][@name='strings'][2]",
263: "String 2", "/map[@name='Key2']/strings[2]", "BbDdBb",
264: "BbDdBbB");
265:
266: // bean/map/map/property
267: assertValueAndPointer("map[@name='Key5'][@name='key']/name",
268: "Name 9", "/map[@name='Key5'][@name='key']/name",
269: "BbDdDdBb", "BbDdDdBbB");
270:
271: assertNullPointer("map[@name='Key2'][@name='foo']",
272: "/map[@name='Key2'][@name='foo']", "BbDdBn");
273:
274: assertNullPointer(
275: "map[@name='Key2'][@name='foo'][@name='bar']",
276: "/map[@name='Key2'][@name='foo'][@name='bar']",
277: "BbDdBnNn");
278:
279: // bean/map/node
280: assertValueAndPointer("map[@name='Key4'][@name='fruitco']",
281: context.getValue("/vendor"), "/map[@name='Key4']",
282: "BbDdM");
283: }
284:
285: public void testDoPredicatesStandard() {
286: // bean/map/collection/node
287: assertValueAndPointer("map[@name='Key3'][@name='fruitco']",
288: context.getValue("/vendor"), "/map[@name='Key3'][3]",
289: "BbDdCM");
290:
291: // bean/map/collection/missingNode
292: assertNullPointer("map[@name='Key3'][@name='foo']",
293: "/map[@name='Key3'][4][@name='foo']", "BbDdCDd");
294:
295: // bean/map/node
296: assertValueAndPointer("map[@name='Key4'][@name='fruitco']",
297: context.getValue("/vendor"), "/map[@name='Key4']",
298: "BbDdM");
299:
300: // bean/map/emptyCollection[@name=foo]
301: assertNullPointer("map[@name='Key6'][@name='fruitco']",
302: "/map[@name='Key6'][@name='fruitco']", "BbDdCn");
303:
304: // bean/node[@name=foo][index]
305: assertValueAndPointer("/vendor/contact[@name='jack'][2]",
306: "Jack Black", "/vendor/contact[4]", "BbMM");
307:
308: // bean/node[@name=foo][missingIndex]
309: assertNullPointer("/vendor/contact[@name='jack'][5]",
310: "/vendor/contact[@name='jack'][5]", "BbMnNn");
311:
312: // bean/node/.[@name=foo][index]
313: assertValueAndPointer("/vendor/contact/.[@name='jack']",
314: "Jack", "/vendor/contact[2]", "BbMM");
315: }
316:
317: public void testDoPredicateIndex() {
318: // Existing dynamic property + existing property + index
319: assertValueAndPointer("/map[@name='Key2'][@name='strings'][2]",
320: "String 2", "/map[@name='Key2']/strings[2]", "BbDdBb",
321: "BbDdBbB");
322:
323: // existingProperty[@name=collectionProperty][index]
324: assertValueAndPointer("/nestedBean[@name='strings'][2]", bean
325: .getNestedBean().getStrings()[1],
326: "/nestedBean/strings[2]", "BbBb", "BbBbB");
327:
328: // existingProperty[@name=missingProperty][index]
329: assertNullPointer("/nestedBean[@name='foo'][3]",
330: "/nestedBean[@name='foo'][3]", "BbBn");
331:
332: // existingProperty[@name=collectionProperty][missingIndex]
333: assertNullPointer("/nestedBean[@name='strings'][5]",
334: "/nestedBean/strings[5]", "BbBbE");
335:
336: // map[@name=collectionProperty][index]
337: assertValueAndPointer("/map[@name='Key3'][2]", new Integer(2),
338: "/map[@name='Key3'][2]", "BbDd", "BbDdB");
339:
340: // map[@name=collectionProperty][missingIndex]
341: assertNullPointer("/map[@name='Key3'][5]",
342: "/map[@name='Key3'][5]", "BbDdE");
343:
344: // map[@name=collectionProperty][missingIndex]/property
345: assertNullPointer("/map[@name='Key3'][5]/foo",
346: "/map[@name='Key3'][5]/foo", "BbDdENn");
347:
348: // map[@name=map][@name=collection][index]
349: assertValueAndPointer("/map[@name='Key5'][@name='strings'][2]",
350: "String 2", "/map[@name='Key5'][@name='strings'][2]",
351: "BbDdDd", "BbDdDdB");
352:
353: // map[@name=map][@name=collection][missingIndex]
354: assertNullPointer("/map[@name='Key5'][@name='strings'][5]",
355: "/map[@name='Key5'][@name='strings'][5]", "BbDdDdE");
356:
357: // Existing dynamic property + indexing
358: assertValueAndPointer("/map[@name='Key3'][2]", new Integer(2),
359: "/map[@name='Key3'][2]", "BbDd", "BbDdB");
360:
361: // Existing dynamic property + indexing
362: assertValueAndPointer("/map[@name='Key3'][1]/name", "some",
363: "/map[@name='Key3'][1]/name", "BbDdBb", "BbDdBbB");
364:
365: // map[@name=missingProperty][index]
366: assertNullPointer("/map[@name='foo'][3]",
367: "/map[@name='foo'][3]", "BbDdE");
368:
369: // collectionProperty[index]
370: assertValueAndPointer("/integers[2]", new Integer(2),
371: "/integers[2]", "Bb", "BbB");
372:
373: // existingProperty/collectionProperty[index]
374: assertValueAndPointer("/nestedBean/strings[2]", bean
375: .getNestedBean().getStrings()[1],
376: "/nestedBean/strings[2]", "BbBb", "BbBbB");
377:
378: // existingProperty[index]/existingProperty
379: assertValueAndPointer("/list[3]/int", new Integer(1),
380: "/list[3]/int", "BbBb", "BbBbB");
381:
382: // existingProperty[missingIndex]
383: assertNullPointer("/list[6]", "/list[6]", "BbE");
384:
385: // existingProperty/missingProperty[index]
386: assertNullPointer("/nestedBean/foo[3]", "/nestedBean/foo[3]",
387: "BbBn");
388:
389: // map[@name=missingProperty][index]
390: assertNullPointer("/map/foo[3]", "/map[@name='foo'][3]",
391: "BbDdE");
392:
393: // existingProperty/collectionProperty[missingIndex]
394: assertNullPointer("/nestedBean/strings[5]",
395: "/nestedBean/strings[5]", "BbBbE");
396:
397: // map/collectionProperty[missingIndex]/property
398: assertNullPointer("/map/Key3[5]/foo",
399: "/map[@name='Key3'][5]/foo", "BbDdENn");
400:
401: // map[@name=map]/collection[index]
402: assertValueAndPointer("/map[@name='Key5']/strings[2]",
403: "String 2", "/map[@name='Key5'][@name='strings'][2]",
404: "BbDdDd", "BbDdDdB");
405:
406: // map[@name=map]/collection[missingIndex]
407: assertNullPointer("/map[@name='Key5']/strings[5]",
408: "/map[@name='Key5'][@name='strings'][5]", "BbDdDdE");
409:
410: // scalarPropertyAsCollection[index]
411: assertValueAndPointer("/int[1]", new Integer(1), "/int", "Bb",
412: "BbB");
413:
414: // scalarPropertyAsCollection[index]
415: assertValueAndPointer(".[1]/int", new Integer(1), "/int", "Bb",
416: "BbB");
417: }
418:
419: public void testInterpretExpressionPath() {
420: context.getVariables().declareVariable("array",
421: new String[] { "Value1" });
422: context.getVariables().declareVariable("testnull",
423: new TestNull());
424:
425: assertNullPointer("$testnull/nothing[2]",
426: "$testnull/nothing[2]", "VBbE");
427: }
428:
429: private void assertValueAndPointer(String path,
430: Object expectedValue, String expectedPath,
431: String expectedSignature) {
432: assertValueAndPointer(path, expectedValue, expectedPath,
433: expectedSignature, expectedSignature);
434: }
435:
436: private void assertValueAndPointer(String path,
437: Object expectedValue, String expectedPath,
438: String expectedSignature, String expectedValueSignature) {
439: Object value = context.getValue(path);
440: assertEquals("Checking value: " + path, expectedValue, value);
441:
442: Pointer pointer = context.getPointer(path);
443: assertEquals("Checking pointer: " + path, expectedPath, pointer
444: .toString());
445:
446: assertEquals("Checking signature: " + path, expectedSignature,
447: pointerSignature(pointer));
448:
449: Pointer vPointer = ((NodePointer) pointer).getValuePointer();
450: assertEquals("Checking value pointer signature: " + path,
451: expectedValueSignature, pointerSignature(vPointer));
452: }
453:
454: private void assertNullPointer(String path, String expectedPath,
455: String expectedSignature) {
456: Pointer pointer = context.getPointer(path);
457: assertNotNull("Null path exists: " + path, pointer);
458: assertEquals("Null path as path: " + path, expectedPath,
459: pointer.asPath());
460: assertEquals("Checking Signature: " + path, expectedSignature,
461: pointerSignature(pointer));
462:
463: Pointer vPointer = ((NodePointer) pointer).getValuePointer();
464: assertTrue("Null path is null: " + path,
465: !((NodePointer) vPointer).isActual());
466: assertEquals("Checking value pointer signature: " + path,
467: expectedSignature + "N", pointerSignature(vPointer));
468: }
469:
470: /**
471: * Since we need to test the internal Signature of a pointer,
472: * we will get a signature which will contain a single character
473: * per pointer in the chain, representing that pointer's type.
474: */
475: private String pointerSignature(Pointer pointer) {
476: if (pointer == null) {
477: return "";
478: }
479:
480: char type = '?';
481: if (pointer instanceof NullPointer) {
482: type = 'N';
483: } else if (pointer instanceof NullPropertyPointer) {
484: type = 'n';
485: } else if (pointer instanceof NullElementPointer) {
486: type = 'E';
487: } else if (pointer instanceof VariablePointer) {
488: type = 'V';
489: } else if (pointer instanceof CollectionPointer) {
490: type = 'C';
491: } else if (pointer instanceof BeanPointer) {
492: type = 'B';
493: } else if (pointer instanceof BeanPropertyPointer) {
494: type = 'b';
495: } else if (pointer instanceof DynamicPointer) {
496: type = 'D';
497: } else if (pointer instanceof DynamicPropertyPointer) {
498: type = 'd';
499: } else if (pointer instanceof DOMNodePointer) {
500: type = 'M';
501: } else {
502: System.err.println("UNKNOWN TYPE: " + pointer.getClass());
503: }
504: NodePointer parent = ((NodePointer) pointer)
505: .getImmediateParentPointer();
506: return pointerSignature(parent) + type;
507: }
508: }
|