View Javadoc

1   /* $Id: RuleTestCase.java 1212599 2011-12-09 19:46:42Z simonetripodi $
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one or more
4    * contributor license agreements.  See the NOTICE file distributed with
5    * this work for additional information regarding copyright ownership.
6    * The ASF licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.commons.digester3;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertNotNull;
23  import static org.junit.Assert.assertNull;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.util.ArrayList;
30  
31  import org.apache.commons.digester3.Digester;
32  import org.apache.commons.digester3.ExtendedBaseRules;
33  import org.apache.commons.digester3.RuleSet;
34  import org.junit.After;
35  import org.junit.Before;
36  import org.junit.Test;
37  import org.xml.sax.SAXException;
38  
39  /**
40   * <p>
41   * Test Case for the Digester class. These tests perform parsing of XML documents to exercise the built-in rules.
42   * </p>
43   *
44   * @author Craig R. McClanahan
45   * @author Janek Bogucki
46   */
47  public class RuleTestCase
48  {
49  
50      // ----------------------------------------------------- Instance Variables
51  
52      /**
53       * The digester instance we will be processing.
54       */
55      protected Digester digester = null;
56  
57      // --------------------------------------------------- Overall Test Methods
58  
59      /**
60       * Set up instance variables required by this test case.
61       */
62      @Before
63      public void setUp()
64      {
65  
66          digester = new Digester();
67  
68      }
69  
70      /**
71       * Tear down instance variables required by this test case.
72       */
73      @After
74      public void tearDown()
75      {
76  
77          digester = null;
78  
79      }
80  
81      // ------------------------------------------------ Individual Test Methods
82  
83      /**
84       * Test object creation (and associated property setting) with nothing on the stack, which should cause an
85       * appropriate Employee object to be returned.
86       */
87      @Test
88      public void testObjectCreate1()
89          throws SAXException, IOException
90      {
91  
92          // Configure the digester as required
93          digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
94          digester.addSetProperties( "employee" );
95  
96          // Parse our test input.
97          Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
98  
99          assertNotNull( "Digester returned an object", employee );
100         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
101         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
102 
103     }
104 
105     /**
106      * Test object creation (and associated property setting) with nothing on the stack, which should cause an
107      * appropriate Employee object to be returned. The processing rules will process the nested Address elements as
108      * well, but will not attempt to add them to the Employee.
109      */
110     @Test
111     public void testObjectCreate2()
112         throws SAXException, IOException
113     {
114 
115         // Configure the digester as required
116         digester.addObjectCreate( "employee", Employee.class );
117         digester.addSetProperties( "employee" );
118         digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
119         digester.addSetProperties( "employee/address" );
120 
121         // Parse our test input.
122         Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
123 
124         assertNotNull( "Digester returned an object", employee );
125         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
126         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
127 
128     }
129 
130     /**
131      * Test object creation (and associated property setting) with nothing on the stack, which should cause an
132      * appropriate Employee object to be returned. The processing rules will process the nested Address elements as
133      * well, and will add them to the owning Employee.
134      */
135     @Test
136     public void testObjectCreate3()
137         throws SAXException, IOException
138     {
139 
140         // Configure the digester as required
141         digester.addObjectCreate( "employee", Employee.class );
142         digester.addSetProperties( "employee" );
143         digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
144         digester.addSetProperties( "employee/address" );
145         digester.addSetNext( "employee/address", "addAddress" );
146 
147         // Parse our test input once
148         Object root = null;
149         root = digester.parse( getInputStream( "Test1.xml" ) );
150 
151         validateObjectCreate3( root );
152 
153         // Parse the same input again
154         try
155         {
156             root = digester.parse( getInputStream( "Test1.xml" ) );
157         }
158         catch ( Throwable t )
159         {
160             fail( "Digester threw IOException: " + t );
161         }
162         validateObjectCreate3( root );
163 
164     }
165 
166     /**
167      * Same as testObjectCreate1(), except use individual call method rules to set the properties of the Employee.
168      */
169     @Test
170     public void testObjectCreate4()
171         throws SAXException, IOException
172     {
173 
174         // Configure the digester as required
175         digester.addObjectCreate( "employee", Employee.class );
176         digester.addCallMethod( "employee", "setFirstName", 1 );
177         digester.addCallParam( "employee", 0, "firstName" );
178         digester.addCallMethod( "employee", "setLastName", 1 );
179         digester.addCallParam( "employee", 0, "lastName" );
180 
181         // Parse our test input.
182         Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
183 
184         assertNotNull( "Digester returned an object", employee );
185         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
186         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
187 
188     }
189 
190     /**
191      * Same as testObjectCreate1(), except use individual call method rules to set the properties of the Employee. Bean
192      * data are defined using elements instead of attributes. The purpose is to test CallMethod with a paramCount=0 (ie
193      * the body of the element is the argument of the method).
194      */
195     @Test
196     public void testObjectCreate5()
197         throws SAXException, IOException
198     {
199 
200         // Configure the digester as required
201         digester.addObjectCreate( "employee", Employee.class );
202         digester.addCallMethod( "employee/firstName", "setFirstName", 0 );
203         digester.addCallMethod( "employee/lastName", "setLastName", 0 );
204 
205         // Parse our test input.
206         Employee employee = digester.parse( getInputStream( "Test5.xml" ) );
207 
208         assertNotNull( "Digester returned an object", employee );
209         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
210         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
211 
212     }
213 
214     /**
215      * It should be possible to parse the same input twice, and get trees of objects that are isomorphic but not be
216      * identical object instances.
217      */
218     @Test
219     public void testRepeatedParse()
220         throws SAXException, IOException
221     {
222 
223         // Configure the digester as required
224         digester.addObjectCreate( "employee", Employee.class );
225         digester.addSetProperties( "employee" );
226         digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
227         digester.addSetProperties( "employee/address" );
228         digester.addSetNext( "employee/address", "addAddress" );
229 
230         // Parse our test input the first time
231         Object root1 = null;
232         root1 = digester.parse( getInputStream( "Test1.xml" ) );
233 
234         validateObjectCreate3( root1 );
235 
236         // Parse our test input the second time
237         Object root2 = null;
238         root2 = digester.parse( getInputStream( "Test1.xml" ) );
239 
240         validateObjectCreate3( root2 );
241 
242         // Make sure that it was a different root
243         assertTrue( "Different tree instances were returned", root1 != root2 );
244 
245     }
246 
247     /**
248      * Test object creation (and associated property setting) with nothing on the stack, which should cause an
249      * appropriate Employee object to be returned. The processing rules will process the nested Address elements as
250      * well, but will not attempt to add them to the Employee.
251      */
252     @Test
253     public void testRuleSet1()
254         throws SAXException, IOException
255     {
256 
257         // Configure the digester as required
258         RuleSet rs = new TestRuleSet();
259         digester.addRuleSet( rs );
260 
261         // Parse our test input.
262         Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
263 
264         assertNotNull( "Digester returned an object", employee );
265         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
266         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
267         assertNotNull( "Can retrieve home address", employee.getAddress( "home" ) );
268         assertNotNull( "Can retrieve office address", employee.getAddress( "office" ) );
269 
270     }
271 
272     /**
273      * Same as <code>testRuleSet1</code> except using a single namespace.
274      */
275     @Test
276     public void testRuleSet2()
277         throws SAXException, IOException
278     {
279 
280         // Configure the digester as required
281         digester.setNamespaceAware( true );
282         RuleSet rs = new TestRuleSet( null, "http://commons.apache.org/digester/Foo" );
283         digester.addRuleSet( rs );
284 
285         // Parse our test input.
286         Employee employee = digester.parse( getInputStream( "Test2.xml" ) );
287 
288         assertNotNull( "Digester returned an object", employee );
289         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
290         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
291         assertNotNull( "Can retrieve home address", employee.getAddress( "home" ) );
292         assertNotNull( "Can retrieve office address", employee.getAddress( "office" ) );
293 
294     }
295 
296     /**
297      * Same as <code>testRuleSet2</code> except using a namespace for employee that we should recognize, and a namespace
298      * for address that we should skip.
299      */
300     @Test
301     public void testRuleSet3()
302         throws SAXException, IOException
303     {
304 
305         // Configure the digester as required
306         digester.setNamespaceAware( true );
307         RuleSet rs = new TestRuleSet( null, "http://commons.apache.org/digester/Foo" );
308         digester.addRuleSet( rs );
309 
310         // Parse our test input.
311         Employee employee = digester.parse( getInputStream( "Test3.xml" ) );
312 
313         assertNotNull( "Digester returned an object", employee );
314         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
315         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
316         assertNull( "Can not retrieve home address", employee.getAddress( "home" ) );
317         assertNull( "Can not retrieve office address", employee.getAddress( "office" ) );
318 
319     }
320 
321     /**
322      * Test the two argument version of the SetTopRule rule. This test is based on testObjectCreate3 and should result
323      * in the same tree of objects. Instead of using the SetNextRule rule which results in a method invocation on the
324      * (top-1) (parent) object with the top object (child) as an argument, this test uses the SetTopRule rule which
325      * results in a method invocation on the top object (child) with the top-1 (parent) object as an argument. The three
326      * argument form is tested in <code>testSetTopRule2</code>.
327      */
328     @Test
329     public void testSetTopRule1()
330         throws SAXException, IOException
331     {
332 
333         // Configure the digester as required
334         digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
335         digester.addSetProperties( "employee" );
336         digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
337         digester.addSetProperties( "employee/address" );
338         digester.addSetTop( "employee/address", "setEmployee" );
339 
340         // Parse our test input.
341         Object root = null;
342         root = digester.parse( getInputStream( "Test1.xml" ) );
343         validateObjectCreate3( root );
344 
345     }
346 
347     /**
348      * Same as <code>testSetTopRule1</code> except using the three argument form of the SetTopRule rule.
349      */
350     @Test
351     public void testSetTopRule2()
352         throws SAXException, IOException
353     {
354 
355         // Configure the digester as required
356         digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
357         digester.addSetProperties( "employee" );
358         digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
359         digester.addSetProperties( "employee/address" );
360         digester.addSetTop( "employee/address", "setEmployee", "org.apache.commons.digester3.Employee" );
361 
362         // Parse our test input.
363         Object root = null;
364         root = digester.parse( getInputStream( "Test1.xml" ) );
365 
366         validateObjectCreate3( root );
367 
368     }
369 
370     /**
371      * Test rule addition - this boils down to making sure that digester is set properly on rule addition.
372      */
373     @Test
374     public void testAddRule()
375     {
376         Digester digester = new Digester();
377         TestRule rule = new TestRule( "Test" );
378         digester.addRule( "/root", rule );
379 
380         assertEquals( "Digester is not properly on rule addition.", digester, rule.getDigester() );
381 
382     }
383 
384     @Test
385     public void testSetNext()
386         throws SAXException, IOException
387     {
388         Digester digester = new Digester();
389         digester.setRules( new ExtendedBaseRules() );
390         digester.setValidating( false );
391 
392         digester.addObjectCreate( "!*/b", BetaBean.class );
393         digester.addObjectCreate( "!*/a", AlphaBean.class );
394         digester.addObjectCreate( "root", ArrayList.class );
395         digester.addSetProperties( "!*" );
396         digester.addSetNext( "!*/b/?", "setChild" );
397         digester.addSetNext( "!*/a/?", "setChild" );
398         digester.addSetNext( "!root/?", "add" );
399         ArrayList<?> root = digester.parse( getInputStream( "Test4.xml" ) );
400 
401         assertEquals( "Wrong array size", 2, root.size() );
402         AlphaBean one = (AlphaBean) root.get( 0 );
403         assertTrue( one.getChild() instanceof BetaBean );
404         BetaBean two = (BetaBean) one.getChild();
405         assertEquals( "Wrong name (1)", two.getName(), "TWO" );
406         assertTrue( two.getChild() instanceof AlphaBean );
407         AlphaBean three = (AlphaBean) two.getChild();
408         assertEquals( "Wrong name (2)", three.getName(), "THREE" );
409         BetaBean four = (BetaBean) root.get( 1 );
410         assertEquals( "Wrong name (3)", four.getName(), "FOUR" );
411         assertTrue( four.getChild() instanceof BetaBean );
412         BetaBean five = (BetaBean) four.getChild();
413         assertEquals( "Wrong name (4)", five.getName(), "FIVE" );
414 
415     }
416 
417     @Test
418     public void testSetTop()
419         throws SAXException, IOException
420     {
421         Digester digester = new Digester();
422         digester.setRules( new ExtendedBaseRules() );
423         digester.setValidating( false );
424 
425         digester.addObjectCreate( "!*/b", BetaBean.class );
426         digester.addObjectCreate( "!*/a", AlphaBean.class );
427         digester.addObjectCreate( "root", ArrayList.class );
428         digester.addSetProperties( "!*" );
429         digester.addSetTop( "!*/b/?", "setParent" );
430         digester.addSetTop( "!*/a/?", "setParent" );
431         digester.addSetRoot( "!*/a", "add" );
432         digester.addSetRoot( "!*/b", "add" );
433         ArrayList<?> root = digester.parse( getInputStream( "Test4.xml" ) );
434 
435         assertEquals( "Wrong array size", 5, root.size() );
436 
437         // note that the array is in popped order (rather than pushed)
438 
439         Object obj = root.get( 1 );
440         assertTrue( "TWO should be a BetaBean", obj instanceof BetaBean );
441         BetaBean two = (BetaBean) obj;
442         assertNotNull( "Two's parent should not be null", two.getParent() );
443         assertEquals( "Wrong name (1)", "TWO", two.getName() );
444         assertEquals( "Wrong name (2)", "ONE", two.getParent().getName() );
445 
446         obj = root.get( 0 );
447         assertTrue( "THREE should be an AlphaBean", obj instanceof AlphaBean );
448         AlphaBean three = (AlphaBean) obj;
449         assertNotNull( "Three's parent should not be null", three.getParent() );
450         assertEquals( "Wrong name (3)", "THREE", three.getName() );
451         assertEquals( "Wrong name (4)", "TWO", three.getParent().getName() );
452 
453         obj = root.get( 3 );
454         assertTrue( "FIVE should be a BetaBean", obj instanceof BetaBean );
455         BetaBean five = (BetaBean) obj;
456         assertNotNull( "Five's parent should not be null", five.getParent() );
457         assertEquals( "Wrong name (5)", "FIVE", five.getName() );
458         assertEquals( "Wrong name (6)", "FOUR", five.getParent().getName() );
459 
460     }
461 
462     /**
463      */
464     @Test
465     public void testSetCustomProperties()
466         throws SAXException, IOException
467     {
468 
469         Digester digester = new Digester();
470 
471         digester.setValidating( false );
472 
473         digester.addObjectCreate( "toplevel", ArrayList.class );
474         digester.addObjectCreate( "toplevel/one", Address.class );
475         digester.addSetNext( "toplevel/one", "add" );
476         digester.addObjectCreate( "toplevel/two", Address.class );
477         digester.addSetNext( "toplevel/two", "add" );
478         digester.addObjectCreate( "toplevel/three", Address.class );
479         digester.addSetNext( "toplevel/three", "add" );
480         digester.addObjectCreate( "toplevel/four", Address.class );
481         digester.addSetNext( "toplevel/four", "add" );
482         digester.addSetProperties( "toplevel/one" );
483         digester.addSetProperties( "toplevel/two", new String[] { "alt-street", "alt-city", "alt-state" },
484                                    new String[] { "street", "city", "state" } );
485         digester.addSetProperties( "toplevel/three", new String[] { "aCity", "state" }, new String[] { "city" } );
486         digester.addSetProperties( "toplevel/four", "alt-city", "city" );
487 
488         ArrayList<?> root = digester.parse( getInputStream( "Test7.xml" ) );
489 
490         assertEquals( "Wrong array size", 4, root.size() );
491 
492         // note that the array is in popped order (rather than pushed)
493 
494         Object obj = root.get( 0 );
495         assertTrue( "(1) Should be an Address ", obj instanceof Address );
496         Address addressOne = (Address) obj;
497         assertEquals( "(1) Street attribute", "New Street", addressOne.getStreet() );
498         assertEquals( "(1) City attribute", "Las Vegas", addressOne.getCity() );
499         assertEquals( "(1) State attribute", "Nevada", addressOne.getState() );
500 
501         obj = root.get( 1 );
502         assertTrue( "(2) Should be an Address ", obj instanceof Address );
503         Address addressTwo = (Address) obj;
504         assertEquals( "(2) Street attribute", "Old Street", addressTwo.getStreet() );
505         assertEquals( "(2) City attribute", "Portland", addressTwo.getCity() );
506         assertEquals( "(2) State attribute", "Oregon", addressTwo.getState() );
507 
508         obj = root.get( 2 );
509         assertTrue( "(3) Should be an Address ", obj instanceof Address );
510         Address addressThree = (Address) obj;
511         assertEquals( "(3) Street attribute", "4th Street", addressThree.getStreet() );
512         assertEquals( "(3) City attribute", "Dayton", addressThree.getCity() );
513         assertEquals( "(3) State attribute", "US", addressThree.getState() );
514 
515         obj = root.get( 3 );
516         assertTrue( "(4) Should be an Address ", obj instanceof Address );
517         Address addressFour = (Address) obj;
518         assertEquals( "(4) Street attribute", "6th Street", addressFour.getStreet() );
519         assertEquals( "(4) City attribute", "Cleveland", addressFour.getCity() );
520         assertEquals( "(4) State attribute", "Ohio", addressFour.getState() );
521 
522     }
523 
524     // ------------------------------------------------ Utility Support Methods
525 
526     /**
527      * Return an appropriate InputStream for the specified test file (which must be inside our current package.
528      *
529      * @param name Name of the test file we want
530      * @exception IOException if an input/output error occurs
531      */
532     protected InputStream getInputStream( String name )
533         throws IOException
534     {
535 
536         return ( this.getClass().getResourceAsStream( "/org/apache/commons/digester3/" + name ) );
537 
538     }
539 
540     /**
541      * Validate the assertions for ObjectCreateRule3.
542      *
543      * @param root Root object returned by <code>digester.parse()</code>
544      */
545     protected void validateObjectCreate3( Object root )
546     {
547 
548         // Validate the retrieved Employee
549         assertNotNull( "Digester returned an object", root );
550         assertTrue( "Digester returned an Employee", root instanceof Employee );
551         Employee employee = (Employee) root;
552         assertEquals( "First name is correct", "First Name", employee.getFirstName() );
553         assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
554 
555         // Validate the corresponding "home" Address
556         Address home = employee.getAddress( "home" );
557         assertNotNull( "Retrieved home address", home );
558         assertEquals( "Home street", "Home Street", home.getStreet() );
559         assertEquals( "Home city", "Home City", home.getCity() );
560         assertEquals( "Home state", "HS", home.getState() );
561         assertEquals( "Home zip", "HmZip", home.getZipCode() );
562 
563         // Validate the corresponding "office" Address
564         Address office = employee.getAddress( "office" );
565         assertNotNull( "Retrieved office address", office );
566         assertEquals( "Office street", "Office Street", office.getStreet() );
567         assertEquals( "Office city", "Office City", office.getCity() );
568         assertEquals( "Office state", "OS", office.getState() );
569         assertEquals( "Office zip", "OfZip", office.getZipCode() );
570 
571     }
572 
573 }