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