1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.digester3;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNotSame;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertSame;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29
30 import java.io.File;
31 import java.io.InputStream;
32 import java.io.Reader;
33 import java.io.StringReader;
34 import java.math.BigDecimal;
35 import java.net.URL;
36 import java.util.ArrayList;
37 import java.util.EmptyStackException;
38 import java.util.Map;
39
40 import org.apache.commons.digester3.Digester;
41 import org.apache.commons.digester3.ObjectCreateRule;
42 import org.apache.commons.digester3.Rule;
43 import org.apache.commons.digester3.RulesBase;
44 import org.apache.commons.digester3.StackAction;
45 import org.apache.commons.digester3.Substitutor;
46 import org.junit.After;
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.xml.sax.Attributes;
50 import org.xml.sax.InputSource;
51 import org.xml.sax.helpers.AttributesImpl;
52
53
54
55
56
57
58
59
60
61 public class DigesterTestCase
62 {
63
64
65
66
67
68
69 protected Digester digester = null;
70
71
72
73
74
75 protected static final String registrations[] = { "-//Netscape Communications//DTD RSS 0.9//EN",
76 "/org/apache/commons/digester3/rss/rss-0.9.dtd", "-//Netscape Communications//DTD RSS 0.91//EN",
77 "/org/apache/commons/digester3/rss/rss-0.91.dtd", };
78
79
80
81
82
83
84 @Before
85 public void setUp()
86 {
87
88 digester = new Digester();
89 digester.setRules( new RulesBase() );
90
91 }
92
93
94
95
96 @After
97 public void tearDown()
98 {
99
100 digester = null;
101
102 }
103
104
105
106
107
108
109 @Test
110 public void testNullFileParse()
111 throws Exception
112 {
113
114 try
115 {
116 digester.parse( (File) null );
117 fail( "Expected IllegalArgumentException with null argument" );
118 }
119 catch ( IllegalArgumentException e )
120 {
121
122 }
123
124 }
125
126 @Test
127 public void testNullInputSourceParse()
128 throws Exception
129 {
130
131 try
132 {
133 digester.parse( (InputSource) null );
134 fail( "Expected IllegalArgumentException with null argument" );
135 }
136 catch ( IllegalArgumentException e )
137 {
138
139 }
140
141 }
142
143 @Test
144 public void testNullInputStreamParse()
145 throws Exception
146 {
147
148 try
149 {
150 digester.parse( (InputStream) null );
151 fail( "Expected IllegalArgumentException with null argument" );
152 }
153 catch ( IllegalArgumentException e )
154 {
155
156 }
157
158 }
159
160 @Test
161 public void testNullReaderParse()
162 throws Exception
163 {
164
165 try
166 {
167 digester.parse( (Reader) null );
168 fail( "Expected IllegalArgumentException with null argument" );
169 }
170 catch ( IllegalArgumentException e )
171 {
172
173 }
174
175 }
176
177 @Test
178 public void testNullStringParse()
179 throws Exception
180 {
181
182 try
183 {
184 digester.parse( (String) null );
185 fail( "Expected IllegalArgumentException with null argument" );
186 }
187 catch ( IllegalArgumentException e )
188 {
189
190 }
191
192 }
193
194 @Test
195 public void testNullURLParse()
196 throws Exception
197 {
198
199 try
200 {
201 digester.parse( (URL) null );
202 fail( "Expected IllegalArgumentException with null argument" );
203 }
204 catch ( IllegalArgumentException e )
205 {
206
207 }
208
209 }
210
211
212
213
214 @Test
215 public void testProperties()
216 {
217
218 assertNull( "Initial error handler is null", digester.getErrorHandler() );
219 digester.setErrorHandler( digester );
220 assertTrue( "Set error handler is digester", digester.getErrorHandler() == digester );
221 digester.setErrorHandler( null );
222 assertNull( "Reset error handler is null", digester.getErrorHandler() );
223
224 assertTrue( "Initial namespace aware is false", !digester.getNamespaceAware() );
225 digester.setNamespaceAware( true );
226 assertTrue( "Set namespace aware is true", digester.getNamespaceAware() );
227 digester.setNamespaceAware( false );
228 assertTrue( "Reset namespace aware is false", !digester.getNamespaceAware() );
229
230 assertTrue( "Initial validating is false", !digester.getValidating() );
231 digester.setValidating( true );
232 assertTrue( "Set validating is true", digester.getValidating() );
233 digester.setValidating( false );
234 assertTrue( "Reset validating is false", !digester.getValidating() );
235
236 }
237
238
239
240
241 @Test
242 public void testRegistrations()
243 {
244
245 Map<String, URL> map = digester.getRegistrations();
246 assertEquals( "Initially zero registrations", 0, map.size() );
247 int n = 0;
248 for ( int i = 0; i < registrations.length; i += 2 )
249 {
250 URL url = this.getClass().getResource( registrations[i + 1] );
251 if ( url != null )
252 {
253 digester.register( registrations[i], url );
254 n++;
255 }
256 }
257 map = digester.getRegistrations();
258 assertEquals( "Registered two URLs", n, map.size() );
259
260 int count[] = new int[n];
261 for ( int i = 0; i < n; i++ )
262 count[i] = 0;
263 for ( String key : map.keySet() )
264 {
265 for ( int i = 0; i < n; i++ )
266 {
267 if ( key.equals( registrations[i * 2] ) )
268 {
269 count[i]++;
270 break;
271 }
272 }
273 }
274 for ( int i = 0; i < n; i++ )
275 assertEquals( "Count for key " + registrations[i * 2], 1, count[i] );
276
277 }
278
279
280
281
282 @Test
283 public void testRules()
284 {
285
286 assertEquals( "Initial rules list is empty", 0, digester.getRules().match( null, "a", null, null ).size() );
287 digester.addSetProperties( "a" );
288 assertEquals( "Add a matching rule", 1, digester.getRules().match( null, "a", null, null ).size() );
289 digester.addSetProperties( "b" );
290 assertEquals( "Add a non-matching rule", 1, digester.getRules().match( null, "a", null, null ).size() );
291 digester.addSetProperties( "a/b" );
292 assertEquals( "Add a non-matching nested rule", 1, digester.getRules().match( null, "a", null, null ).size() );
293 digester.addSetProperties( "a/b" );
294 assertEquals( "Add a second matching rule", 2, digester.getRules().match( null, "a/b", null, null ).size() );
295
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 @Test
312 public void testRulesBase()
313 {
314
315 assertEquals( "Initial rules list is empty", 0, digester.getRules().rules().size() );
316
317
318 digester.addRule( "a/b/c/d", new TestRule( "a/b/c/d" ) );
319 digester.addRule( "*/d", new TestRule( "*/d" ) );
320 digester.addRule( "*/c/d", new TestRule( "*/c/d" ) );
321
322
323 assertEquals( "Exact match takes precedence 1", 1, digester.getRules().match( null, "a/b/c/d", null, null ).size() );
324 assertEquals( "Exact match takes precedence 2", "a/b/c/d",
325 ( (TestRule) digester.getRules().match( null, "a/b/c/d", null, null ).iterator().next() ).getIdentifier() );
326
327
328 assertEquals( "Wildcard tail matching rule 1", 1, digester.getRules().match( null, "a/b/d", null, null ).size() );
329 assertEquals( "Wildcard tail matching rule 2", "*/d",
330 ( (TestRule) digester.getRules().match( null, "a/b/d", null, null ).iterator().next() ).getIdentifier() );
331
332
333 assertEquals( "Longest tail rule 1", 1, digester.getRules().match( null, "x/c/d", null, null ).size() );
334 assertEquals( "Longest tail rule 2", "*/c/d",
335 ( (TestRule) digester.getRules().match( null, "x/c/d", null, null ).iterator().next() ).getIdentifier() );
336
337 }
338
339
340
341
342 @Test
343 public void testStackMethods()
344 {
345
346 Object value = null;
347
348
349 assertEquals( "New stack is empty", 0, digester.getCount() );
350 value = digester.peek();
351 assertNull( "New stack peek() returns null", value );
352 value = digester.pop();
353 assertNull( "New stack pop() returns null", value );
354
355
356 digester.push( "First Item" );
357 assertEquals( "Pushed one item size", 1, digester.getCount() );
358 value = digester.peek();
359 assertNotNull( "Peeked first item is not null", value );
360 assertEquals( "Peeked first item value", "First Item", value );
361
362 digester.push( "Second Item" );
363 assertEquals( "Pushed two items size", 2, digester.getCount() );
364 value = digester.peek();
365 assertNotNull( "Peeked second item is not null", value );
366 assertEquals( "Peeked second item value", "Second Item", value );
367
368 value = digester.pop();
369 assertEquals( "Popped stack size", 1, digester.getCount() );
370 assertNotNull( "Popped second item is not null", value );
371 assertEquals( "Popped second item value", "Second Item", value );
372 value = digester.peek();
373 assertNotNull( "Remaining item is not null", value );
374 assertEquals( "Remaining item value", "First Item", value );
375 assertEquals( "Remaining stack size", 1, digester.getCount() );
376
377
378 digester.push( "Dummy Item" );
379 digester.clear();
380 assertEquals( "Cleared stack is empty", 0, digester.getCount() );
381 value = digester.peek();
382 assertNull( "Cleared stack peek() returns null", value );
383 value = digester.pop();
384 assertNull( "Cleared stack pop() returns null", value );
385
386 }
387
388 @Test
389 public void testOnceAndOnceOnly()
390 throws Exception
391 {
392
393 class TestConfigureDigester
394 extends Digester
395 {
396 public int called = 0;
397
398 public TestConfigureDigester()
399 {
400 }
401
402 @Override
403 protected void initialize()
404 {
405 called++;
406 }
407 }
408
409 TestConfigureDigester digester = new TestConfigureDigester();
410
411 String xml = "<?xml version='1.0'?><document/>";
412 digester.parse( new StringReader( xml ) );
413
414 assertEquals( "Initialize should be called once and only once", 1, digester.called );
415 }
416
417 @Test
418 public void testBasicSubstitution()
419 throws Exception
420 {
421 class TestSubRule
422 extends Rule
423 {
424 public String body;
425
426 public Attributes attributes;
427
428 @Override
429 public void begin( String namespace, String name, Attributes attributes )
430 {
431 this.attributes = new AttributesImpl( attributes );
432 }
433
434 @Override
435 public void body( String namespace, String name, String text )
436 {
437 this.body = text;
438 }
439 }
440
441 TestSubRule tsr = new TestSubRule();
442 Digester digester = new Digester();
443 digester.addRule( "alpha/beta", tsr );
444
445
446 String xml =
447 "<?xml version='1.0'?><alpha><beta forname='Dirty' surname='Harry'>Do you feel luck punk?</beta></alpha>";
448 InputSource in = new InputSource( new StringReader( xml ) );
449
450 digester.parse( in );
451
452 assertEquals( "Unsubstituted body text", "Do you feel luck punk?", tsr.body );
453 assertEquals( "Unsubstituted number of attributes", 2, tsr.attributes.getLength() );
454 assertEquals( "Unsubstituted forname attribute value", "Dirty", tsr.attributes.getValue( "forname" ) );
455 assertEquals( "Unsubstituted surname attribute value", "Harry", tsr.attributes.getValue( "surname" ) );
456
457 digester.setSubstitutor( new Substitutor()
458 {
459 @Override
460 public Attributes substitute( Attributes attributes )
461 {
462 AttributesImpl results = new AttributesImpl();
463 results.addAttribute( "", "python", "python", "CDATA", "Cleese" );
464 return results;
465 }
466
467 @Override
468 public String substitute( String bodyText )
469 {
470 return "And now for something completely different...";
471 }
472 } );
473
474
475 in = new InputSource( new StringReader( xml ) );
476 digester.parse( in );
477
478 assertEquals( "Substituted body text", "And now for something completely different...", tsr.body );
479 assertEquals( "Substituted number of attributes", 1, tsr.attributes.getLength() );
480 assertEquals( "Substituted python attribute value", "Cleese", tsr.attributes.getValue( "", "python" ) );
481 }
482
483
484 @Test
485 public void testNamedStackPushPeekPop()
486 throws Exception
487 {
488 BigDecimal archimedesAveragePi = new BigDecimal( "3.1418" );
489 String testStackName = "org.apache.commons.digester3.tests.testNamedStackPushPeekPop";
490 Digester digester = new Digester();
491 assertTrue( "Stack starts empty:", digester.isEmpty( testStackName ) );
492 digester.push( testStackName, archimedesAveragePi );
493 assertEquals( "Peeked value:", archimedesAveragePi, digester.peek( testStackName ) );
494 assertEquals( "Popped value:", archimedesAveragePi, digester.pop( testStackName ) );
495 assertTrue( "Stack ends empty:", digester.isEmpty( testStackName ) );
496
497 digester.push( testStackName, "1" );
498 digester.push( testStackName, "2" );
499 digester.push( testStackName, "3" );
500
501 assertEquals( "Peek#1", "1", digester.peek( testStackName, 2 ) );
502 assertEquals( "Peek#2", "2", digester.peek( testStackName, 1 ) );
503 assertEquals( "Peek#3", "3", digester.peek( testStackName, 0 ) );
504 assertEquals( "Peek#3a", "3", digester.peek( testStackName ) );
505
506 try
507 {
508
509 digester.peek( testStackName, 3 );
510 fail( "Peek#4 failed to throw an exception." );
511 }
512 catch ( EmptyStackException ex )
513 {
514
515 }
516
517 try
518 {
519
520 digester.peek( "no.such.stack", 0 );
521 fail( "Peeking a non-existent stack failed to throw an exception." );
522 }
523 catch ( EmptyStackException ex )
524 {
525
526 }
527 }
528
529
530 @Test
531 public void testNamedIndependence()
532 {
533 String testStackOneName = "org.apache.commons.digester3.tests.testNamedIndependenceOne";
534 String testStackTwoName = "org.apache.commons.digester3.tests.testNamedIndependenceTwo";
535 Digester digester = new Digester();
536 digester.push( testStackOneName, "Tweedledum" );
537 digester.push( testStackTwoName, "Tweedledee" );
538 assertEquals( "Popped value one:", "Tweedledum", digester.pop( testStackOneName ) );
539 assertEquals( "Popped value two:", "Tweedledee", digester.pop( testStackTwoName ) );
540 }
541
542
543 @Test
544 public void testPopNamedStackNotPushed()
545 {
546 String testStackName = "org.apache.commons.digester3.tests.testPopNamedStackNotPushed";
547 Digester digester = new Digester();
548 try
549 {
550
551 digester.pop( testStackName );
552 fail( "Expected an EmptyStackException" );
553
554 }
555 catch ( EmptyStackException e )
556 {
557
558 }
559
560 try
561 {
562
563 digester.peek( testStackName );
564 fail( "Expected an EmptyStackException" );
565
566 }
567 catch ( EmptyStackException e )
568 {
569
570 }
571 }
572
573
574 @Test
575 public void testNamedStackIsEmpty()
576 {
577 String testStackName = "org.apache.commons.digester3.tests.testNamedStackIsEmpty";
578 Digester digester = new Digester();
579 assertTrue( "A named stack that has no object pushed onto it yet should be empty",
580 digester.isEmpty( testStackName ) );
581
582 digester.push( testStackName, "Some test value" );
583 assertFalse( "A named stack that has an object pushed onto it should be not empty",
584 digester.isEmpty( testStackName ) );
585
586 digester.peek( testStackName );
587 assertFalse( "Peek should not effect whether the stack is empty", digester.isEmpty( testStackName ) );
588
589 digester.pop( testStackName );
590 assertTrue( "A named stack that has it's last object popped is empty", digester.isEmpty( testStackName ) );
591 }
592
593
594
595
596 @Test
597 public void testGetRoot()
598 throws Exception
599 {
600 Digester digester = new Digester();
601 digester.addRule( "root", new ObjectCreateRule( TestBean.class ) );
602
603 String xml = "<root/>";
604 InputSource in = new InputSource( new StringReader( xml ) );
605
606 digester.parse( in );
607
608 Object root = digester.getRoot();
609 assertNotNull( "root object not retrieved", root );
610 assertTrue( "root object not a TestRule instance", ( root instanceof TestBean ) );
611 }
612
613
614 private static class TrackingStackAction
615 implements StackAction
616 {
617 public ArrayList<String> events = new ArrayList<String>();
618
619 public Object onPush( Digester d, String stackName, Object o )
620 {
621 String msg = "push:" + stackName + ":" + o.toString();
622 events.add( msg );
623
624 String str = o.toString();
625 if ( str.startsWith( "replpush" ) )
626 {
627 return new String( str );
628 }
629 return o;
630 }
631
632 public Object onPop( Digester d, String stackName, Object o )
633 {
634 String msg = "pop:" + stackName + ":" + o.toString();
635 events.add( msg );
636 String str = o.toString();
637 if ( str.startsWith( "replpop" ) )
638 {
639 return new String( str );
640 }
641 return o;
642 }
643 }
644
645
646
647
648 @Test
649 public void testStackAction()
650 {
651 TrackingStackAction action = new TrackingStackAction();
652
653 Object obj1 = new String( "obj1" );
654 Object obj2 = new String( "obj2" );
655 Object obj3 = new String( "replpop.obj3" );
656 Object obj4 = new String( "replpush.obj4" );
657
658 Object obj8 = new String( "obj8" );
659 Object obj9 = new String( "obj9" );
660
661 Digester d = new Digester();
662 d.setStackAction( action );
663
664 assertEquals( 0, action.events.size() );
665 d.push( obj1 );
666 d.push( obj2 );
667 d.push( obj3 );
668 d.push( obj4 );
669
670 assertNotNull( d.peek( 0 ) );
671
672 assertNotSame( obj4, d.peek( 0 ) );
673 assertEquals( obj4, d.peek( 0 ) );
674
675 assertSame( obj3, d.peek( 1 ) );
676 assertSame( obj2, d.peek( 2 ) );
677 assertSame( obj1, d.peek( 3 ) );
678
679 Object obj4a = d.pop();
680 Object obj3a = d.pop();
681 Object obj2a = d.pop();
682 Object obj1a = d.pop();
683
684 assertFalse( obj4 == obj4a );
685 assertEquals( obj4, obj4a );
686 assertFalse( obj3 == obj4a );
687 assertEquals( obj3, obj3a );
688 assertSame( obj2, obj2a );
689 assertSame( obj1, obj1a );
690
691 d.push( "stack1", obj8 );
692 d.push( "stack1", obj9 );
693 Object obj9a = d.pop( "stack1" );
694 Object obj8a = d.pop( "stack1" );
695
696 assertSame( obj8, obj8a );
697 assertSame( obj9, obj9a );
698
699 assertEquals( 12, action.events.size() );
700 assertEquals( "push:null:obj1", action.events.get( 0 ) );
701 assertEquals( "push:null:obj2", action.events.get( 1 ) );
702 assertEquals( "push:null:replpop.obj3", action.events.get( 2 ) );
703 assertEquals( "push:null:replpush.obj4", action.events.get( 3 ) );
704 assertEquals( "pop:null:replpush.obj4", action.events.get( 4 ) );
705 assertEquals( "pop:null:replpop.obj3", action.events.get( 5 ) );
706 assertEquals( "pop:null:obj2", action.events.get( 6 ) );
707 assertEquals( "pop:null:obj1", action.events.get( 7 ) );
708
709 assertEquals( "push:stack1:obj8", action.events.get( 8 ) );
710 assertEquals( "push:stack1:obj9", action.events.get( 9 ) );
711 assertEquals( "pop:stack1:obj9", action.events.get( 10 ) );
712 assertEquals( "pop:stack1:obj8", action.events.get( 11 ) );
713 }
714 }