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  package org.apache.commons.jxpath.ri.model;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Locale;
24  
25  import org.apache.commons.jxpath.AbstractFactory;
26  import org.apache.commons.jxpath.ClassFunctions;
27  import org.apache.commons.jxpath.JXPathContext;
28  import org.apache.commons.jxpath.JXPathTestCase;
29  import org.apache.commons.jxpath.NestedTestBean;
30  import org.apache.commons.jxpath.Pointer;
31  import org.apache.commons.jxpath.ri.QName;
32  import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
33  import org.apache.commons.jxpath.ri.compiler.TestFunctions;
34  import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
35  import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
36  import org.apache.commons.jxpath.ri.model.dynabeans.DynaBeanModelTest;
37  
38  /**
39   * Abstract superclass for Bean access with JXPath.
40   *
41   * @author Dmitri Plotnikov
42   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
43   */
44  public abstract class BeanModelTestCase extends JXPathTestCase {
45      private JXPathContext context;
46  
47      public void setUp() {
48  //        if (context == null) {
49              context = JXPathContext.newContext(createContextBean());
50              context.setLocale(Locale.US);
51              context.setFactory(getAbstractFactory());
52  //        }
53      }
54  
55      protected abstract Object createContextBean();
56      protected abstract AbstractFactory getAbstractFactory();
57  
58      /**
59       * Test property iterators, the core of the graph traversal engine
60       */
61      public void testIndividualIterators() {
62          testIndividual(+1, 0, true, false, 0);
63          testIndividual(-1, 0, true, false, 4);
64  
65          testIndividual(0, -1, true, true, 4);
66          testIndividual(+1, -1, true, true, 4);
67          testIndividual(-1, -1, true, true, 0);
68  
69          testIndividual(0, 1, true, false, 2);
70          testIndividual(0, 1, true, true, 1);
71  
72          testIndividual(0, 0, false, false, 4);
73          testIndividual(0, 0, false, true, 4);
74      }
75  
76      private void testIndividual(
77          int relativePropertyIndex,
78          int offset,
79          boolean useStartLocation,
80          boolean reverse,
81          int expected) 
82      {
83          PropertyOwnerPointer root =
84              (PropertyOwnerPointer) NodePointer.newNodePointer(
85                  new QName(null, "root"),
86                  createContextBean(),
87                  Locale.getDefault());
88  
89          NodeIterator it;
90  
91          PropertyPointer start = null;
92  
93          if (useStartLocation) {
94              start = root.getPropertyPointer();
95              start.setPropertyIndex(
96                  relativeProperty(start, relativePropertyIndex));
97              start.setIndex(offset);
98          }
99          it =
100             root.childIterator(
101                 new NodeNameTest(new QName(null, "integers")),
102                 reverse,
103                 start);
104 
105         int size = 0;
106         while (it.setPosition(it.getPosition() + 1)) {
107             size++;
108         }
109         assertEquals(
110             "ITERATIONS: Individual, relativePropertyIndex="
111                 + relativePropertyIndex
112                 + ", offset="
113                 + offset
114                 + ", useStartLocation="
115                 + useStartLocation
116                 + ", reverse="
117                 + reverse,
118             expected,
119             size);
120     }
121 
122     /**
123      * Test property iterators with multiple properties returned
124      */
125     public void testMultipleIterators() {
126         testMultiple(0, 0, true, false, 20);
127 
128         testMultiple(3, 0, true, false, 16);
129         testMultiple(3, -1, true, true, 8);
130         testMultiple(3, 0, true, true, 4);
131         testMultiple(0, 0, false, false, 21);
132         testMultiple(0, 0, false, true, 21);
133 
134         testMultiple(3, 1, true, false, 15);
135         testMultiple(3, 3, true, false, 13);
136     }
137 
138     private void testMultiple(
139         int propertyIndex,
140         int offset,
141         boolean useStartLocation,
142         boolean reverse,
143         int expected) 
144     {
145         PropertyOwnerPointer root =
146             (PropertyOwnerPointer) NodePointer.newNodePointer(
147                 new QName(null, "root"),
148                 createContextBean(),
149                 Locale.getDefault());
150         NodeIterator it;
151 
152         PropertyPointer start = null;
153 
154         if (useStartLocation) {
155             start = root.getPropertyPointer();
156             start.setPropertyIndex(propertyIndex);
157             start.setIndex(offset);
158         }
159         it = root.childIterator(null, reverse, start);
160 
161         int size = 0;
162         while (it.setPosition(it.getPosition() + 1)) {
163 //            System.err.println("LOC: " + it.getCurrentNodePointer());
164             size++;
165         }
166         assertEquals(
167             "ITERATIONS: Multiple, propertyIndex="
168                 + propertyIndex
169                 + ", offset="
170                 + offset
171                 + ", useStartLocation="
172                 + useStartLocation
173                 + ", reverse="
174                 + reverse,
175             expected,
176             size);
177     }
178 
179     private int relativeProperty(PropertyPointer holder, int offset) {
180         String[] names = holder.getPropertyNames();
181         for (int i = 0; i < names.length; i++) {
182             if (names[i].equals("integers")) {
183                 return i + offset;
184             }
185         }
186         return -1;
187     }
188 
189     public void testIteratePropertyArrayWithHasNext() {
190         JXPathContext context = JXPathContext.newContext(createContextBean());
191         Iterator it = context.iteratePointers("/integers");
192         List actual = new ArrayList();
193         while (it.hasNext()) {
194             actual.add(((Pointer) it.next()).asPath());
195         }
196         assertEquals(
197             "Iterating 'hasNext'/'next'<" + "/integers" + ">",
198             list(
199                 "/integers[1]",
200                 "/integers[2]",
201                 "/integers[3]",
202                 "/integers[4]"),
203             actual);
204     }
205 
206     public void testIteratePropertyArrayWithoutHasNext() {
207         JXPathContext context = JXPathContext.newContext(createContextBean());
208         Iterator it = context.iteratePointers("/integers");
209         List actual = new ArrayList();
210         for (int i = 0; i < 4; i++) {
211             actual.add(it.next().toString());
212         }
213         assertEquals(
214             "Iterating 'next'<" + "/integers" + ">",
215             list(
216                 "/integers[1]",
217                 "/integers[2]",
218                 "/integers[3]",
219                 "/integers[4]"),
220             actual);
221     }
222 
223     public void testIterateAndSet() {
224         JXPathContext context = JXPathContext.newContext(createContextBean());
225 
226         Iterator it = context.iteratePointers("beans/int");
227         int i = 5;
228         while (it.hasNext()) {
229             NodePointer pointer = (NodePointer) it.next();
230             pointer.setValue(new Integer(i++));
231         }
232 
233         it = context.iteratePointers("beans/int");
234         List actual = new ArrayList();
235         while (it.hasNext()) {
236             actual.add(((Pointer) it.next()).getValue());
237         }
238         assertEquals(
239             "Iterating <" + "beans/int" + ">",
240             list(new Integer(5), new Integer(6)),
241             actual);
242     }
243 
244     /**
245      * Test contributed by Kate Dvortsova
246      */
247     public void testIteratePointerSetValue() {
248         JXPathContext context = JXPathContext.newContext(createContextBean());
249 
250         assertXPathValue(context, "/beans[1]/name", "Name 1");
251         assertXPathValue(context, "/beans[2]/name", "Name 2");
252 
253         // Test setting via context
254         context.setValue("/beans[2]/name", "Name 2 set");
255         assertXPathValue(context, "/beans[2]/name", "Name 2 set");
256 
257         // Restore original value
258         context.setValue("/beans[2]/name", "Name 2");
259         assertXPathValue(context, "/beans[2]/name", "Name 2");
260 
261         int iterCount = 0;
262         Iterator iter = context.iteratePointers("/beans/name");
263         while (iter.hasNext()) {
264             iterCount++;
265             Pointer pointer = (Pointer) iter.next();
266             String s = (String) pointer.getValue();
267             s = s + "suffix";
268             pointer.setValue(s);
269             assertEquals("pointer.getValue", s, pointer.getValue());
270             // fails right here, the value isn't getting set in the bean.
271             assertEquals(
272                 "context.getValue",
273                 s,
274                 context.getValue(pointer.asPath()));
275         }
276         assertEquals("Iteration count", 2, iterCount);
277 
278         assertXPathValue(context, "/beans[1]/name", "Name 1suffix");
279         assertXPathValue(context, "/beans[2]/name", "Name 2suffix");
280     }
281 
282     public void testRoot() {
283         assertXPathValueAndPointer(context, "/", context.getContextBean(), "/");
284     }
285 
286     public void testAxisAncestor() {
287         // ancestor::
288         assertXPathValue(context, "int/ancestor::root = /", Boolean.TRUE);
289 
290         assertXPathValue(
291             context,
292             "count(beans/name/ancestor-or-self::node())",
293             new Double(5));
294 
295         assertXPathValue(
296             context,
297             "beans/name/ancestor-or-self::node()[3] = /",
298             Boolean.TRUE);
299     }
300 
301     public void testAxisChild() {
302         assertXPathValue(context, "boolean", Boolean.FALSE);
303 
304         assertXPathPointer(context, "boolean", "/boolean");
305 
306         assertXPathPointerIterator(context, "boolean", list("/boolean"));
307 
308         // Count elements in a child collection
309         assertXPathValue(context, "count(set)", new Double(3));
310 
311 //        assertXPathValue(context,"boolean/class/name", "java.lang.Boolean");
312 
313         // Child with namespace - should not find any
314         assertXPathValueIterator(context, "foo:boolean", list());
315 
316         // Count all children with a wildcard
317         assertXPathValue(context, "count(*)", new Double(21));
318 
319         // Same, constrained by node type = node()
320         assertXPathValue(context, "count(child::node())", new Double(21));
321     }
322 
323     public void testAxisChildNestedBean() {
324         // Nested bean
325         assertXPathValue(context, "nestedBean/name", "Name 0");
326 
327         assertXPathPointer(context, "nestedBean/name", "/nestedBean/name");
328 
329         assertXPathPointerIterator(
330             context,
331             "nestedBean/name",
332             list("/nestedBean/name"));
333     }
334 
335     public void testAxisChildNestedCollection() {
336         assertXPathValueIterator(
337             context,
338             "integers",
339             list(
340                 new Integer(1),
341                 new Integer(2),
342                 new Integer(3),
343                 new Integer(4)));
344 
345         assertXPathPointer(context, "integers", "/integers");
346 
347         assertXPathPointerIterator(
348             context,
349             "integers",
350             list(
351                 "/integers[1]",
352                 "/integers[2]",
353                 "/integers[3]",
354                 "/integers[4]"));
355     }
356 
357     public void testIndexPredicate() {
358         assertXPathValue(context, "integers[2]", new Integer(2));
359 
360         assertXPathPointer(context, "integers[2]", "/integers[2]");
361 
362         assertXPathPointerIterator(
363             context,
364             "integers[2]",
365             list("/integers[2]"));
366 
367         assertXPathValue(context, "beans[1]/name", "Name 1");
368 
369         assertXPathPointer(context, "beans[1]/name", "/beans[1]/name");
370 
371         assertXPathValueIterator(
372             context,
373             "beans[1]/strings",
374             list("String 1", "String 2", "String 3"));
375 
376         assertXPathValueIterator(
377             context,
378             "beans/strings[2]",
379             list("String 2", "String 2"));
380 
381         // Find the first match
382         assertXPathValue(context, "beans/strings[2]", "String 2");
383 
384         // Indexing in a set collected from a UnionContext
385         assertXPathValue(context, "(beans/strings[2])[1]", "String 2");
386     }
387 
388     public void testAxisDescendant() {
389         // descendant::
390         assertXPathValue(context, "count(descendant::node())", new Double(65));
391 
392         // Should not find any descendants with name root
393         assertXPathValue(context, "count(descendant::root)", new Double(0));
394 
395         assertXPathValue(context, "count(descendant::name)", new Double(7));
396     }
397 
398     public void testAxisDescendantOrSelf() {
399         // descendant-or-self::
400         assertXPathValueIterator(
401             context,
402             "descendant-or-self::name",
403             set(
404                 "Name 1",
405                 "Name 2",
406                 "Name 3",
407                 "Name 6",
408                 "Name 0",
409                 "Name 5",
410                 "Name 4"));
411 
412         // Same - abbreviated syntax
413         assertXPathValueIterator(
414             context,
415             "//name",
416             set(
417                 "Name 1",
418                 "Name 2",
419                 "Name 3",
420                 "Name 6",
421                 "Name 0",
422                 "Name 5",
423                 "Name 4"));
424 
425         // See that it actually finds self
426         assertXPathValue(
427             context,
428             "count(descendant-or-self::root)",
429             new Double(1));
430 
431         // Combine descendant-or-self:: and and self::
432         assertXPathValue(context, "count(nestedBean//.)", new Double(7));
433 
434         // Combine descendant-or-self:: and and self::name
435         assertXPathValue(context, "count(//self::beans)", new Double(2));
436 
437         // Count all nodes in the tree
438         assertXPathValue(
439             context,
440             "count(descendant-or-self::node())",
441             new Double(66));
442 
443     }
444 
445     public void testAxisFollowing() {
446         // following::
447         assertXPathValue(
448             context,
449             "count(nestedBean/strings[2]/following::node())",
450             new Double(21));
451 
452         assertXPathValue(
453             context,
454             "count(nestedBean/strings[2]/following::strings)",
455             new Double(7));
456     }
457 
458     public void testAxisFollowingSibling() {
459         // following-sibling::
460         assertXPathValue(
461             context,
462             "count(/nestedBean/following-sibling::node())",
463             new Double(8));
464 
465         assertXPathValue(
466             context,
467             "count(/nestedBean/following-sibling::object)",
468             new Double(1));
469 
470         // Combine parent:: and following-sibling::
471         assertXPathValue(
472             context,
473             "count(/nestedBean/boolean/../following-sibling::node())",
474             new Double(8));
475 
476         assertXPathValue(
477             context,
478             "count(/nestedBean/boolean/../following-sibling::object)",
479             new Double(1));
480 
481         // Combine descendant:: and following-sibling::
482         assertXPathValue(
483             context,
484             "count(/descendant::boolean/following-sibling::node())",
485             new Double(53));
486 
487         assertXPathValue(
488             context,
489             "count(/descendant::boolean/following-sibling::name)",
490             new Double(7));
491     }
492 
493     public void testAxisParent() {
494         // parent::
495         assertXPathValue(context, "count(/beans/..)", new Double(1));
496 
497         assertXPathValue(context, "count(//..)", new Double(9));
498 
499         assertXPathValue(context, "count(//../..)", new Double(2));
500 
501         assertXPathValueIterator(
502             context,
503             "//parent::beans/name",
504             list("Name 1", "Name 2"));
505     }
506 
507     public void testAxisPreceding() {
508         // preceding::
509         assertXPathValue(
510             context,
511             "count(beans[2]/int/preceding::node())",
512             new Double(8));
513 
514         assertXPathValue(
515             context,
516             "count(beans[2]/int/preceding::boolean)",
517             new Double(2));
518     }
519 
520     public void testAxisPrecedingSibling() {
521         // preceding-sibling::
522         assertXPathValue(
523             context,
524             "count(/boolean/preceding-sibling::node())",
525             new Double(2));
526 
527         assertXPathValue(
528             context,
529             "count(/nestedBean/int/../preceding-sibling::node())",
530             new Double(12));
531 
532         assertXPathValue(
533             context,
534             "count(/descendant::int/preceding-sibling::node())",
535             new Double(10));
536     }
537 
538     public void testAxisSelf() {
539         // self::
540         assertXPathValue(context, "self::node() = /", Boolean.TRUE);
541 
542         assertXPathValue(context, "self::root = /", Boolean.TRUE);
543     }
544 
545     public void testUnion() {
546         // Union - note corrected document order
547         assertXPathValueIterator(
548             context,
549             "integers | beans[1]/strings",
550             list(
551                 "String 1",
552                 "String 2",
553                 "String 3",
554                 new Integer(1),
555                 new Integer(2),
556                 new Integer(3),
557                 new Integer(4)));
558 
559         assertXPathValue(
560             context,
561             "count((integers | beans[1]/strings)[contains(., '1')])",
562             new Double(2));
563 
564         assertXPathValue(
565             context,
566             "count((integers | beans[1]/strings)[name(.) = 'strings'])",
567             new Double(3));
568 
569         // Note that the following is different from "integer[2]" -
570         // it is a filter expression
571         assertXPathValue(context, "(integers)[2]", new Integer(2));
572     }
573 
574     public void testAxisAttribute() {
575         // Attributes are just like children to beans
576         assertXPathValue(context, "count(@*)", new Double(21.0));
577 
578         // Unknown attribute
579         assertXPathValueLenient(context, "@foo", null);
580     }
581 
582     /**
583      * Testing the pseudo-attribute "name" that java beans
584      * objects appear to have.
585      */
586     public void testAttributeName() {
587         assertXPathValue(context, "nestedBean[@name = 'int']", new Integer(1));
588 
589         assertXPathPointer(
590             context,
591             "nestedBean[@name = 'int']",
592             "/nestedBean/int");
593     }
594 
595     public void testAttributeLang() {
596 
597         assertXPathValue(context, "@xml:lang", "en-US");
598 
599         assertXPathValue(context, "count(@xml:*)", new Double(1));
600 
601         assertXPathValue(context, "lang('en')", Boolean.TRUE);
602 
603         assertXPathValue(context, "lang('fr')", Boolean.FALSE);
604     }
605 
606     public void testCoreFunctions() {
607 
608         assertXPathValue(context, "boolean(boolean)", Boolean.TRUE);
609 
610         assertXPathValue(context, "boolean(boolean = false())", Boolean.TRUE);
611 
612         assertXPathValue(
613             context,
614             "boolean(integers[position() < 3])",
615             Boolean.TRUE);
616 
617         assertXPathValue(
618             context,
619             "boolean(integers[position() > 4])",
620             Boolean.FALSE);
621 
622         assertXPathValue(context, "sum(integers)", new Double(10));        
623 
624         assertXPathValueAndPointer(
625                 context,
626                 "integers[last()]",
627                 new Integer(4),
628                 "/integers[4]");
629 
630         assertXPathValueAndPointer(
631                 context,
632                 "//strings[last()]",
633                 "String 3",
634                 "/beans[1]/strings[3]");
635     }
636 
637     public void testBooleanPredicate() {
638         // use child axis
639 
640         // bean[1]/int = 1
641         // bean[2]/int = 3
642 
643         assertXPathValue(context, "beans[int > 2]/name", "Name 2");
644 
645         assertXPathValueIterator(
646             context,
647             "beans[int > 2]/name",
648             list("Name 2"));
649 
650         assertXPathValueIterator(
651             context,
652             "beans[int >= 1]/name",
653             list("Name 1", "Name 2"));
654 
655         assertXPathValueIterator(
656             context,
657             "beans[int < 2]/name",
658             list("Name 1"));
659 
660         assertXPathValueIterator(
661             context,
662             "beans[int <= 3]/name",
663             list("Name 1", "Name 2"));
664 
665         assertXPathValueIterator(
666             context,
667             "beans[1]/strings[string-length() = 8]",
668             list("String 1", "String 2", "String 3"));
669 
670         // use some fancy axis and the child axis in the predicate
671         assertXPathValueIterator(
672             context,
673             "//self::node()[name = 'Name 0']/name",
674             list("Name 0"));
675 
676         // use context-dependent function in the predicate
677         assertXPathValue(
678             context,
679             "beans/strings[name(.)='strings'][2]",
680             "String 2");
681 
682         // use context-independent function in the predicate
683         assertXPathValueIterator(
684             context,
685             "//self::node()[name(.) = concat('n', 'a', 'm', 'e')]",
686             list(
687                 "Name 1",
688                 "Name 2",
689                 "Name 3",
690                 "Name 6",
691                 "Name 0",
692                 "Name 5",
693                 "Name 4"));
694 
695         assertXPathValueIterator(
696             context,
697             "integers[position()<3]",
698             list(new Integer(1), new Integer(2)));
699             
700         context.getVariables().declareVariable(
701             "temp",
702             context.getValue("beans"));
703         
704         assertXPathValueIterator(
705             context,
706             "$temp[int < 2]/int",
707             list(new Integer(1)));
708     }
709 
710     public void testDocumentOrder() {
711         assertDocumentOrder(context, "boolean", "int", -1);
712 
713         assertDocumentOrder(context, "integers[1]", "integers[2]", -1);
714 
715         assertDocumentOrder(context, "integers[1]", "integers[1]", 0);
716 
717         assertDocumentOrder(context, "nestedBean/int", "nestedBean", 1);
718 
719         assertDocumentOrder(
720             context,
721             "nestedBean/int",
722             "nestedBean/strings",
723             -1);
724 
725         assertDocumentOrder(context, "nestedBean/int", "object/int", -1);
726     }
727 
728     public void testSetPropertyValue() {
729         // Simple property
730         assertXPathSetValue(context, "int", new Integer(2));
731 
732         // Simple property with conversion from string
733         assertXPathSetValue(context, "int", "3", new Integer(3));
734 
735         // Simple property with conversion from array
736         assertXPathSetValue(context, "int", new int[] { 4 }, new Integer(4));
737 
738         // Attribute (which is the same as a child for beans
739         assertXPathSetValue(context, "@int", new Integer(10));
740     }
741 
742     public void testSetCollectionElement() {
743         // Collection element
744         assertXPathSetValue(context, "integers[2]", new Integer(5));
745 
746         // Collection element with conversion
747         assertXPathSetValue(
748             context,
749             "integers[2]",
750             new int[] { 6 },
751             new Integer(6));
752     }
753 
754     public void testSetContextDependentNode() {
755         // Find node without using SimplePathInterpreter
756         assertXPathSetValue(
757             context,
758             "integers[position() = 1]",
759             new Integer(8));
760 
761         // Find node without using SimplePathInterpreter and set its property
762         assertXPathSetValue(
763             context,
764             "beans[name = 'Name 1']/int",
765             new Integer(9));
766 
767     }
768 
769     public void testSetNonPrimitiveValue() {
770         // First, let's see if we can set a collection element to null
771         assertXPathSetValue(context, "beans[2]", null);
772 
773         // Now, assign it a whole bean
774         context.setValue("beans[2]", new NestedTestBean("Name 9"));
775 
776         assertEquals(
777             "Modified <" + "beans[2]/name" + ">",
778             "Name 9",
779             context.getValue("beans[2]/name"));
780     }
781 
782     public void testCreatePath() {
783         context.setValue("nestedBean", null);
784 
785         // Calls factory.createObject(..., TestBean, "nestedBean")
786         assertXPathCreatePath(
787             context,
788             "/nestedBean/int",
789             new Integer(1),
790             "/nestedBean/int");
791 
792         boolean ex = false;
793         try {
794             assertXPathCreatePath(
795                 context,
796                 "/nestedBean/beans[last() + 1]",
797                 new Integer(1),
798                 "/nestedBean/beans[last() + 1]");
799         }
800         catch (Exception e) {
801             ex = true;
802         }
803         assertTrue("Exception thrown on invalid path for creation", ex);
804         
805     }
806 
807     public void testCreatePathAndSetValue() {
808         context.setValue("nestedBean", null);
809 
810         // Calls factory.createObject(..., TestBean, "nestedBean")
811         assertXPathCreatePathAndSetValue(
812             context,
813             "/nestedBean/int",
814             new Integer(2),
815             "/nestedBean/int");
816     }
817 
818     public void testCreatePathExpandNewCollection() {
819         context.setValue("beans", null);
820 
821         // Calls factory.createObject(..., testBean, "beans", 2), 
822         // then  factory.createObject(..., testBean, "beans", 2)
823         assertXPathCreatePath(
824             context,
825             "/beans[2]/int",
826             new Integer(1),
827             "/beans[2]/int");
828     }
829 
830     public void testCreatePathAndSetValueExpandNewCollection() {
831         context.setValue("beans", null);
832 
833         // Calls factory.createObject(..., testBean, "beans", 2), 
834         // then factory.createObject(..., testBean, "beans", 2)
835         assertXPathCreatePathAndSetValue(
836             context,
837             "/beans[2]/int",
838             new Integer(2),
839             "/beans[2]/int");
840     }
841 
842     public void testCreatePathExpandExistingCollection() {
843         // Calls factory.createObject(..., TestBean, "integers", 5)
844         // to expand collection
845         assertXPathCreatePathAndSetValue(
846             context,
847             "/integers[5]",
848             new Integer(3),
849             "/integers[5]");
850     }
851 
852     public void testCreatePathExpandExistingCollectionAndSetProperty() {
853         // Another, but the collection already exists
854         assertXPathCreatePath(
855             context,
856             "/beans[3]/int",
857             new Integer(1),
858             "/beans[3]/int");
859     }
860 
861     public void testCreatePathAndSetValueExpandExistingCollection() {
862         // Another, but the collection already exists
863         assertXPathCreatePathAndSetValue(
864             context,
865             "/beans[3]/int",
866             new Integer(2),
867             "/beans[3]/int");
868     }
869 
870     public void testCreatePathCreateBeanExpandCollection() {
871         context.setValue("nestedBean", null);
872 
873         // Calls factory.createObject(..., TestBean, "nestedBean")
874         // Calls factory.createObject(..., nestedBean, "strings", 2)
875         assertXPathCreatePath(
876             context,
877             "/nestedBean/strings[2]",
878             "String 2",
879             "/nestedBean/strings[2]");
880     }
881 
882     public void testCreatePathAndSetValueCreateBeanExpandCollection() {
883         context.setValue("nestedBean", null);
884 
885         // Calls factory.createObject(..., TestBean, "nestedBean")
886         // Calls factory.createObject(..., nestedBean, "strings", 2)
887         assertXPathCreatePathAndSetValue(
888             context,
889             "/nestedBean/strings[2]",
890             "Test",
891             "/nestedBean/strings[2]");
892     }
893 
894     public void testRemovePathPropertyValue() {
895         // Remove property value
896         context.removePath("nestedBean/int");
897         assertEquals(
898             "Remove property value",
899             new Integer(0),
900             context.getValue("nestedBean/int"));
901     }
902 
903     public void testRemovePathArrayElement() {
904         // Assigns a new array to the property
905         context.removePath("nestedBean/strings[1]");
906         assertEquals(
907             "Remove array element",
908             "String 2",
909             context.getValue("nestedBean/strings[1]"));
910     }
911 
912     public void testRemoveAllArrayElements() {
913         context.removeAll("nestedBean/strings");
914         assertXPathValueIterator(
915             context,
916             "nestedBean/strings",
917             list());
918     }
919 
920     public void testRemoveAllListElements() {
921         context.removeAll("list");
922         assertXPathValueIterator(
923             context,
924             "list",
925             this instanceof DynaBeanModelTest ? list(null, null, null) : list());
926     }
927 
928     public void testRemoveAllMapEntries() {
929         context.removeAll("map/*");
930         assertXPathValue(
931             context,
932             "map",
933             Collections.EMPTY_MAP);
934     }
935 
936     public void testRemovePathBeanValue() {
937         context.removePath("nestedBean");
938         assertEquals(
939             "Remove collection element",
940             null,
941             context.getValue("nestedBean"));
942     }
943     
944     public void testRelativeContextRelativePath() {
945         JXPathContext relative =
946             context.getRelativeContext(context.getPointer("nestedBean"));
947         
948         assertXPathValueAndPointer(relative, 
949             "int", 
950             new Integer(1), 
951             "/nestedBean/int");
952     }
953 
954     public void testRelativeContextAbsolutePath() {
955         JXPathContext relative =
956             context.getRelativeContext(context.getPointer("nestedBean"));
957         
958         assertXPathValueAndPointer(relative, 
959             "/integers[2]", 
960             new Integer(2), 
961             "/integers[2]");
962     }
963 
964     public void testRelativeContextParent() {
965         JXPathContext relative =
966             context.getRelativeContext(context.getPointer("nestedBean"));
967         
968         assertXPathValueAndPointer(relative, 
969             "../integers[2]", 
970             new Integer(2), 
971             "/integers[2]");
972     }
973     
974     public void testRelativeContextInheritance() {
975         context.setFunctions(new ClassFunctions(TestFunctions.class, "test"));
976         JXPathContext relative =
977             context.getRelativeContext(context.getPointer("nestedBean"));
978         
979         assertXPathValue(relative, 
980             "test:countPointers(strings)", 
981             new Integer(3));
982     }
983 }