blob: b56c008a0e61f7d40f05aa7090d7d3235103786a [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.digester3;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.ExtendedBaseRules;
import org.apache.commons.digester3.RuleSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
/**
* <p>
* Test Case for the Digester class. These tests perform parsing of XML documents to exercise the built-in rules.
* </p>
*
* @author Craig R. McClanahan
* @author Janek Bogucki
*/
public class RuleTestCase
{
// ----------------------------------------------------- Instance Variables
/**
* The digester instance we will be processing.
*/
protected Digester digester = null;
// --------------------------------------------------- Overall Test Methods
/**
* Set up instance variables required by this test case.
*/
@Before
public void setUp()
{
digester = new Digester();
}
/**
* Tear down instance variables required by this test case.
*/
@After
public void tearDown()
{
digester = null;
}
// ------------------------------------------------ Individual Test Methods
/**
* Test object creation (and associated property setting) with nothing on the stack, which should cause an
* appropriate Employee object to be returned.
*/
@Test
public void testObjectCreate1()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
digester.addSetProperties( "employee" );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
}
/**
* Test object creation (and associated property setting) with nothing on the stack, which should cause an
* appropriate Employee object to be returned. The processing rules will process the nested Address elements as
* well, but will not attempt to add them to the Employee.
*/
@Test
public void testObjectCreate2()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", Employee.class );
digester.addSetProperties( "employee" );
digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
digester.addSetProperties( "employee/address" );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
}
/**
* Test object creation (and associated property setting) with nothing on the stack, which should cause an
* appropriate Employee object to be returned. The processing rules will process the nested Address elements as
* well, and will add them to the owning Employee.
*/
@Test
public void testObjectCreate3()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", Employee.class );
digester.addSetProperties( "employee" );
digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
digester.addSetProperties( "employee/address" );
digester.addSetNext( "employee/address", "addAddress" );
// Parse our test input once
Object root = null;
root = digester.parse( getInputStream( "Test1.xml" ) );
validateObjectCreate3( root );
// Parse the same input again
try
{
root = digester.parse( getInputStream( "Test1.xml" ) );
}
catch ( Throwable t )
{
fail( "Digester threw IOException: " + t );
}
validateObjectCreate3( root );
}
/**
* Same as testObjectCreate1(), except use individual call method rules to set the properties of the Employee.
*/
@Test
public void testObjectCreate4()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", Employee.class );
digester.addCallMethod( "employee", "setFirstName", 1 );
digester.addCallParam( "employee", 0, "firstName" );
digester.addCallMethod( "employee", "setLastName", 1 );
digester.addCallParam( "employee", 0, "lastName" );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
}
/**
* Same as testObjectCreate1(), except use individual call method rules to set the properties of the Employee. Bean
* data are defined using elements instead of attributes. The purpose is to test CallMethod with a paramCount=0 (ie
* the body of the element is the argument of the method).
*/
@Test
public void testObjectCreate5()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", Employee.class );
digester.addCallMethod( "employee/firstName", "setFirstName", 0 );
digester.addCallMethod( "employee/lastName", "setLastName", 0 );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test5.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
}
/**
* It should be possible to parse the same input twice, and get trees of objects that are isomorphic but not be
* identical object instances.
*/
@Test
public void testRepeatedParse()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", Employee.class );
digester.addSetProperties( "employee" );
digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
digester.addSetProperties( "employee/address" );
digester.addSetNext( "employee/address", "addAddress" );
// Parse our test input the first time
Object root1 = null;
root1 = digester.parse( getInputStream( "Test1.xml" ) );
validateObjectCreate3( root1 );
// Parse our test input the second time
Object root2 = null;
root2 = digester.parse( getInputStream( "Test1.xml" ) );
validateObjectCreate3( root2 );
// Make sure that it was a different root
assertTrue( "Different tree instances were returned", root1 != root2 );
}
/**
* Test object creation (and associated property setting) with nothing on the stack, which should cause an
* appropriate Employee object to be returned. The processing rules will process the nested Address elements as
* well, but will not attempt to add them to the Employee.
*/
@Test
public void testRuleSet1()
throws SAXException, IOException
{
// Configure the digester as required
RuleSet rs = new TestRuleSet();
digester.addRuleSet( rs );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test1.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
assertNotNull( "Can retrieve home address", employee.getAddress( "home" ) );
assertNotNull( "Can retrieve office address", employee.getAddress( "office" ) );
}
/**
* Same as <code>testRuleSet1</code> except using a single namespace.
*/
@Test
public void testRuleSet2()
throws SAXException, IOException
{
// Configure the digester as required
digester.setNamespaceAware( true );
RuleSet rs = new TestRuleSet( null, "http://commons.apache.org/digester/Foo" );
digester.addRuleSet( rs );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test2.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
assertNotNull( "Can retrieve home address", employee.getAddress( "home" ) );
assertNotNull( "Can retrieve office address", employee.getAddress( "office" ) );
}
/**
* Same as <code>testRuleSet2</code> except using a namespace for employee that we should recognize, and a namespace
* for address that we should skip.
*/
@Test
public void testRuleSet3()
throws SAXException, IOException
{
// Configure the digester as required
digester.setNamespaceAware( true );
RuleSet rs = new TestRuleSet( null, "http://commons.apache.org/digester/Foo" );
digester.addRuleSet( rs );
// Parse our test input.
Employee employee = digester.parse( getInputStream( "Test3.xml" ) );
assertNotNull( "Digester returned an object", employee );
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
assertNull( "Can not retrieve home address", employee.getAddress( "home" ) );
assertNull( "Can not retrieve office address", employee.getAddress( "office" ) );
}
/**
* Test the two argument version of the SetTopRule rule. This test is based on testObjectCreate3 and should result
* in the same tree of objects. Instead of using the SetNextRule rule which results in a method invocation on the
* (top-1) (parent) object with the top object (child) as an argument, this test uses the SetTopRule rule which
* results in a method invocation on the top object (child) with the top-1 (parent) object as an argument. The three
* argument form is tested in <code>testSetTopRule2</code>.
*/
@Test
public void testSetTopRule1()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
digester.addSetProperties( "employee" );
digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
digester.addSetProperties( "employee/address" );
digester.addSetTop( "employee/address", "setEmployee" );
// Parse our test input.
Object root = null;
root = digester.parse( getInputStream( "Test1.xml" ) );
validateObjectCreate3( root );
}
/**
* Same as <code>testSetTopRule1</code> except using the three argument form of the SetTopRule rule.
*/
@Test
public void testSetTopRule2()
throws SAXException, IOException
{
// Configure the digester as required
digester.addObjectCreate( "employee", "org.apache.commons.digester3.Employee" );
digester.addSetProperties( "employee" );
digester.addObjectCreate( "employee/address", "org.apache.commons.digester3.Address" );
digester.addSetProperties( "employee/address" );
digester.addSetTop( "employee/address", "setEmployee", "org.apache.commons.digester3.Employee" );
// Parse our test input.
Object root = null;
root = digester.parse( getInputStream( "Test1.xml" ) );
validateObjectCreate3( root );
}
/**
* Test rule addition - this boils down to making sure that digester is set properly on rule addition.
*/
@Test
public void testAddRule()
{
Digester digester = new Digester();
TestRule rule = new TestRule( "Test" );
digester.addRule( "/root", rule );
assertEquals( "Digester is not properly on rule addition.", digester, rule.getDigester() );
}
@Test
public void testSetNext()
throws SAXException, IOException
{
Digester digester = new Digester();
digester.setRules( new ExtendedBaseRules() );
digester.setValidating( false );
digester.addObjectCreate( "!*/b", BetaBean.class );
digester.addObjectCreate( "!*/a", AlphaBean.class );
digester.addObjectCreate( "root", ArrayList.class );
digester.addSetProperties( "!*" );
digester.addSetNext( "!*/b/?", "setChild" );
digester.addSetNext( "!*/a/?", "setChild" );
digester.addSetNext( "!root/?", "add" );
ArrayList<?> root = digester.parse( getInputStream( "Test4.xml" ) );
assertEquals( "Wrong array size", 2, root.size() );
AlphaBean one = (AlphaBean) root.get( 0 );
assertTrue( one.getChild() instanceof BetaBean );
BetaBean two = (BetaBean) one.getChild();
assertEquals( "Wrong name (1)", two.getName(), "TWO" );
assertTrue( two.getChild() instanceof AlphaBean );
AlphaBean three = (AlphaBean) two.getChild();
assertEquals( "Wrong name (2)", three.getName(), "THREE" );
BetaBean four = (BetaBean) root.get( 1 );
assertEquals( "Wrong name (3)", four.getName(), "FOUR" );
assertTrue( four.getChild() instanceof BetaBean );
BetaBean five = (BetaBean) four.getChild();
assertEquals( "Wrong name (4)", five.getName(), "FIVE" );
}
@Test
public void testSetTop()
throws SAXException, IOException
{
Digester digester = new Digester();
digester.setRules( new ExtendedBaseRules() );
digester.setValidating( false );
digester.addObjectCreate( "!*/b", BetaBean.class );
digester.addObjectCreate( "!*/a", AlphaBean.class );
digester.addObjectCreate( "root", ArrayList.class );
digester.addSetProperties( "!*" );
digester.addSetTop( "!*/b/?", "setParent" );
digester.addSetTop( "!*/a/?", "setParent" );
digester.addSetRoot( "!*/a", "add" );
digester.addSetRoot( "!*/b", "add" );
ArrayList<?> root = digester.parse( getInputStream( "Test4.xml" ) );
assertEquals( "Wrong array size", 5, root.size() );
// note that the array is in popped order (rather than pushed)
Object obj = root.get( 1 );
assertTrue( "TWO should be a BetaBean", obj instanceof BetaBean );
BetaBean two = (BetaBean) obj;
assertNotNull( "Two's parent should not be null", two.getParent() );
assertEquals( "Wrong name (1)", "TWO", two.getName() );
assertEquals( "Wrong name (2)", "ONE", two.getParent().getName() );
obj = root.get( 0 );
assertTrue( "THREE should be an AlphaBean", obj instanceof AlphaBean );
AlphaBean three = (AlphaBean) obj;
assertNotNull( "Three's parent should not be null", three.getParent() );
assertEquals( "Wrong name (3)", "THREE", three.getName() );
assertEquals( "Wrong name (4)", "TWO", three.getParent().getName() );
obj = root.get( 3 );
assertTrue( "FIVE should be a BetaBean", obj instanceof BetaBean );
BetaBean five = (BetaBean) obj;
assertNotNull( "Five's parent should not be null", five.getParent() );
assertEquals( "Wrong name (5)", "FIVE", five.getName() );
assertEquals( "Wrong name (6)", "FOUR", five.getParent().getName() );
}
/**
*/
@Test
public void testSetCustomProperties()
throws SAXException, IOException
{
Digester digester = new Digester();
digester.setValidating( false );
digester.addObjectCreate( "toplevel", ArrayList.class );
digester.addObjectCreate( "toplevel/one", Address.class );
digester.addSetNext( "toplevel/one", "add" );
digester.addObjectCreate( "toplevel/two", Address.class );
digester.addSetNext( "toplevel/two", "add" );
digester.addObjectCreate( "toplevel/three", Address.class );
digester.addSetNext( "toplevel/three", "add" );
digester.addObjectCreate( "toplevel/four", Address.class );
digester.addSetNext( "toplevel/four", "add" );
digester.addSetProperties( "toplevel/one" );
digester.addSetProperties( "toplevel/two", new String[] { "alt-street", "alt-city", "alt-state" },
new String[] { "street", "city", "state" } );
digester.addSetProperties( "toplevel/three", new String[] { "aCity", "state" }, new String[] { "city" } );
digester.addSetProperties( "toplevel/four", "alt-city", "city" );
ArrayList<?> root = digester.parse( getInputStream( "Test7.xml" ) );
assertEquals( "Wrong array size", 4, root.size() );
// note that the array is in popped order (rather than pushed)
Object obj = root.get( 0 );
assertTrue( "(1) Should be an Address ", obj instanceof Address );
Address addressOne = (Address) obj;
assertEquals( "(1) Street attribute", "New Street", addressOne.getStreet() );
assertEquals( "(1) City attribute", "Las Vegas", addressOne.getCity() );
assertEquals( "(1) State attribute", "Nevada", addressOne.getState() );
obj = root.get( 1 );
assertTrue( "(2) Should be an Address ", obj instanceof Address );
Address addressTwo = (Address) obj;
assertEquals( "(2) Street attribute", "Old Street", addressTwo.getStreet() );
assertEquals( "(2) City attribute", "Portland", addressTwo.getCity() );
assertEquals( "(2) State attribute", "Oregon", addressTwo.getState() );
obj = root.get( 2 );
assertTrue( "(3) Should be an Address ", obj instanceof Address );
Address addressThree = (Address) obj;
assertEquals( "(3) Street attribute", "4th Street", addressThree.getStreet() );
assertEquals( "(3) City attribute", "Dayton", addressThree.getCity() );
assertEquals( "(3) State attribute", "US", addressThree.getState() );
obj = root.get( 3 );
assertTrue( "(4) Should be an Address ", obj instanceof Address );
Address addressFour = (Address) obj;
assertEquals( "(4) Street attribute", "6th Street", addressFour.getStreet() );
assertEquals( "(4) City attribute", "Cleveland", addressFour.getCity() );
assertEquals( "(4) State attribute", "Ohio", addressFour.getState() );
}
// ------------------------------------------------ Utility Support Methods
/**
* Return an appropriate InputStream for the specified test file (which must be inside our current package.
*
* @param name Name of the test file we want
* @throws IOException if an input/output error occurs
*/
protected InputStream getInputStream( String name )
throws IOException
{
return ( this.getClass().getResourceAsStream( "/org/apache/commons/digester3/" + name ) );
}
/**
* Validate the assertions for ObjectCreateRule3.
*
* @param root Root object returned by <code>digester.parse()</code>
*/
protected void validateObjectCreate3( Object root )
{
// Validate the retrieved Employee
assertNotNull( "Digester returned an object", root );
assertTrue( "Digester returned an Employee", root instanceof Employee );
Employee employee = (Employee) root;
assertEquals( "First name is correct", "First Name", employee.getFirstName() );
assertEquals( "Last name is correct", "Last Name", employee.getLastName() );
// Validate the corresponding "home" Address
Address home = employee.getAddress( "home" );
assertNotNull( "Retrieved home address", home );
assertEquals( "Home street", "Home Street", home.getStreet() );
assertEquals( "Home city", "Home City", home.getCity() );
assertEquals( "Home state", "HS", home.getState() );
assertEquals( "Home zip", "HmZip", home.getZipCode() );
// Validate the corresponding "office" Address
Address office = employee.getAddress( "office" );
assertNotNull( "Retrieved office address", office );
assertEquals( "Office street", "Office Street", office.getStreet() );
assertEquals( "Office city", "Office City", office.getCity() );
assertEquals( "Office state", "OS", office.getState() );
assertEquals( "Office zip", "OfZip", office.getZipCode() );
}
}