001/* $Id: RuleTestCase.java 1212599 2011-12-09 19:46:42Z simonetripodi $ 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.commons.digester3; 020 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertNull; 024import static org.junit.Assert.assertTrue; 025import static org.junit.Assert.fail; 026 027import java.io.IOException; 028import java.io.InputStream; 029import java.util.ArrayList; 030 031import org.apache.commons.digester3.Digester; 032import org.apache.commons.digester3.ExtendedBaseRules; 033import org.apache.commons.digester3.RuleSet; 034import org.junit.After; 035import org.junit.Before; 036import org.junit.Test; 037import org.xml.sax.SAXException; 038 039/** 040 * <p> 041 * Test Case for the Digester class. These tests perform parsing of XML documents to exercise the built-in rules. 042 * </p> 043 * 044 * @author Craig R. McClanahan 045 * @author Janek Bogucki 046 */ 047public class RuleTestCase 048{ 049 050 // ----------------------------------------------------- Instance Variables 051 052 /** 053 * The digester instance we will be processing. 054 */ 055 protected Digester digester = null; 056 057 // --------------------------------------------------- Overall Test Methods 058 059 /** 060 * Set up instance variables required by this test case. 061 */ 062 @Before 063 public void setUp() 064 { 065 066 digester = new Digester(); 067 068 } 069 070 /** 071 * Tear down instance variables required by this test case. 072 */ 073 @After 074 public void tearDown() 075 { 076 077 digester = null; 078 079 } 080 081 // ------------------------------------------------ Individual Test Methods 082 083 /** 084 * Test object creation (and associated property setting) with nothing on the stack, which should cause an 085 * appropriate Employee object to be returned. 086 */ 087 @Test 088 public void testObjectCreate1() 089 throws SAXException, IOException 090 { 091 092 // Configure the digester as required 093 digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" ); 094 digester.addSetProperties( "employee" ); 095 096 // Parse our test input. 097 Employee employee = digester.parse( getInputStream( "Test1.xml" ) ); 098 099 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}