001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.support.xstream;
018:
019: import java.io.ByteArrayInputStream;
020:
021: import javax.xml.parsers.DocumentBuilderFactory;
022: import javax.xml.xpath.XPath;
023: import javax.xml.xpath.XPathConstants;
024:
025: import junit.framework.TestCase;
026:
027: import org.junit.Test;
028: import org.w3c.dom.Document;
029: import org.w3c.dom.Node;
030: import org.w3c.dom.NodeList;
031:
032: import edu.iu.uis.eden.routetemplate.xmlrouting.XPathHelper;
033:
034: public class XStreamSafeEvaluatorTest extends TestCase {
035:
036: private static final String XML = "<document>"
037: + " <beans>"
038: + " <testBean1>"
039: + " <bean1Name>Bean One #1</bean1Name>"
040: + " <bean2>"
041: + " <seeHowFarTheRabbitHoleGoes><value>20</value></seeHowFarTheRabbitHoleGoes>"
042: + " <bean2Name>Bean Two #1</bean2Name>"
043: + " <redPill reference=\"../../../redPill\"/>"
044: + " <redPill reference=\"../seeHowFarTheRabbitHoleGoes\"/>"
045: + " <redPill><value>30</value></redPill>"
046: + " </bean2>" + " </testBean1>" + " <testBean1>"
047: + " <bean1Name>Bean One #2</bean1Name>"
048: + " <bean2 reference=\"../../testBean1/bean2\"/>"
049: + " </testBean1>"
050: + " <redPill><value>10</value></redPill>" + " </beans>"
051: + "</document>";
052:
053: private static final String XML2 = "<document>"
054: + " <test1 reference=\"../test2\"/>"
055: + " <test2 reference=\"../test3\"/>"
056: + " <test3>test3</test3>" + "</document>";
057:
058: private static final String XPATH_NO_REF = "//document/beans/testBean1/bean1Name";
059: private static final String XPATH_THROUGH_REF = "//document/beans/testBean1/bean2/bean2Name";
060: private static final String XPATH_RED_PILL = "//document/beans/testBean1/bean2/redPill/value";
061:
062: private static final String XPATH2_TEST1 = "/document/test1";
063: private static final String XPATH2_TEST2 = "//test2";
064: private static final String XPATH2_TEST3 = "//document/test3";
065:
066: private static final String XPATH_GET_FOR_RELATIVE = "/document/beans/testBean1/bean2";
067: //private static final String XPATH_GLOBAL_VALUE = ".//value";
068: private static final String XPATH_VALUE_20_RELATIVE = "./seeHowFarTheRabbitHoleGoes/value";
069: private static final String XPATH_VALUE_10_20_30_RELATIVE = "./redPill/value";
070:
071: private Document document;
072: private XStreamSafeEvaluator eval = new XStreamSafeEvaluator();
073: private XPath xpath;
074:
075: /**
076: * Set up an XPath instance using our XPathHelper which should configure the namespace and
077: * WorkflowFunctionResolver for us.
078: */
079: public void setUp() throws Exception {
080: super .setUp();
081: document = DocumentBuilderFactory.newInstance()
082: .newDocumentBuilder().parse(
083: new ByteArrayInputStream(XML.getBytes()));
084: xpath = XPathHelper.newXPath(document);
085: }
086:
087: @Test
088: public void testEvaluation() throws Exception {
089: // test against straight xpath first
090: NodeList nodeList = (NodeList) xpath.evaluate(XPATH_NO_REF,
091: document, XPathConstants.NODESET);
092: assertEquals("Should find 2 nodes.", 2, nodeList.getLength());
093: nodeList = (NodeList) xpath.evaluate(XPATH_THROUGH_REF,
094: document, XPathConstants.NODESET);
095: assertEquals("Should find 1 nodes.", 1, nodeList.getLength());
096:
097: // test against our evaluator, it should be able to follow our reference path
098: nodeList = eval.evaluate(XPATH_NO_REF, document);
099: assertEquals("Should find 2 nodes.", 2, nodeList.getLength());
100: nodeList = eval.evaluate(XPATH_THROUGH_REF, document);
101: assertEquals("Should find 2 nodes.", 2, nodeList.getLength());
102:
103: // now test our evaluator exposed as an XPath function
104: nodeList = (NodeList) xpath.evaluate(
105: wrapXStreamSafe(XPATH_NO_REF), document,
106: XPathConstants.NODESET);
107: assertEquals("Should find 2 nodes.", 2, nodeList.getLength());
108: nodeList = (NodeList) xpath.evaluate(
109: wrapXStreamSafe(XPATH_THROUGH_REF), document,
110: XPathConstants.NODESET);
111: assertEquals("Should find 2 nodes.", 2, nodeList.getLength());
112:
113: // now test a bit more complicated XML
114: nodeList = (NodeList) xpath.evaluate(XPATH_RED_PILL, document,
115: XPathConstants.NODESET);
116: assertEquals(
117: "Without XStream safe evaulation, should only find 1 node.",
118: 1, nodeList.getLength());
119: System.out.println("\n\n\n\n");
120: nodeList = (NodeList) xpath.evaluate(
121: wrapXStreamSafe(XPATH_RED_PILL), document,
122: XPathConstants.NODESET);
123: assertEquals("Should have 6 nodes.", 6, nodeList.getLength());
124: String totalValue = xpath.evaluate("sum("
125: + wrapXStreamSafe(XPATH_RED_PILL) + ")", document);
126: assertEquals("Sum should be 120.", "120", totalValue);
127: }
128:
129: /**
130: * Tests the case where the last node that resulted from the evaulation of the xpath has a "reference" attribute
131: * on it. I found a bug where this last "reference" attribute was not being evaluated and resolved to the
132: * proper node.
133: *
134: * This method also does some testing of chaining of reference nodes (i.e. a node has a reference to a node
135: * which has a reference to another node).
136: */
137: @Test
138: public void testTerminalReferences() throws Exception {
139: document = DocumentBuilderFactory.newInstance()
140: .newDocumentBuilder().parse(
141: new ByteArrayInputStream(XML2.getBytes()));
142: xpath = XPathHelper.newXPath(document);
143:
144: // test against straight xpath first
145: NodeList nodeList = (NodeList) xpath.evaluate(XPATH2_TEST1,
146: document, XPathConstants.NODESET);
147: assertEquals("There should be one node.", 1, nodeList
148: .getLength());
149: assertEquals("The first node should be named 'test1'", "test1",
150: nodeList.item(0).getNodeName());
151: assertEquals("The node should have no children.", 0, nodeList
152: .item(0).getChildNodes().getLength());
153: assertNotNull("The node should have a reference attribute.",
154: nodeList.item(0).getAttributes().getNamedItem(
155: "reference"));
156:
157: String test3Value = xpath.evaluate(XPATH2_TEST3, document);
158: assertEquals("test3", test3Value);
159:
160: // test using the xstreamsafe function
161: String test1Value = xpath.evaluate(
162: wrapXStreamSafe(XPATH2_TEST1), document);
163: assertEquals("test3", test1Value);
164:
165: String test2Value = xpath.evaluate(
166: wrapXStreamSafe(XPATH2_TEST2), document);
167: assertEquals("test3", test2Value);
168:
169: test3Value = xpath.evaluate(wrapXStreamSafe(XPATH2_TEST3),
170: document);
171: assertEquals("test3", test3Value);
172: }
173:
174: /**
175: * Tests the usage of XPath expressions which are evaluated relative to a particular context (i.e. starts with a ".").
176: * This tests the resolution to EN-100.
177: */
178: @Test
179: public void testContextRelativeExpressions() throws Exception {
180: // drill down in the document to an element which we will use as our context
181: NodeList nodeList = (NodeList) xpath.evaluate(
182: XPATH_GET_FOR_RELATIVE, document,
183: XPathConstants.NODESET);
184: assertEquals("There should be two nodes.", 2, nodeList
185: .getLength());
186: // run the same xpath through the xstreamsafe evaluator
187: nodeList = (NodeList) xpath.evaluate(
188: wrapXStreamSafe(XPATH_GET_FOR_RELATIVE), document,
189: XPathConstants.NODESET);
190: assertEquals("There should be two nodes.", 2, nodeList
191: .getLength());
192:
193: // now drill down using the first node in the list as the context
194: Node node = nodeList.item(0);
195: // reconstruct the XPath instance for the given root node
196: xpath = XPathHelper.newXPath(node);
197: // look for <value> elements, there should be two
198:
199: // TODO we currently can't support xpath expressions that start with .// When we can, uncomment this test code.
200: // nodeList = (NodeList)xpath.evaluate(XPATH_GLOBAL_VALUE, node, XPathConstants.NODESET);
201: // assertEquals("There should be two value elements.", 2, nodeList.getLength());
202: // // evaluate as xstreamsafe
203: // nodeList = (NodeList)xpath.evaluate(wrapXStreamSafe(XPATH_GLOBAL_VALUE), node, XPathConstants.NODESET);
204: // assertEquals("There should be three value elements now.", 3, nodeList.getLength());
205:
206: // try to find the value inside of redpill section
207: String value = xpath.evaluate(XPATH_VALUE_20_RELATIVE, node);
208: assertEquals("20", value);
209: // do with xstreamsafe
210: value = xpath.evaluate(
211: wrapXStreamSafe(XPATH_VALUE_20_RELATIVE), node);
212: assertEquals("20", value);
213:
214: // test non xstreamsafe, should only be 1 node
215: nodeList = (NodeList) xpath.evaluate(
216: XPATH_VALUE_10_20_30_RELATIVE, node,
217: XPathConstants.NODESET);
218: assertEquals("NodeList should have 1 elements.", 1, nodeList
219: .getLength());
220:
221: // test with xstreamsafe, should be 3 nodes
222: nodeList = (NodeList) xpath.evaluate(
223: wrapXStreamSafe(XPATH_VALUE_10_20_30_RELATIVE), node,
224: XPathConstants.NODESET);
225: assertEquals("NodeList should have 3 elements.", 3, nodeList
226: .getLength());
227: }
228:
229: private String wrapXStreamSafe(String xPathExpression) {
230: return "wf:xstreamsafe('" + xPathExpression + "')";
231: }
232:
233: }
|