skitching 2004/04/03 21:03:23 Added: digester/src/test/org/apache/commons/digester Box.java OverlappingCallMethodRuleTestCase.java Log: Some more test cases for CallMethodRule behaviour when calls and params overlap and nest. Revision Changes Path 1.1 jakarta-commons/digester/src/test/org/apache/commons/digester/Box.java Index: Box.java =================================================================== /* * 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.util.List; import java.util.LinkedList; import java.util.Iterator; /** * Simple class for use in unit tests. A box has an ID, and can have * multiple boxes within it. */ public class Box { private String id; private List children = new LinkedList(); public Box() {} public String getId() { return id; } public void setId(String id) { this.id = id; } public void addChild(Box child) { this.children.add(child); } public List getChildren() { return children; } public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[Box] id="); buf.append(id); buf.append(" nchildren="); buf.append(children.size()); for(Iterator i = children.iterator(); i.hasNext(); ) { Box child = (Box) i.next(); buf.append(" "); buf.append(child.toString()); } return buf.toString(); } /** * Return a string containing this object's name value, followed by the * names of all child objects (and their children etc) in pre-order * sequence. Each name is separated by a space from the preceding one. */ public String getIds() { StringBuffer buf = new StringBuffer(); buf.append(this.id); for(Iterator i = children.iterator(); i.hasNext(); ) { Box child = (Box) i.next(); buf.append(" "); buf.append(child.getIds()); } return buf.toString(); } } 1.1 jakarta-commons/digester/src/test/org/apache/commons/digester/OverlappingCallMethodRuleTestCase.java Index: OverlappingCallMethodRuleTestCase.java =================================================================== /* * 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.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.xml.sax.SAXException; /** * <p>Tests for situations where CallMethodRule instances and their * parameters overlap each other.</p> */ public class OverlappingCallMethodRuleTestCase extends TestCase { // ----------------------------------------------------- Instance Variables /** * The digester instance we will be processing. */ protected Digester digester = null; // ----------------------------------------------------------- Constructors /** * Construct a new instance of this test case. * * @param name Name of the test case */ public OverlappingCallMethodRuleTestCase(String name) { super(name); } // --------------------------------------------------- Overall Test Methods /** * Set up instance variables required by this test case. */ public void setUp() { } /** * Return the tests included in this test suite. */ public static Test suite() { return (new TestSuite(OverlappingCallMethodRuleTestCase.class)); } /** * Tear down instance variables required by this test case. */ public void tearDown() { } String itemId; String itemName; public void setItemId(String id) { itemId = id; } public void setItemName(String name) { itemName = name; } // ------------------------------------------------ Individual Test Methods public void testItem1() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<root>"); input.append(" <item id='1'>anitem</item>"); input.append("</root>"); Digester digester = new Digester(); digester.addCallMethod("root/item", "setItemId", 1); digester.addCallParam("root/item", 0, "id"); digester.addCallMethod("root/item", "setItemName", 1); digester.addCallParam("root/item", 0); this.itemId = null; this.itemName = null; digester.push(this); digester.parse(new StringReader(input.toString())); assertEquals("1", this.itemId); assertEquals("anitem", this.itemName); } public void testItem2() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<root>"); input.append(" <item id='1'>anitem</item>"); input.append("</root>"); Digester digester = new Digester(); digester.addCallMethod("root/item", "setItemName", 1); digester.addCallParam("root/item", 0); digester.addCallMethod("root/item", "setItemId", 1); digester.addCallParam("root/item", 0, "id"); this.itemId = null; this.itemName = null; digester.push(this); digester.parse(new StringReader(input.toString())); assertEquals("1", this.itemId); assertEquals("anitem", this.itemName); } public void testItem3() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<root>"); input.append(" <item>1</item>"); input.append("</root>"); Digester digester = new Digester(); digester.addCallMethod("root/item", "setItemId", 1); digester.addCallParam("root/item", 0); digester.addCallMethod("root/item", "setItemName", 1); digester.addCallParam("root/item", 0); this.itemId = null; this.itemName = null; digester.push(this); digester.parse(new StringReader(input.toString())); assertEquals("1", this.itemId); assertEquals("1", this.itemName); } /** * This is an "anti-test" that demonstrates how digester can <i>fails</i> * to produce the correct results, due to a design flaw (or at least * limitation) in the way that CallMethodRule and CallParamRule work. * <p> * The following sequence always fails: * <ul> * <li>CallMethodRule A fires (pushing params array)</li> * <li>CallMethodRule B fires (pushing params array)</li> * <li>params rule for A fires --> writes to params of method B!</li> * <li>params rule for B fires --> overwrites params for method B</li> * </ul> * The result is that method "b" appears to work ok, but method "a" * loses its input parameters. * <p> * One solution is for CallParamRule objects to know which CallMethodRule * they are associated with. Even this might fail in corner cases where * the same rule is associated with multiple patterns, or with wildcard * patterns which cause a rule to fire in a "recursive" manner. However * implementing this is not possible with the current digester design. */ public void testItem4() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<root>"); input.append(" <item>"); input.append(" <id value='1'/>"); input.append(" <name value='name'/>"); input.append(" </item>"); input.append("</root>"); Digester digester = new Digester(); digester.addCallMethod("root/item", "setItemId", 1); digester.addCallParam("root/item/id", 0, "value"); digester.addCallMethod("root/item", "setItemName", 1); digester.addCallParam("root/item/name", 0, "value"); this.itemId = null; this.itemName = null; digester.push(this); digester.parse(new StringReader(input.toString())); // These are the "correct" results //assertEquals("1", this.itemId); //assertEquals("name", this.itemName); // These are what actually happens assertEquals(null, this.itemId); assertEquals("name", this.itemName); } /** * This test checks that CallParamRule instances which fetch data * from xml attributes work ok when invoked "recursively", * ie a rule instances' methods gets called in the order * begin[1]/begin[2]/body[2]/end[2]/body[1]/end[1] */ public void testWildcard1() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<box id='A1'>"); input.append(" <box id='B1'>"); input.append(" <box id='C1'/>"); input.append(" <box id='C2'/>"); input.append(" </box>"); input.append("</box>"); Digester digester = new Digester(); digester.addObjectCreate("*/box", Box.class); digester.addCallMethod("*/box", "setId", 1); digester.addCallParam("*/box", 0, "id"); digester.addSetNext("*/box", "addChild"); Box root = new Box(); root.setId("root"); digester.push(root); digester.parse(new StringReader(input.toString())); // walk the object tree, concatenating the id strings String ids = root.getIds(); assertEquals("root A1 B1 C1 C2", ids); } /** * This test checks that CallParamRule instances which fetch data * from the xml element body work ok when invoked "recursively", * ie a rule instances' methods gets called in the order * begin[1]/begin[2]/body[2]/end[2]/body[1]/end[1] */ public void testWildcard2() throws SAXException, IOException { StringBuffer input = new StringBuffer(); input.append("<box>A1"); input.append(" <box>B1"); input.append(" <box>C1</box>"); input.append(" <box>C2</box>"); input.append(" </box>"); input.append("</box>"); Digester digester = new Digester(); digester.addObjectCreate("*/box", Box.class); digester.addCallMethod("*/box", "setId", 1); digester.addCallParam("*/box", 0); digester.addSetNext("*/box", "addChild"); Box root = new Box(); root.setId("root"); digester.push(root); digester.parse(new StringReader(input.toString())); // walk the object tree, concatenating the id strings String ids = root.getIds(); assertEquals("root A1 B1 C1 C2", ids); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]