| /* $Id: DigesterTestCase.java,v 1.21 2004/06/08 08:26:47 skitching Exp $ |
| * |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed 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.digester; |
| |
| import java.math.BigDecimal; |
| import java.net.URL; |
| import java.io.StringReader; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.EmptyStackException; |
| |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| import junit.framework.TestSuite; |
| |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.helpers.AttributesImpl; |
| import org.xml.sax.InputSource; |
| |
| |
| /** |
| * <p>Test Case for the Digester class. These tests exercise the individual |
| * methods of a Digester, but do not attempt to process complete documents. |
| * </p> |
| * |
| * @author Craig R. McClanahan |
| * @version $Revision: 1.21 $ $Date: 2004/06/08 08:26:47 $ |
| */ |
| |
| public class DigesterTestCase extends TestCase { |
| |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| |
| /** |
| * The digester instance we will be processing. |
| */ |
| protected Digester digester = null; |
| |
| |
| /** |
| * The set of public identifiers, and corresponding resource names, |
| * for the versions of the DTDs that we know about. There |
| * <strong>MUST</strong> be an even number of Strings in this array. |
| */ |
| protected static final String registrations[] = { |
| "-//Netscape Communications//DTD RSS 0.9//EN", |
| "/org/apache/commons/digester/rss/rss-0.9.dtd", |
| "-//Netscape Communications//DTD RSS 0.91//EN", |
| "/org/apache/commons/digester/rss/rss-0.91.dtd", |
| }; |
| |
| |
| // ----------------------------------------------------------- Constructors |
| |
| |
| /** |
| * Construct a new instance of this test case. |
| * |
| * @param name Name of the test case |
| */ |
| public DigesterTestCase(String name) { |
| |
| super(name); |
| |
| } |
| |
| |
| // -------------------------------------------------- Overall Test Methods |
| |
| |
| /** |
| * Set up instance variables required by this test case. |
| */ |
| public void setUp() { |
| |
| digester = new Digester(); |
| digester.setRules(new RulesBase()); |
| |
| } |
| |
| |
| /** |
| * Return the tests included in this test suite. |
| */ |
| public static Test suite() { |
| |
| return (new TestSuite(DigesterTestCase.class)); |
| |
| } |
| |
| |
| /** |
| * Tear down instance variables required by this test case. |
| */ |
| public void tearDown() { |
| |
| digester = null; |
| |
| } |
| |
| |
| |
| // ------------------------------------------------ Individual Test Methods |
| |
| |
| /** |
| * Test the basic property getters and setters. |
| */ |
| public void testProperties() { |
| |
| assertNull("Initial error handler is null", |
| digester.getErrorHandler()); |
| digester.setErrorHandler((ErrorHandler) digester); |
| assertTrue("Set error handler is digester", |
| digester.getErrorHandler() == digester); |
| digester.setErrorHandler(null); |
| assertNull("Reset error handler is null", |
| digester.getErrorHandler()); |
| |
| assertTrue("Initial namespace aware is false", |
| !digester.getNamespaceAware()); |
| digester.setNamespaceAware(true); |
| assertTrue("Set namespace aware is true", |
| digester.getNamespaceAware()); |
| digester.setNamespaceAware(false); |
| assertTrue("Reset namespace aware is false", |
| !digester.getNamespaceAware()); |
| |
| assertTrue("Initial validating is false", |
| !digester.getValidating()); |
| digester.setValidating(true); |
| assertTrue("Set validating is true", |
| digester.getValidating()); |
| digester.setValidating(false); |
| assertTrue("Reset validating is false", |
| !digester.getValidating()); |
| |
| } |
| |
| |
| /** |
| * Test registration of URLs for specified public identifiers. |
| */ |
| public void testRegistrations() { |
| |
| Map map = digester.getRegistrations(); |
| assertEquals("Initially zero registrations", 0, map.size()); |
| int n = 0; |
| for (int i = 0; i < registrations.length; i += 2) { |
| URL url = this.getClass().getResource(registrations[i + 1]); |
| if (url != null) { |
| digester.register(registrations[i], url.toString()); |
| n++; |
| } |
| } |
| map = digester.getRegistrations(); |
| assertEquals("Registered two URLs", n, map.size()); |
| |
| int count[] = new int[n]; |
| for (int i = 0; i < n; i++) |
| count[i] = 0; |
| Iterator keys = map.keySet().iterator(); |
| while (keys.hasNext()) { |
| String key = (String) keys.next(); |
| for (int i = 0; i < n; i++) { |
| if (key.equals(registrations[i * 2])) { |
| count[i]++; |
| break; |
| } |
| } |
| } |
| for (int i = 0; i < n; i++) |
| assertEquals("Count for key " + registrations[i * 2], |
| 1, count[i]); |
| |
| } |
| |
| |
| /** |
| * Basic test for rule creation and matching. |
| */ |
| public void testRules() { |
| |
| List list = null; |
| |
| assertEquals("Initial rules list is empty", |
| 0, digester.getRules().match(null, "a").size()); |
| digester.addSetProperties("a"); |
| assertEquals("Add a matching rule", |
| 1, digester.getRules().match(null, "a").size()); |
| digester.addSetProperties("b"); |
| assertEquals("Add a non-matching rule", |
| 1, digester.getRules().match(null, "a").size()); |
| digester.addSetProperties("a/b"); |
| assertEquals("Add a non-matching nested rule", |
| 1, digester.getRules().match(null, "a").size()); |
| digester.addSetProperties("a/b"); |
| assertEquals("Add a second matching rule", |
| 2, digester.getRules().match(null, "a/b").size()); |
| |
| } |
| |
| |
| /** |
| * <p>Test matching rules in {@link RulesBase}.</p> |
| * |
| * <p>Tests:</p> |
| * <ul> |
| * <li>exact match</li> |
| * <li>tail match</li> |
| * <li>longest pattern rule</li> |
| * </ul> |
| */ |
| public void testRulesBase() { |
| |
| assertEquals("Initial rules list is empty", |
| 0, digester.getRules().rules().size()); |
| |
| // We're going to set up |
| digester.addRule("a/b/c/d", new TestRule("a/b/c/d")); |
| digester.addRule("*/d", new TestRule("*/d")); |
| digester.addRule("*/c/d", new TestRule("*/c/d")); |
| |
| // Test exact match |
| assertEquals("Exact match takes precedence 1", |
| 1, digester.getRules().match(null, "a/b/c/d").size()); |
| assertEquals("Exact match takes precedence 2", |
| "a/b/c/d", |
| ((TestRule) digester.getRules().match(null, "a/b/c/d").iterator().next()).getIdentifier()); |
| |
| // Test wildcard tail matching |
| assertEquals("Wildcard tail matching rule 1", |
| 1, digester.getRules().match(null, "a/b/d").size()); |
| assertEquals("Wildcard tail matching rule 2", |
| "*/d", |
| ((TestRule) digester.getRules().match(null, "a/b/d").iterator().next()).getIdentifier()); |
| |
| // Test the longest matching pattern rule |
| assertEquals("Longest tail rule 1", |
| 1, digester.getRules().match(null, "x/c/d").size()); |
| assertEquals("Longest tail rule 2", |
| "*/c/d", |
| ((TestRule) digester.getRules().match(null, "x/c/d").iterator().next()).getIdentifier()); |
| |
| } |
| |
| |
| /** |
| * Test the basic stack mechanisms. |
| */ |
| public void testStackMethods() { |
| |
| Object value = null; |
| |
| // New stack must be empty |
| assertEquals("New stack is empty", 0, digester.getCount()); |
| value = digester.peek(); |
| assertNull("New stack peek() returns null", value); |
| value = digester.pop(); |
| assertNull("New stack pop() returns null", value); |
| |
| // Test pushing and popping activities |
| digester.push("First Item"); |
| assertEquals("Pushed one item size", 1, digester.getCount()); |
| value = digester.peek(); |
| assertNotNull("Peeked first item is not null", value); |
| assertEquals("Peeked first item value", "First Item", (String) value); |
| |
| digester.push("Second Item"); |
| assertEquals("Pushed two items size", 2, digester.getCount()); |
| value = digester.peek(); |
| assertNotNull("Peeked second item is not null", value); |
| assertEquals("Peeked second item value", "Second Item", (String) value); |
| |
| value = digester.pop(); |
| assertEquals("Popped stack size", 1, digester.getCount()); |
| assertNotNull("Popped second item is not null", value); |
| assertEquals("Popped second item value", "Second Item", (String) value); |
| value = digester.peek(); |
| assertNotNull("Remaining item is not null", value); |
| assertEquals("Remaining item value", "First Item", (String) value); |
| assertEquals("Remaining stack size", 1, digester.getCount()); |
| |
| // Cleared stack is empty |
| digester.push("Dummy Item"); |
| digester.clear(); |
| assertEquals("Cleared stack is empty", 0, digester.getCount()); |
| value = digester.peek(); |
| assertNull("Cleared stack peek() returns null", value); |
| value = digester.pop(); |
| assertNull("Cleared stack pop() returns null", value); |
| |
| } |
| |
| public void testOnceAndOnceOnly() throws Exception { |
| |
| class TestConfigureDigester extends Digester { |
| public int called=0; |
| public TestConfigureDigester() {} |
| |
| protected void initialize() { |
| called++; |
| } |
| } |
| |
| TestConfigureDigester digester = new TestConfigureDigester(); |
| |
| String xml = "<?xml version='1.0'?><document/>"; |
| digester.parse(new StringReader(xml)); |
| |
| assertEquals("Initialize should be called once and only once", 1, digester.called); |
| } |
| |
| public void testBasicSubstitution() throws Exception { |
| class TestSubRule extends Rule { |
| public String body; |
| public Attributes attributes; |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| this.attributes = new AttributesImpl(attributes); |
| } |
| |
| public void body(String namespace, String name, String text) { |
| this.body = text; |
| } |
| } |
| |
| TestSubRule tsr = new TestSubRule(); |
| Digester digester = new Digester(); |
| digester.addRule("alpha/beta", tsr); |
| |
| // it's not easy to transform dirty harry into the mighty circus - but let's give it a try |
| String xml = "<?xml version='1.0'?><alpha><beta forname='Dirty' surname='Harry'>Do you feel luck punk?</beta></alpha>"; |
| InputSource in = new InputSource(new StringReader(xml)); |
| |
| digester.parse(in); |
| |
| assertEquals("Unsubstituted body text", "Do you feel luck punk?", tsr.body); |
| assertEquals("Unsubstituted number of attributes", 2, tsr.attributes.getLength()); |
| assertEquals("Unsubstituted forname attribute value", "Dirty", tsr.attributes.getValue("forname")); |
| assertEquals("Unsubstituted surname attribute value", "Harry", tsr.attributes.getValue("surname")); |
| |
| digester.setSubstitutor( |
| new Substitutor() { |
| public Attributes substitute(Attributes attributes) { |
| AttributesImpl results = new AttributesImpl(); |
| results.addAttribute("", "python", "python", "CDATA", "Cleese"); |
| return results; |
| } |
| |
| public String substitute(String bodyText) { |
| return "And now for something completely different..."; |
| } |
| }); |
| |
| // now transform into the full monty |
| in = new InputSource(new StringReader(xml)); |
| digester.parse(in); |
| |
| assertEquals("Substituted body text", "And now for something completely different...", tsr.body); |
| assertEquals("Substituted number of attributes", 1, tsr.attributes.getLength()); |
| assertEquals("Substituted python attribute value", "Cleese", tsr.attributes.getValue("", "python")); |
| } |
| |
| /** Tests the push-peek-pop cycle for a named stack */ |
| public void testNamedStackPushPeekPop() throws Exception |
| { |
| BigDecimal archimedesAveragePi = new BigDecimal("3.1418"); |
| String testStackName = "org.apache.commons.digester.tests.testNamedStackPushPeekPop"; |
| Digester digester = new Digester(); |
| assertTrue("Stack starts empty:", digester.isEmpty(testStackName)); |
| digester.push(testStackName, archimedesAveragePi); |
| assertEquals("Peeked value:", archimedesAveragePi, digester.peek(testStackName)); |
| assertEquals("Popped value:", archimedesAveragePi, digester.pop(testStackName)); |
| assertTrue("Stack ends empty:", digester.isEmpty(testStackName)); |
| } |
| |
| /** Tests that values are stored independently */ |
| public void testNamedIndependence() |
| { |
| String testStackOneName = "org.apache.commons.digester.tests.testNamedIndependenceOne"; |
| String testStackTwoName = "org.apache.commons.digester.tests.testNamedIndependenceTwo"; |
| Digester digester = new Digester(); |
| digester.push(testStackOneName, "Tweedledum"); |
| digester.push(testStackTwoName, "Tweedledee"); |
| assertEquals("Popped value one:", "Tweedledum", digester.pop(testStackOneName)); |
| assertEquals("Popped value two:", "Tweedledee", digester.pop(testStackTwoName)); |
| } |
| |
| /** Tests popping named stack not yet pushed */ |
| public void testPopNamedStackNotPushed() |
| { |
| String testStackName = "org.apache.commons.digester.tests.testPopNamedStackNotPushed"; |
| Digester digester = new Digester(); |
| try { |
| |
| digester.pop(testStackName); |
| fail("Expected an EmptyStackException"); |
| |
| } catch (EmptyStackException e) { |
| // expected |
| } |
| |
| try { |
| |
| digester.peek(testStackName); |
| fail("Expected an EmptyStackException"); |
| |
| } catch (EmptyStackException e) { |
| // expected |
| } |
| } |
| |
| /** Tests for isEmpty */ |
| public void testNamedStackIsEmpty() |
| { |
| String testStackName = "org.apache.commons.digester.tests.testNamedStackIsEmpty"; |
| Digester digester = new Digester(); |
| assertTrue( |
| "A named stack that has no object pushed onto it yet should be empty", |
| digester.isEmpty(testStackName)); |
| |
| digester.push(testStackName, "Some test value"); |
| assertFalse( |
| "A named stack that has an object pushed onto it should be not empty", |
| digester.isEmpty(testStackName)); |
| |
| digester.peek(testStackName); |
| assertFalse( |
| "Peek should not effect whether the stack is empty", |
| digester.isEmpty(testStackName)); |
| |
| digester.pop(testStackName); |
| assertTrue( |
| "A named stack that has it's last object popped is empty", |
| digester.isEmpty(testStackName)); |
| } |
| |
| /** |
| * Test the Digester.getRoot method. |
| */ |
| public void testGetRoot() throws Exception { |
| Digester digester = new Digester(); |
| digester.addRule("root", new ObjectCreateRule(TestBean.class)); |
| |
| String xml = "<root/>"; |
| InputSource in = new InputSource(new StringReader(xml)); |
| |
| digester.parse(in); |
| |
| Object root = digester.getRoot(); |
| assertNotNull("root object not retrieved", root); |
| assertTrue("root object not a TestRule instance", (root instanceof TestBean)); |
| } |
| } |