1 /*
2 * $Header$
3 * $Revision$
4 * $Date$
5 *
6 * ====================================================================
7 *
8 * Copyright 2000-2002 bob mcwhirter & James Strachan.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are
13 * met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * * Neither the name of the Jaxen Project nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 * ====================================================================
39 * This software consists of voluntary contributions made by many
40 * individuals on behalf of the Jaxen Project and was originally
41 * created by bob mcwhirter <bob@werken.com> and
42 * James Strachan <jstrachan@apache.org>. For more information on the
43 * Jaxen Project, please see <http://www.jaxen.org/>.
44 *
45 * $Id$
46 */
47
48
49 package org.jaxen.test;
50
51 import java.io.IOException;
52
53 import javax.xml.parsers.DocumentBuilder;
54 import javax.xml.parsers.DocumentBuilderFactory;
55 import javax.xml.parsers.ParserConfigurationException;
56
57 import junit.framework.TestCase;
58
59 import org.jaxen.JaxenException;
60 import org.jaxen.XPath;
61 import org.jaxen.dom.DOMXPath;
62 import org.jaxen.saxpath.SAXPathException;
63 import org.jaxen.saxpath.base.XPathReader;
64 import org.jaxen.saxpath.XPathSyntaxException;
65 import org.w3c.dom.Document;
66 import org.xml.sax.SAXException;
67
68 public class XPathReaderTest extends TestCase
69 {
70 private ConformanceXPathHandler actual;
71 private Document doc;
72
73 private XPathReader reader;
74
75 private String[] paths = {
76 "/foo/bar[@a='1' and @b='2']",
77 "/foo/bar[@a='1' and @b!='2']",
78 "$varname[@a='1']",
79 "//attribute::*[.!='crunchy']",
80 "'//*[contains(string(text()),\"yada yada\")]'",
81 };
82
83 private String[][] bogusPaths = {
84 new String[]{"chyld::foo", "Expected valid axis name instead of [chyld]"},
85 new String[]{"foo/tacos()", "Expected node-type"},
86 new String[]{"foo/tacos()", "Expected node-type"},
87 new String[]{"*:foo", "Unexpected ':'"},
88 new String[]{"/foo/bar[baz", "Expected: ]"},
89 new String[]{"/cracker/cheese[(mold > 1) and (sense/taste", "Expected: )"},
90 new String[]{"//", "Location path cannot end with //"},
91 new String[]{"foo/$variable/foo", "Expected one of '.', '..', '@', '*', <QName>"}
92 };
93
94 public XPathReaderTest( String name )
95 {
96 super( name );
97 }
98
99 public void setUp() throws ParserConfigurationException, SAXException, IOException
100 {
101 this.reader = new XPathReader();
102
103 this.actual = new ConformanceXPathHandler();
104
105 this.reader.setXPathHandler( this.actual );
106
107 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
108 factory.setNamespaceAware(true);
109 DocumentBuilder builder = factory.newDocumentBuilder();
110 doc = builder.parse( "xml/basic.xml" );
111
112 }
113
114 public void tearDown()
115 {
116 this.reader = null;
117 }
118
119 // --------------------------------------------------------------------------------
120 // --------------------------------------------------------------------------------
121
122
123 public void testPaths() throws SAXPathException
124 {
125
126 for( int i = 0; i < paths.length; ++i )
127 {
128 reader.parse( paths[i] );
129 }
130 }
131
132 public void testBogusPaths() throws SAXPathException
133 {
134
135 for( int i = 0; i < bogusPaths.length; ++i )
136 {
137 final String[] bogusPath = bogusPaths[i];
138
139 try
140 {
141 reader.parse( bogusPath[0] );
142 fail( "Should have thrown XPathSyntaxException for " + bogusPath[0]);
143 }
144 catch( XPathSyntaxException e )
145 {
146 assertEquals( bogusPath[1], e.getMessage() );
147 }
148 }
149 }
150
151 public void testChildrenOfNumber() throws SAXPathException
152 {
153 try
154 {
155 reader.parse( "1/child::test" );
156 fail( "Should have thrown XPathSyntaxException for 1/child::test");
157 }
158 catch( XPathSyntaxException e )
159 {
160 assertEquals( "Node-set expected", e.getMessage() );
161 }
162 }
163
164 public void testChildIsNumber() throws SAXPathException
165 {
166 try
167 {
168 reader.parse( "jane/3" );
169 fail( "Should have thrown XPathSyntaxException for jane/3");
170 }
171 catch( XPathSyntaxException e )
172 {
173 assertEquals( "Expected one of '.', '..', '@', '*', <QName>", e.getMessage() );
174 }
175
176 }
177
178 public void testNumberOrNumber()
179 {
180
181 try
182 {
183 XPath xpath = new DOMXPath( "4 | 5" );
184 xpath.selectNodes( doc );
185 fail( "Should have thrown XPathSyntaxException for 4 | 5");
186 }
187 catch( JaxenException e )
188 {
189 assertEquals( "Unions are only allowed over node-sets", e.getMessage() );
190 }
191 }
192
193 public void testStringOrNumber()
194 {
195
196 try
197 {
198 XPath xpath = new DOMXPath( "\"test\" | 5" );
199 xpath.selectNodes( doc );
200 fail( "Should have thrown XPathSyntaxException for \"test\" | 5");
201 }
202 catch( JaxenException e )
203 {
204 assertEquals( "Unions are only allowed over node-sets", e.getMessage() );
205 }
206 }
207
208 public void testStringOrString()
209 {
210
211 try
212 {
213 XPath xpath = new DOMXPath( "\"test\" | \"festival\"" );
214 xpath.selectNodes( doc );
215 fail( "Should have thrown XPathSyntaxException for \"test\" | 5");
216 }
217 catch( JaxenException e )
218 {
219 assertEquals( "Unions are only allowed over node-sets", e.getMessage() );
220 }
221
222 }
223
224 public void testUnionofNodesAndNonNodes()
225 {
226
227 try
228 {
229 XPath xpath = new DOMXPath( "count(//*) | //* " );
230 xpath.selectNodes( doc );
231 fail( "Should have thrown XPathSyntaxException for \"count(//*) | //* ");
232 }
233 catch( JaxenException e )
234 {
235 assertEquals( "Unions are only allowed over node-sets", e.getMessage() );
236 }
237 }
238
239 public void testValidAxis() throws SAXPathException
240 {
241 reader.parse( "child::foo" );
242 }
243
244 public void testInvalidAxis() throws SAXPathException
245 {
246
247 try
248 {
249 reader.parse( "chyld::foo" );
250 fail( "Should have thrown XPathSyntaxException" );
251 }
252 catch( XPathSyntaxException ex )
253 {
254 assertNotNull(ex.getMessage());
255 }
256
257 }
258
259 /* public void testSimpleNameStep() throws SAXPathException
260 {
261 this.text = "foo";
262 this.reader.setUpParse( this.text );
263 this.reader.step( );
264 this.expected.startNameStep( Axis.CHILD,
265 "",
266 "foo" );
267 this.expected.endNameStep();
268 assertEquals( this.expected,
269 this.actual );
270
271 }
272
273 public void testNameStepWithAxisAndPrefix() throws SAXPathException
274 {
275 this.text = "parent::foo:bar";
276 this.reader.setUpParse( this.text );
277 this.reader.step( );
278 this.expected.startNameStep( Axis.PARENT,
279 "foo",
280 "bar" );
281 this.expected.endNameStep();
282 assertEquals( this.expected,
283 this.actual );
284
285 }
286
287 public void testNodeStepWithAxis() throws SAXPathException
288 {
289
290 this.text = "parent::node()";
291 this.reader.setUpParse( this.text );
292 this.reader.step();
293 this.expected.startAllNodeStep( Axis.PARENT );
294 this.expected.endAllNodeStep();
295 assertEquals( this.expected,
296 this.actual );
297
298 }
299
300 public void testProcessingInstructionStepWithName() throws SAXPathException
301 {
302 this.text = "parent::processing-instruction('cheese')";
303 this.reader.setUpParse( this.text );
304 this.reader.step( );
305 this.expected.startProcessingInstructionNodeStep( Axis.PARENT,
306 "cheese" );
307 this.expected.endProcessingInstructionNodeStep();
308 assertEquals( this.expected,
309 this.actual );
310 }
311
312 public void testProcessingInstructionStepNoName() throws SAXPathException
313 {
314 this.text = "parent::processing-instruction()";
315 this.reader.setUpParse( this.text );
316 this.reader.step( );
317 this.expected.startProcessingInstructionNodeStep( Axis.PARENT,
318 "" );
319 this.expected.endProcessingInstructionNodeStep();
320 assertEquals( this.expected,
321 this.actual );
322
323 }
324
325 public void testAllNodeStep() throws SAXPathException
326 {
327
328 this.text = "parent::node()";
329 this.reader.setUpParse( this.text );
330 this.reader.step( );
331 this.expected.startAllNodeStep( Axis.PARENT );
332 this.expected.endAllNodeStep();
333 assertEquals( this.expected,
334 this.actual );
335
336 }
337
338 public void testTextNodeStep() throws SAXPathException
339 {
340
341 this.text = "parent::text()";
342 this.reader.setUpParse( this.text );
343 this.reader.step( );
344 this.expected.startTextNodeStep( Axis.PARENT );
345 this.expected.endTextNodeStep();
346 assertEquals( this.expected,
347 this.actual );
348
349 }
350
351 public void testCommentNodeStep() throws SAXPathException
352 {
353
354 this.text = "parent::comment()";
355 this.reader.setUpParse( this.text );
356 this.reader.step( );
357 this.expected.startCommentNodeStep( Axis.PARENT );
358 this.expected.endCommentNodeStep();
359 assertEquals( this.expected,
360 this.actual );
361
362 }*/
363
364 public void testLocationPathStartsWithVariable() throws SAXPathException
365 {
366
367 reader.parse( "$variable/foo" );
368
369 }
370
371 public void testLocationPathStartsWithParentheses() throws SAXPathException
372 {
373
374 reader.parse( "(//x)/foo" );
375
376 }
377
378 /*public void testRelativeLocationPath() throws SAXPathException
379 {
380
381 this.text = "foo/bar/baz";
382 this.reader.setUpParse( this.text );
383 this.reader.locationPath( false );
384 this.expected.startRelativeLocationPath();
385 this.expected.startNameStep( Axis.CHILD,
386 "",
387 "foo" );
388 this.expected.endNameStep();
389 this.expected.startNameStep( Axis.CHILD,
390 "",
391 "bar" );
392 this.expected.endNameStep();
393 this.expected.startNameStep( Axis.CHILD,
394 "",
395 "baz" );
396 this.expected.endNameStep();
397 this.expected.endRelativeLocationPath();
398 assertEquals( this.expected,
399 this.actual );
400
401 }
402
403 public void testAbsoluteLocationPath() throws SAXPathException
404 {
405
406 this.text = "/foo/bar/baz";
407 this.reader.setUpParse( this.text );
408 this.reader.locationPath( true );
409 this.expected.startAbsoluteLocationPath();
410 this.expected.startNameStep( Axis.CHILD,
411 "",
412 "foo" );
413 this.expected.endNameStep();
414 this.expected.startNameStep( Axis.CHILD,
415 "",
416 "bar" );
417 this.expected.endNameStep();
418 this.expected.startNameStep( Axis.CHILD,
419 "",
420 "baz" );
421 this.expected.endNameStep();
422 this.expected.endAbsoluteLocationPath();
423 assertEquals( this.expected,
424 this.actual );
425
426 }*/
427
428 public void testNoSpaceAfterDiv() throws JaxenException
429 {
430 XPath xpath = new DOMXPath( "105 div10" );
431 Double result = (Double) xpath.evaluate(doc);
432 assertEquals(10.5, result.doubleValue(), 0.000001);
433 }
434
435
436 public void testNoSpaceAfterMod() throws JaxenException
437 {
438 XPath xpath = new DOMXPath( "105 mod10" );
439 Double result = (Double) xpath.evaluate(doc);
440 assertEquals(5, result.intValue());
441 }
442
443
444 public void testNoSpaceAfterPlus() throws JaxenException
445 {
446 XPath xpath = new DOMXPath( "105 +10" );
447 Double result = (Double) xpath.evaluate(doc);
448 assertEquals(115, result.intValue());
449 }
450
451 public void testNoSpaceAfterAnd() throws JaxenException
452 {
453 XPath xpath = new DOMXPath("true() andfalse()");
454 Boolean result = (Boolean) xpath.evaluate(doc);
455 assertFalse(result.booleanValue());
456 }
457
458 public void testNoSpaceAfterOr() throws JaxenException
459 {
460 XPath xpath = new DOMXPath("true() orfalse()");
461 Boolean result = (Boolean) xpath.evaluate(doc);
462 assertTrue(result.booleanValue());
463 }
464
465 public void testAndImmediatelyFollowedByRelativeLocationPath() throws JaxenException
466 {
467 XPath xpath = new DOMXPath("true() andfoo");
468 Boolean result = (Boolean) xpath.evaluate(doc);
469 assertTrue(result.booleanValue());
470 }
471
472 }