/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jxpath.ri.axes;
import java.util.HashMap;
import junit.framework.TestCase;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.NestedTestBean;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.TestNull;
import org.apache.commons.jxpath.ri.model.NodePointer;
import org.apache.commons.jxpath.ri.model.VariablePointer;
import org.apache.commons.jxpath.ri.model.beans.BeanPointer;
import org.apache.commons.jxpath.ri.model.beans.BeanPropertyPointer;
import org.apache.commons.jxpath.ri.model.beans.CollectionPointer;
import org.apache.commons.jxpath.ri.model.beans.NullElementPointer;
import org.apache.commons.jxpath.ri.model.beans.NullPointer;
import org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer;
import org.apache.commons.jxpath.ri.model.beans.TestBeanFactory;
import org.apache.commons.jxpath.ri.model.dom.DOMNodePointer;
import org.apache.commons.jxpath.ri.model.dynamic.DynamicPointer;
import org.apache.commons.jxpath.ri.model.dynamic.DynamicPropertyPointer;
public class SimplePathInterpreterTest extends TestCase {
private TestBeanWithNode bean;
private JXPathContext context;
protected void setUp() throws Exception {
bean = TestBeanWithNode.createTestBeanWithDOM();
HashMap submap = new HashMap();
submap.put("key", new NestedTestBean("Name 9"));
submap.put("strings", bean.getNestedBean().getStrings());
bean.getList().add(new int[]{1, 2});
bean.getList().add(bean.getVendor());
bean.getMap().put("Key3",
new Object[]{
new NestedTestBean("some"),
new Integer(2),
bean.getVendor(),
submap
}
);
bean.getMap().put("Key4", bean.getVendor());
bean.getMap().put("Key5", submap);
bean.getMap().put("Key6", new Object[0]);
context = JXPathContext.newContext(null, bean);
context.setLenient(true);
context.setFactory(new TestBeanFactory());
}
public void testDoStepNoPredicatesPropertyOwner() {
// Existing scalar property
assertValueAndPointer("/int",
new Integer(1),
"/int",
"Bb",
"BbB");
// self::
assertValueAndPointer("/./int",
new Integer(1),
"/int",
"Bb",
"BbB");
// Missing property
assertNullPointer("/foo",
"/foo",
"Bn");
// existingProperty/existingScalarProperty
assertValueAndPointer("/nestedBean/int",
new Integer(1),
"/nestedBean/int",
"BbBb",
"BbBbB");
// existingProperty/collectionProperty
assertValueAndPointer("/nestedBean/strings",
bean.getNestedBean().getStrings(),
"/nestedBean/strings",
"BbBb",
"BbBbC");
// existingProperty/missingProperty
assertNullPointer("/nestedBean/foo",
"/nestedBean/foo",
"BbBn");
// map/missingProperty
assertNullPointer("/map/foo",
"/map[@name='foo']",
"BbDd");
// Existing property by search in collection
assertValueAndPointer("/list/int",
new Integer(1),
"/list[3]/int",
"BbBb",
"BbBbB");
// Missing property by search in collection
assertNullPointer("/list/foo",
"/list[1]/foo",
"BbBn");
// existingProperty/missingProperty/missingProperty
assertNullPointer("/nestedBean/foo/bar",
"/nestedBean/foo/bar",
"BbBnNn");
// collection/existingProperty/missingProperty
assertNullPointer("/list/int/bar",
"/list[3]/int/bar",
"BbBbBn");
// collectionProperty/missingProperty/missingProperty
assertNullPointer("/list/foo/bar",
"/list[1]/foo/bar",
"BbBnNn");
// map/missingProperty/anotherStep
assertNullPointer("/map/foo/bar",
"/map[@name='foo']/bar",
"BbDdNn");
// Existing dynamic property
assertValueAndPointer("/map/Key1",
"Value 1",
"/map[@name='Key1']",
"BbDd",
"BbDdB");
// collectionProperty
assertValueAndPointer("/integers",
bean.getIntegers(),
"/integers",
"Bb",
"BbC");
}
public void testDoStepNoPredicatesStandard() {
// Existing DOM node
assertValueAndPointer("/vendor/location/address/city",
"Fruit Market",
"/vendor/location[2]/address[1]/city[1]",
"BbMMMM");
// Missing DOM node
assertNullPointer("/vendor/location/address/pity",
"/vendor/location[1]/address[1]/pity",
"BbMMMn");
// Missing DOM node inside a missing element
assertNullPointer("/vendor/location/address/itty/bitty",
"/vendor/location[1]/address[1]/itty/bitty",
"BbMMMnNn");
// Missing DOM node by search for the best match
assertNullPointer("/vendor/location/address/city/pretty",
"/vendor/location[2]/address[1]/city[1]/pretty",
"BbMMMMn");
}
public void testDoStepPredicatesPropertyOwner() {
// missingProperty[@name=foo]
assertNullPointer("/foo[@name='foo']",
"/foo[@name='foo']",
"BnNn");
// missingProperty[index]
assertNullPointer("/foo[3]",
"/foo[3]",
"Bn");
}
public void testDoStepPredicatesStandard() {
// Looking for an actual XML attribute called "name"
// nodeProperty/name[@name=value]
assertValueAndPointer("/vendor/contact[@name='jack']",
"Jack",
"/vendor/contact[2]",
"BbMM");
// Indexing in XML
assertValueAndPointer("/vendor/contact[2]",
"Jack",
"/vendor/contact[2]",
"BbMM");
// Indexing in XML, no result
assertNullPointer("/vendor/contact[5]",
"/vendor/contact[5]",
"BbMn");
// Combination of search by name and indexing in XML
assertValueAndPointer("/vendor/contact[@name='jack'][2]",
"Jack Black",
"/vendor/contact[4]",
"BbMM");
// Combination of search by name and indexing in XML
assertValueAndPointer("/vendor/contact[@name='jack'][2]",
"Jack Black",
"/vendor/contact[4]",
"BbMM");
}
public void testDoPredicateName() {
// existingProperty[@name=existingProperty]
assertValueAndPointer("/nestedBean[@name='int']",
new Integer(1),
"/nestedBean/int",
"BbBb",
"BbBbB");
// /self::node()[@name=existingProperty]
assertValueAndPointer("/.[@name='int']",
new Integer(1),
"/int",
"Bb",
"BbB");
// dynamicProperty[@name=existingProperty]
assertValueAndPointer("/map[@name='Key1']",
"Value 1",
"/map[@name='Key1']",
"BbDd",
"BbDdB");
// existingProperty[@name=collectionProperty]
assertValueAndPointer("/nestedBean[@name='strings']",
bean.getNestedBean().getStrings(),
"/nestedBean/strings",
"BbBb",
"BbBbC");
// existingProperty[@name=missingProperty]
assertNullPointer("/nestedBean[@name='foo']",
"/nestedBean[@name='foo']",
"BbBn");
// map[@name=collectionProperty]
assertValueAndPointer("/map[@name='Key3']",
bean.getMap().get("Key3"),
"/map[@name='Key3']",
"BbDd",
"BbDdC");
// map[@name=missingProperty]
assertNullPointer("/map[@name='foo']",
"/map[@name='foo']",
"BbDd");
// collectionProperty[@name=...] (find node)
assertValueAndPointer("/list[@name='fruitco']",
context.getValue("/vendor"),
"/list[5]",
"BbCM");
// collectionProperty[@name=...] (find map entry)
assertValueAndPointer("/map/Key3[@name='key']/name",
"Name 9",
"/map[@name='Key3'][4][@name='key']/name",
"BbDdCDdBb",
"BbDdCDdBbB");
// map/collectionProperty[@name...]
assertValueAndPointer("map/Key3[@name='fruitco']",
context.getValue("/vendor"),
"/map[@name='Key3'][3]",
"BbDdCM");
// Bean property -> DOM Node, name match
assertValueAndPointer("/vendor[@name='fruitco']",
context.getValue("/vendor"),
"/vendor",
"BbM");
// Bean property -> DOM Node, name mismatch
assertNullPointer("/vendor[@name='foo']",
"/vendor[@name='foo']",
"BbMn");
assertNullPointer("/vendor[@name='foo'][3]",
"/vendor[@name='foo'][3]",
"BbMn");
// existingProperty(bean)[@name=missingProperty]/anotherStep
assertNullPointer("/nestedBean[@name='foo']/bar",
"/nestedBean[@name='foo']/bar",
"BbBnNn");
// map[@name=missingProperty]/anotherStep
assertNullPointer("/map[@name='foo']/bar",
"/map[@name='foo']/bar",
"BbDdNn");
// existingProperty(node)[@name=missingProperty]/anotherStep
assertNullPointer("/vendor[@name='foo']/bar",
"/vendor[@name='foo']/bar",
"BbMnNn");
// existingProperty(node)[@name=missingProperty][index]/anotherStep
assertNullPointer("/vendor[@name='foo'][3]/bar",
"/vendor[@name='foo'][3]/bar",
"BbMnNn");
// Existing dynamic property + existing property
assertValueAndPointer("/map[@name='Key2'][@name='name']",
"Name 6",
"/map[@name='Key2']/name",
"BbDdBb",
"BbDdBbB");
// Existing dynamic property + existing property + index
assertValueAndPointer("/map[@name='Key2'][@name='strings'][2]",
"String 2",
"/map[@name='Key2']/strings[2]",
"BbDdBb",
"BbDdBbB");
// bean/map/map/property
assertValueAndPointer("map[@name='Key5'][@name='key']/name",
"Name 9",
"/map[@name='Key5'][@name='key']/name",
"BbDdDdBb",
"BbDdDdBbB");
assertNullPointer("map[@name='Key2'][@name='foo']",
"/map[@name='Key2'][@name='foo']",
"BbDdBn");
assertNullPointer("map[@name='Key2'][@name='foo'][@name='bar']",
"/map[@name='Key2'][@name='foo'][@name='bar']",
"BbDdBnNn");
// bean/map/node
assertValueAndPointer("map[@name='Key4'][@name='fruitco']",
context.getValue("/vendor"),
"/map[@name='Key4']",
"BbDdM");
}
public void testDoPredicatesStandard() {
// bean/map/collection/node
assertValueAndPointer("map[@name='Key3'][@name='fruitco']",
context.getValue("/vendor"),
"/map[@name='Key3'][3]",
"BbDdCM");
// bean/map/collection/missingNode
assertNullPointer("map[@name='Key3'][@name='foo']",
"/map[@name='Key3'][4][@name='foo']",
"BbDdCDd");
// bean/map/node
assertValueAndPointer("map[@name='Key4'][@name='fruitco']",
context.getValue("/vendor"),
"/map[@name='Key4']",
"BbDdM");
// bean/map/emptyCollection[@name=foo]
assertNullPointer("map[@name='Key6'][@name='fruitco']",
"/map[@name='Key6'][@name='fruitco']",
"BbDdCn");
// bean/node[@name=foo][index]
assertValueAndPointer("/vendor/contact[@name='jack'][2]",
"Jack Black",
"/vendor/contact[4]",
"BbMM");
// bean/node[@name=foo][missingIndex]
assertNullPointer("/vendor/contact[@name='jack'][5]",
"/vendor/contact[@name='jack'][5]",
"BbMnNn");
// bean/node/.[@name=foo][index]
assertValueAndPointer("/vendor/contact/.[@name='jack']",
"Jack",
"/vendor/contact[2]",
"BbMM");
}
public void testDoPredicateIndex() {
// Existing dynamic property + existing property + index
assertValueAndPointer("/map[@name='Key2'][@name='strings'][2]",
"String 2",
"/map[@name='Key2']/strings[2]",
"BbDdBb",
"BbDdBbB");
// existingProperty[@name=collectionProperty][index]
assertValueAndPointer("/nestedBean[@name='strings'][2]",
bean.getNestedBean().getStrings()[1],
"/nestedBean/strings[2]",
"BbBb",
"BbBbB");
// existingProperty[@name=missingProperty][index]
assertNullPointer("/nestedBean[@name='foo'][3]",
"/nestedBean[@name='foo'][3]",
"BbBn");
// existingProperty[@name=collectionProperty][missingIndex]
assertNullPointer("/nestedBean[@name='strings'][5]",
"/nestedBean/strings[5]",
"BbBbE");
// map[@name=collectionProperty][index]
assertValueAndPointer("/map[@name='Key3'][2]",
new Integer(2),
"/map[@name='Key3'][2]",
"BbDd",
"BbDdB");
// map[@name=collectionProperty][missingIndex]
assertNullPointer("/map[@name='Key3'][5]",
"/map[@name='Key3'][5]",
"BbDdE");
// map[@name=collectionProperty][missingIndex]/property
assertNullPointer("/map[@name='Key3'][5]/foo",
"/map[@name='Key3'][5]/foo",
"BbDdENn");
// map[@name=map][@name=collection][index]
assertValueAndPointer("/map[@name='Key5'][@name='strings'][2]",
"String 2",
"/map[@name='Key5'][@name='strings'][2]",
"BbDdDd",
"BbDdDdB");
// map[@name=map][@name=collection][missingIndex]
assertNullPointer("/map[@name='Key5'][@name='strings'][5]",
"/map[@name='Key5'][@name='strings'][5]",
"BbDdDdE");
// Existing dynamic property + indexing
assertValueAndPointer("/map[@name='Key3'][2]",
new Integer(2),
"/map[@name='Key3'][2]",
"BbDd",
"BbDdB");
// Existing dynamic property + indexing
assertValueAndPointer("/map[@name='Key3'][1]/name",
"some",
"/map[@name='Key3'][1]/name",
"BbDdBb",
"BbDdBbB");
// map[@name=missingProperty][index]
assertNullPointer("/map[@name='foo'][3]",
"/map[@name='foo'][3]",
"BbDdE");
// collectionProperty[index]
assertValueAndPointer("/integers[2]",
new Integer(2),
"/integers[2]",
"Bb",
"BbB");
// existingProperty/collectionProperty[index]
assertValueAndPointer("/nestedBean/strings[2]",
bean.getNestedBean().getStrings()[1],
"/nestedBean/strings[2]",
"BbBb",
"BbBbB");
// existingProperty[index]/existingProperty
assertValueAndPointer("/list[3]/int",
new Integer(1),
"/list[3]/int",
"BbBb",
"BbBbB");
// existingProperty[missingIndex]
assertNullPointer("/list[6]",
"/list[6]",
"BbE");
// existingProperty/missingProperty[index]
assertNullPointer("/nestedBean/foo[3]",
"/nestedBean/foo[3]",
"BbBn");
// map[@name=missingProperty][index]
assertNullPointer("/map/foo[3]",
"/map[@name='foo'][3]",
"BbDdE");
// existingProperty/collectionProperty[missingIndex]
assertNullPointer("/nestedBean/strings[5]",
"/nestedBean/strings[5]",
"BbBbE");
// map/collectionProperty[missingIndex]/property
assertNullPointer("/map/Key3[5]/foo",
"/map[@name='Key3'][5]/foo",
"BbDdENn");
// map[@name=map]/collection[index]
assertValueAndPointer("/map[@name='Key5']/strings[2]",
"String 2",
"/map[@name='Key5'][@name='strings'][2]",
"BbDdDd",
"BbDdDdB");
// map[@name=map]/collection[missingIndex]
assertNullPointer("/map[@name='Key5']/strings[5]",
"/map[@name='Key5'][@name='strings'][5]",
"BbDdDdE");
// scalarPropertyAsCollection[index]
assertValueAndPointer("/int[1]",
new Integer(1),
"/int",
"Bb",
"BbB");
// scalarPropertyAsCollection[index]
assertValueAndPointer(".[1]/int",
new Integer(1),
"/int",
"Bb",
"BbB");
}
public void testInterpretExpressionPath() {
context.getVariables().declareVariable("array", new String[]{"Value1"});
context.getVariables().declareVariable("testnull", new TestNull());
assertNullPointer("$testnull/nothing[2]",
"$testnull/nothing[2]",
"VBbE");
}
private void assertValueAndPointer(
String path, Object expectedValue, String expectedPath,
String expectedSignature)
{
assertValueAndPointer(
path,
expectedValue,
expectedPath,
expectedSignature,
expectedSignature);
}
private void assertValueAndPointer(
String path, Object expectedValue, String expectedPath,
String expectedSignature, String expectedValueSignature)
{
Object value = context.getValue(path);
assertEquals("Checking value: " + path, expectedValue, value);
Pointer pointer = context.getPointer(path);
assertEquals("Checking pointer: " + path,
expectedPath, pointer.toString());
assertEquals("Checking signature: " + path,
expectedSignature, pointerSignature(pointer));
Pointer vPointer = ((NodePointer) pointer).getValuePointer();
assertEquals("Checking value pointer signature: " + path,
expectedValueSignature, pointerSignature(vPointer));
}
private void assertNullPointer(String path, String expectedPath,
String expectedSignature)
{
Pointer pointer = context.getPointer(path);
assertNotNull("Null path exists: " + path,
pointer);
assertEquals("Null path as path: " + path,
expectedPath, pointer.asPath());
assertEquals("Checking Signature: " + path,
expectedSignature, pointerSignature(pointer));
Pointer vPointer = ((NodePointer) pointer).getValuePointer();
assertTrue("Null path is null: " + path,
!((NodePointer) vPointer).isActual());
assertEquals("Checking value pointer signature: " + path,
expectedSignature + "N", pointerSignature(vPointer));
}
/**
* Since we need to test the internal Signature of a pointer,
* we will get a signature which will contain a single character
* per pointer in the chain, representing that pointer's type.
*/
private String pointerSignature(Pointer pointer) {
if (pointer == null) {
return "";
}
char type = '?';
if (pointer instanceof NullPointer) { type = 'N'; }
else if (pointer instanceof NullPropertyPointer) { type = 'n'; }
else if (pointer instanceof NullElementPointer) { type = 'E'; }
else if (pointer instanceof VariablePointer) { type = 'V'; }
else if (pointer instanceof CollectionPointer) { type = 'C'; }
else if (pointer instanceof BeanPointer) { type = 'B'; }
else if (pointer instanceof BeanPropertyPointer) { type = 'b'; }
else if (pointer instanceof DynamicPointer) { type = 'D'; }
else if (pointer instanceof DynamicPropertyPointer) { type = 'd'; }
else if (pointer instanceof DOMNodePointer) { type = 'M'; }
else {
System.err.println("UNKNOWN TYPE: " + pointer.getClass());
}
NodePointer parent =
((NodePointer) pointer).getImmediateParentPointer();
return pointerSignature(parent) + type;
}
}