/*
* 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.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathTestCase;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.TestBean;
import org.apache.commons.jxpath.TestMixedModelBean;
import org.apache.commons.jxpath.TestNull;
import org.apache.commons.jxpath.Variables;
/**
* Tests JXPath with mixed model: beans, maps, DOM etc.
*
* @author Dmitri Plotnikov
* @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
*/
public class MixedModelTest extends JXPathTestCase {
private JXPathContext context;
public void setUp() {
TestMixedModelBean bean = new TestMixedModelBean();
context = JXPathContext.newContext(bean);
context.setFactory(new TestMixedModelFactory());
context.setLocale(Locale.US);
Variables vars = context.getVariables();
vars.declareVariable("string", bean.getString());
vars.declareVariable("bean", bean.getBean());
vars.declareVariable("map", bean.getMap());
vars.declareVariable("list", bean.getList());
vars.declareVariable("document", bean.getDocument());
vars.declareVariable("element", bean.getElement());
vars.declareVariable("container", bean.getContainer());
vars.declareVariable("testnull", new TestNull());
int[][] matrix = new int[1][];
matrix[0] = new int[1];
matrix[0][0] = 3;
vars.declareVariable("matrix", matrix);
}
public void testVar() {
context.getVariables().declareVariable("foo:bar", "baz");
assertXPathValueAndPointer(context,
"$foo:bar",
"baz",
"$foo:bar");
}
public void testVarPrimitive() {
assertXPathValueAndPointer(context, "$string", "string", "$string");
}
public void testVarBean() {
assertXPathValueAndPointer(
context,
"$bean/int",
new Integer(1),
"$bean/int");
}
public void testVarMap() {
assertXPathValueAndPointer(
context,
"$map/string",
"string",
"$map[@name='string']");
}
public void testVarList() {
assertXPathValueAndPointer(context, "$list[1]", "string", "$list[1]");
}
public void testVarDocument() {
assertXPathValueAndPointer(
context,
"$document/vendor/location/address/city",
"Fruit Market",
"$document/vendor[1]/location[2]/address[1]/city[1]");
}
public void testVarElement() {
assertXPathValueAndPointer(
context,
"$element/location/address/city",
"Fruit Market",
"$element/location[2]/address[1]/city[1]");
}
public void testVarContainer() {
assertXPathValueAndPointer(
context,
"$container/vendor/location/address/city",
"Fruit Market",
"$container/vendor[1]/location[2]/address[1]/city[1]");
}
// ----------------------------------------------------------------------
public void testBeanPrimitive() {
assertXPathValueAndPointer(context, "string", "string", "/string");
}
public void testBeanBean() {
assertXPathValueAndPointer(
context,
"bean/int",
new Integer(1),
"/bean/int");
}
public void testBeanMap() {
assertXPathValueAndPointer(
context,
"map/string",
"string",
"/map[@name='string']");
}
public void testBeanList() {
assertXPathValueAndPointer(context, "list[1]", "string", "/list[1]");
}
public void testBeanDocument() {
assertXPathValueAndPointer(
context,
"document/vendor/location/address/city",
"Fruit Market",
"/document/vendor[1]/location[2]/address[1]/city[1]");
}
public void testBeanElement() {
assertXPathValueAndPointer(
context,
"element/location/address/city",
"Fruit Market",
"/element/location[2]/address[1]/city[1]");
}
public void testBeanContainer() {
assertXPathValueAndPointer(
context,
"container/vendor/location/address/city",
"Fruit Market",
"/container/vendor[1]/location[2]/address[1]/city[1]");
}
// ----------------------------------------------------------------------
public void testMapPrimitive() {
assertXPathValueAndPointer(
context,
"map/string",
"string",
"/map[@name='string']");
}
public void testMapBean() {
assertXPathValueAndPointer(
context,
"map/bean/int",
new Integer(1),
"/map[@name='bean']/int");
}
public void testMapMap() {
assertXPathValueAndPointer(
context,
"map/map/string",
"string",
"/map[@name='map'][@name='string']");
}
public void testMapList() {
assertXPathValueAndPointer(
context,
"map/list[1]",
"string",
"/map[@name='list'][1]");
}
public void testMapDocument() {
assertXPathValueAndPointer(
context,
"map/document/vendor/location/address/city",
"Fruit Market",
"/map[@name='document']"
+ "/vendor[1]/location[2]/address[1]/city[1]");
}
public void testMapElement() {
assertXPathValueAndPointer(
context,
"map/element/location/address/city",
"Fruit Market",
"/map[@name='element']/location[2]/address[1]/city[1]");
}
public void testMapContainer() {
assertXPathValueAndPointer(
context,
"map/container/vendor/location/address/city",
"Fruit Market",
"/map[@name='container']"
+ "/vendor[1]/location[2]/address[1]/city[1]");
}
// ----------------------------------------------------------------------
public void testListPrimitive() {
assertXPathValueAndPointer(context, "list[1]", "string", "/list[1]");
}
public void testListBean() {
assertXPathValueAndPointer(
context,
"list[2]/int",
new Integer(1),
"/list[2]/int");
}
public void testListMap() {
assertXPathValueAndPointer(
context,
"list[3]/string",
"string",
"/list[3][@name='string']");
}
public void testListList() {
/** @todo: what is this supposed to do? Should we stick to XPath,
* in which case [1] is simply ignored, or Java, in which case
* it is supposed to extract the first element from the list?
*/
// assertXPathValueAndPointer(context,
// "list[4][1]",
// "string2",
// "/list[4][1]");
assertXPathValueAndPointer(
context,
"list[4]/.[1]",
"string2",
"/list[4]/.[1]");
}
public void testListDocument() {
assertXPathValueAndPointer(
context,
"list[5]/vendor/location/address/city",
"Fruit Market",
"/list[5]/vendor[1]/location[2]/address[1]/city[1]");
}
public void testListElement() {
assertXPathValueAndPointer(
context,
"list[6]/location/address/city",
"Fruit Market",
"/list[6]/location[2]/address[1]/city[1]");
}
public void testListContainer() {
assertXPathValueAndPointer(
context,
"list[7]/vendor/location/address/city",
"Fruit Market",
"/list[7]/vendor[1]/location[2]/address[1]/city[1]");
}
public void testNull() {
assertXPathPointerLenient(context, "$null", "$null");
assertXPathPointerLenient(context, "$null[3]", "$null[3]");
assertXPathPointerLenient(
context,
"$testnull/nothing",
"$testnull/nothing");
assertXPathPointerLenient(
context,
"$testnull/nothing[2]",
"$testnull/nothing[2]");
assertXPathPointerLenient(context, "beans[8]/int", "/beans[8]/int");
assertXPathValueIterator(
context,
"$testnull/nothing[1]",
Collections.EMPTY_LIST);
JXPathContext ctx = JXPathContext.newContext(new TestNull());
assertXPathValue(ctx, "nothing", null);
assertXPathValue(ctx, "child/nothing", null);
assertXPathValue(ctx, "array[2]", null);
assertXPathValueLenient(ctx, "nothing/something", null);
assertXPathValueLenient(ctx, "array[2]/something", null);
}
public void testRootAsCollection() {
assertXPathValue(context, ".[1]/string", "string");
}
public void testCreatePath() {
context = JXPathContext.newContext(new TestBean());
context.setFactory(new TestMixedModelFactory());
TestBean bean = (TestBean) context.getContextBean();
bean.setMap(null);
assertXPathCreatePath(
context,
"/map[@name='TestKey5']/nestedBean/int",
new Integer(1),
"/map[@name='TestKey5']/nestedBean/int");
bean.setMap(null);
assertXPathCreatePath(
context,
"/map[@name='TestKey5']/beans[2]/int",
new Integer(1),
"/map[@name='TestKey5']/beans[2]/int");
}
/**
* Test JXPath.iterate() with map containing an array
*/
public void testIterateArray() {
Map map = new HashMap();
map.put("foo", new String[] { "a", "b", "c" });
JXPathContext context = JXPathContext.newContext(map);
assertXPathValueIterator(context, "foo", list("a", "b", "c"));
}
public void testIteratePointersArray() {
Map map = new HashMap();
map.put("foo", new String[] { "a", "b", "c" });
JXPathContext context = JXPathContext.newContext(map);
Iterator it = context.iteratePointers("foo");
List actual = new ArrayList();
while (it.hasNext()) {
Pointer ptr = (Pointer) it.next();
actual.add(context.getValue(ptr.asPath()));
}
assertEquals(
"Iterating pointers <" + "foo" + ">",
list("a", "b", "c"),
actual);
}
public void testIteratePointersArrayElementWithVariable() {
Map map = new HashMap();
map.put("foo", new String[] { "a", "b", "c" });
JXPathContext context = JXPathContext.newContext(map);
context.getVariables().declareVariable("x", new Integer(2));
Iterator it = context.iteratePointers("foo[$x]");
List actual = new ArrayList();
while (it.hasNext()) {
Pointer ptr = (Pointer) it.next();
actual.add(context.getValue(ptr.asPath()));
}
assertEquals("Iterating pointers <" + "foo" + ">", list("b"), actual);
}
public void testIterateVector() {
Map map = new HashMap();
Vector vec = new Vector();
vec.add(new HashMap());
vec.add(new HashMap());
map.put("vec", vec);
JXPathContext context = JXPathContext.newContext(map);
assertXPathPointerIterator(
context,
"/vec",
list("/.[@name='vec'][1]", "/.[@name='vec'][2]"));
}
public void testErrorProperty() {
context.getVariables().declareVariable(
"e",
new ExceptionPropertyTestBean());
boolean ex = false;
try {
assertXPathValue(context, "$e/errorString", null);
}
catch (Throwable t) {
ex = true;
}
assertTrue("Legitimate exception accessing property", ex);
assertXPathPointer(context, "$e/errorString", "$e/errorString");
assertXPathPointerLenient(
context,
"$e/errorStringArray[1]",
"$e/errorStringArray[1]");
assertXPathPointerIterator(
context,
"$e/errorString",
list("$e/errorString"));
assertXPathPointerIterator(
context,
"$e//error",
Collections.EMPTY_LIST);
}
public void testMatrix() {
assertXPathValueAndPointer(
context,
"$matrix[1]/.[1]",
new Integer(3),
"$matrix[1]/.[1]");
context.setValue("$matrix[1]/.[1]", new Integer(2));
assertXPathValueAndPointer(
context,
"matrix[1]/.[1]",
new Integer(3),
"/matrix[1]/.[1]");
context.setValue("matrix[1]/.[1]", "2");
assertXPathValue(context, "matrix[1]/.[1]", new Integer(2));
context.getVariables().declareVariable(
"wholebean",
context.getContextBean());
assertXPathValueAndPointer(
context,
"$wholebean/matrix[1]/.[1]",
new Integer(2),
"$wholebean/matrix[1]/.[1]");
boolean ex = false;
try {
context.setValue("$wholebean/matrix[1]/.[2]", "4");
}
catch (Exception e) {
ex = true;
}
assertTrue("Exception setting value of non-existent element", ex);
ex = false;
try {
context.setValue("$wholebean/matrix[2]/.[1]", "4");
}
catch (Exception e) {
ex = true;
}
assertTrue("Exception setting value of non-existent element", ex);
}
public void testCreatePathAndSetValueWithMatrix() {
context.setValue("matrix", null);
// Calls factory.createObject(..., TestMixedModelBean, "matrix")
// Calls factory.createObject(..., nestedBean, "strings", 2)
assertXPathCreatePathAndSetValue(
context,
"/matrix[1]/.[1]",
new Integer(4),
"/matrix[1]/.[1]");
}
/**
* Scott Heaberlin's test - collection of collections
*/
public void testCollectionPointer() {
List list = new ArrayList();
Map map = new HashMap();
map.put("KeyOne", "SomeStringOne");
map.put("KeyTwo", "SomeStringTwo");
Map map2 = new HashMap();
map2.put("KeyA", "StringA");
map2.put("KeyB", "StringB");
map.put("KeyThree", map2);
list.add(map);
List list2 = new ArrayList();
list2.add("foo");
list2.add(map);
list2.add(map);
list.add(list2);
context = JXPathContext.newContext(list);
assertEquals("SomeStringOne", context.getValue(".[1]/KeyOne"));
assertEquals("StringA", context.getValue(".[1]/KeyThree/KeyA"));
assertEquals(new Integer(3), context.getValue("size(.[1]/KeyThree)"));
assertEquals(new Double(6.0), context.getValue("count(.[1]/KeyThree/*)"));
assertEquals(new Double(3.0), context.getValue("count(.[1]/KeyThree/KeyA)"));
}
}