You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/04/20 21:32:10 UTC

svn commit: r1588831 [8/11] - in /commons/proper/configuration/trunk: ./ src/main/java/org/apache/commons/configuration/ src/main/java/org/apache/commons/configuration/beanutils/ src/main/java/org/apache/commons/configuration/builder/combined/ src/main...

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java Sun Apr 20 19:32:08 2014
@@ -14,433 +14,46 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.configuration;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.configuration.convert.DefaultListDelimiterHandler;
-import org.apache.commons.configuration.event.ConfigurationEvent;
-import org.apache.commons.configuration.event.ConfigurationListener;
-import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
 import org.apache.commons.configuration.tree.DefaultConfigurationKey;
-import org.apache.commons.configuration.tree.DefaultConfigurationNode;
 import org.apache.commons.configuration.tree.DefaultExpressionEngine;
-import org.apache.commons.configuration.tree.DefaultExpressionEngineSymbols;
-import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.ImmutableNode;
+import org.apache.commons.configuration.tree.NodeStructureHelper;
 import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Test class for BaseHierarchicalConfiguration.
+ * Test class for {@code BaseHierarchicalConfiguration}.
  *
  * @version $Id$
  */
 public class TestHierarchicalConfiguration
 {
-    private static String[] tables = { "users", "documents" };
-
-    private static String[][] fields =
-    {
-        { "uid", "uname", "firstName", "lastName", "email" },
-        { "docid", "name", "creationDate", "authorID", "version" }
-    };
+    /** Constant for a changed name. */
+    private static final String NEW_NAME = "alteredName";
 
+    /** The configuration to be tested. */
     private BaseHierarchicalConfiguration config;
 
     @Before
     public void setUp() throws Exception
     {
+        ImmutableNode root =
+                new ImmutableNode.Builder(1).addChild(
+                        NodeStructureHelper.ROOT_TABLES_TREE).create();
         config = new BaseHierarchicalConfiguration();
-        fillConfiguration(tables);
-    }
-
-    /**
-     * Initialize the configuration with the following structure:
-     *
-     * tables
-     *      table
-     *         name
-     *         fields
-     *             field
-     *                 name
-     *             field
-     *                 name
-     * @param tabNames the array with the names of the test tables
-     */
-    private void fillConfiguration(String[] tabNames)
-    {
-        ConfigurationNode nodeTables = createNode("tables", null);
-        for(int i = 0; i < tabNames.length; i++)
-        {
-            ConfigurationNode nodeTable = createNode("table", null);
-            nodeTables.addChild(nodeTable);
-            ConfigurationNode nodeName = createNode("name", tabNames[i]);
-            nodeTable.addChild(nodeName);
-            ConfigurationNode nodeFields = createNode("fields", null);
-            nodeTable.addChild(nodeFields);
-
-            for (int j = 0; j < fields[i].length; j++)
-            {
-                nodeFields.addChild(createFieldNode(fields[i][j]));
-            }
-        }
-
-        config.getRootNode().addChild(nodeTables);
-    }
-
-    @Test
-    public void testSetRootNode()
-    {
-        ConfigurationNode root = new DefaultConfigurationNode("testNode");
         config.setRootNode(root);
-        assertSame("Wrong root node", root, config.getRootNode());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testSetRootNodeNull()
-    {
-        config.setRootNode(null);
-    }
-
-    @Test
-    public void testIsEmpty()
-    {
-        assertFalse(config.isEmpty());
-        BaseHierarchicalConfiguration conf2 = new BaseHierarchicalConfiguration();
-        assertTrue(conf2.isEmpty());
-        ConfigurationNode child1 = new DefaultConfigurationNode("child1");
-        ConfigurationNode child2 = new DefaultConfigurationNode("child2");
-        child1.addChild(child2);
-        conf2.getRootNode().addChild(child1);
-        assertTrue(conf2.isEmpty());
-    }
-
-    @Test
-    public void testGetProperty()
-    {
-        assertNull(config.getProperty("tables.table.resultset"));
-        assertNull(config.getProperty("tables.table.fields.field"));
-
-        Object prop = config.getProperty("tables.table(0).fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(5, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables.table.fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(10, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables.table.fields.field(3).name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(2, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables.table(1).fields.field(2).name");
-        assertNotNull(prop);
-        assertEquals("creationDate", prop.toString());
-    }
-
-    @Test
-    public void testSetProperty()
-    {
-        config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
-        config.setProperty("tables.table(0).name", "resources");
-        assertEquals("resources", config.getString("tables.table(0).name"));
-        config.setProperty("tables.table.name", "tab1,tab2");
-        assertEquals("tab1", config.getString("tables.table(0).name"));
-        assertEquals("tab2", config.getString("tables.table(1).name"));
-
-        config.setProperty("test.items.item", new int[] { 2, 4, 8, 16 });
-        assertEquals(3, config.getMaxIndex("test.items.item"));
-        assertEquals(8, config.getInt("test.items.item(2)"));
-        config.setProperty("test.items.item(2)", new Integer(6));
-        assertEquals(6, config.getInt("test.items.item(2)"));
-        config.setProperty("test.items.item(2)", new int[] { 7, 9, 11 });
-        assertEquals(5, config.getMaxIndex("test.items.item"));
-
-        config.setProperty("test", Boolean.TRUE);
-        config.setProperty("test.items", "01/01/05");
-        assertEquals(5, config.getMaxIndex("test.items.item"));
-        assertTrue(config.getBoolean("test"));
-        assertEquals("01/01/05", config.getProperty("test.items"));
-
-        config.setProperty("test.items.item", new Integer(42));
-        assertEquals(0, config.getMaxIndex("test.items.item"));
-        assertEquals(42, config.getInt("test.items.item"));
-    }
-
-    @Test
-    public void testClear()
-    {
-        config.setProperty(null, "value");
-        config.addProperty("[@attr]", "defined");
-        config.clear();
-        assertTrue("Configuration not empty", config.isEmpty());
-    }
-
-    @Test
-    public void testClearProperty()
-    {
-        config.clearProperty("tables.table(0).fields.field(0).name");
-        assertEquals("uname", config.getProperty("tables.table(0).fields.field(0).name"));
-        config.clearProperty("tables.table(0).name");
-        assertFalse(config.containsKey("tables.table(0).name"));
-        assertEquals("firstName", config.getProperty("tables.table(0).fields.field(1).name"));
-        assertEquals("documents", config.getProperty("tables.table.name"));
-        config.clearProperty("tables.table");
-        assertEquals("documents", config.getProperty("tables.table.name"));
-
-        config.addProperty("test", "first");
-        config.addProperty("test.level", "second");
-        config.clearProperty("test");
-        assertEquals("second", config.getString("test.level"));
-        assertFalse(config.containsKey("test"));
-    }
-
-    @Test
-    public void testClearTree()
-    {
-        Object prop = config.getProperty("tables.table(0).fields.field.name");
-        assertNotNull(prop);
-        config.clearTree("tables.table(0).fields.field(3)");
-        prop = config.getProperty("tables.table(0).fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(4, ((Collection<?>) prop).size());
-
-        config.clearTree("tables.table(0).fields");
-        assertNull(config.getProperty("tables.table(0).fields.field.name"));
-        prop = config.getProperty("tables.table.fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(5, ((Collection<?>) prop).size());
-
-        config.clearTree("tables.table(1)");
-        assertNull(config.getProperty("tables.table.fields.field.name"));
-    }
-
-    /**
-     * Tests removing more complex node structures.
-     */
-    @Test
-    public void testClearTreeComplex()
-    {
-        final int count = 5;
-        // create the structure
-        for (int idx = 0; idx < count; idx++)
-        {
-            config.addProperty("indexList.index(-1)[@default]", Boolean.FALSE);
-            config.addProperty("indexList.index[@name]", "test" + idx);
-            config.addProperty("indexList.index.dir", "testDir" + idx);
-        }
-        assertEquals("Wrong number of nodes", count - 1, config
-                .getMaxIndex("indexList.index[@name]"));
-
-        // Remove a sub tree
-        boolean found = false;
-        for (int idx = 0; true; idx++)
-        {
-            String name = config.getString("indexList.index(" + idx
-                    + ")[@name]");
-            if (name == null)
-            {
-                break;
-            }
-            if ("test3".equals(name))
-            {
-                assertEquals("Wrong dir", "testDir3", config
-                        .getString("indexList.index(" + idx + ").dir"));
-                config.clearTree("indexList.index(" + idx + ")");
-                found = true;
-            }
-        }
-        assertTrue("Key to remove not found", found);
-        assertEquals("Wrong number of nodes after remove", count - 2, config
-                .getMaxIndex("indexList.index[@name]"));
-        assertEquals("Wrong number of dir nodes after remove", count - 2,
-                config.getMaxIndex("indexList.index.dir"));
-
-        // Verify
-        for (int idx = 0; true; idx++)
-        {
-            String name = config.getString("indexList.index(" + idx
-                    + ")[@name]");
-            if (name == null)
-            {
-                break;
-            }
-            if ("test3".equals(name))
-            {
-                fail("Key was not removed!");
-            }
-        }
-    }
-
-    /**
-     * Tests the clearTree() method on a hierarchical structure of nodes. This
-     * is a test case for CONFIGURATION-293.
-     */
-    @Test
-    public void testClearTreeHierarchy()
-    {
-        config.addProperty("a.b.c", "c");
-        config.addProperty("a.b.c.d", "d");
-        config.addProperty("a.b.c.d.e", "e");
-        config.clearTree("a.b.c");
-        assertFalse("Property not removed", config.containsKey("a.b.c"));
-        assertFalse("Sub property not removed", config.containsKey("a.b.c.d"));
-    }
-
-    @Test
-    public void testContainsKey()
-    {
-        assertTrue(config.containsKey("tables.table(0).name"));
-        assertTrue(config.containsKey("tables.table(1).name"));
-        assertFalse(config.containsKey("tables.table(2).name"));
-
-        assertTrue(config.containsKey("tables.table(0).fields.field.name"));
-        assertFalse(config.containsKey("tables.table(0).fields.field"));
-        config.clearTree("tables.table(0).fields");
-        assertFalse(config.containsKey("tables.table(0).fields.field.name"));
-
-        assertTrue(config.containsKey("tables.table.fields.field.name"));
-    }
-
-    @Test
-    public void testGetKeys()
-    {
-        List<String> keys = new ArrayList<String>();
-        for (Iterator<String> it = config.getKeys(); it.hasNext();)
-        {
-            keys.add(it.next());
-        }
-
-        assertEquals(2, keys.size());
-        assertTrue(keys.contains("tables.table.name"));
-        assertTrue(keys.contains("tables.table.fields.field.name"));
-
-        // test the order of the keys returned
-        config.addProperty("order.key1", "value1");
-        config.addProperty("order.key2", "value2");
-        config.addProperty("order.key3", "value3");
-
-        Iterator<String> it = config.getKeys("order");
-        assertEquals("1st key", "order.key1", it.next());
-        assertEquals("2nd key", "order.key2", it.next());
-        assertEquals("3rd key", "order.key3", it.next());
-    }
-
-    @Test
-    public void testGetKeysString()
-    {
-        // add some more properties to make it more interesting
-        config.addProperty("tables.table(0).fields.field(1).type", "VARCHAR");
-        config.addProperty("tables.table(0)[@type]", "system");
-        config.addProperty("tables.table(0).size", "42");
-        config.addProperty("tables.table(0).fields.field(0).size", "128");
-        config.addProperty("connections.connection.param.url", "url1");
-        config.addProperty("connections.connection.param.user", "me");
-        config.addProperty("connections.connection.param.pwd", "secret");
-        config.addProperty("connections.connection(-1).param.url", "url2");
-        config.addProperty("connections.connection(1).param.user", "guest");
-
-        checkKeys("tables.table(1)", new String[] { "name", "fields.field.name" });
-        checkKeys("tables.table(0)",
-                new String[] { "name", "fields.field.name", "tables.table(0)[@type]", "size", "fields.field.type", "fields.field.size" });
-        checkKeys("connections.connection(0).param",
-                new String[] {"url", "user", "pwd" });
-        checkKeys("connections.connection(1).param",
-                new String[] {"url", "user" });
-    }
-
-    /**
-     * Tests getKeys() with a prefix when the prefix matches exactly a key.
-     */
-    @Test
-    public void testGetKeysWithKeyAsPrefix()
-    {
-        config.addProperty("order.key1", "value1");
-        config.addProperty("order.key2", "value2");
-        Iterator<String> it = config.getKeys("order.key1");
-        assertTrue("no key found", it.hasNext());
-        assertEquals("1st key", "order.key1", it.next());
-        assertFalse("more keys than expected", it.hasNext());
-    }
-
-    /**
-     * Tests getKeys() with a prefix when the prefix matches exactly a key, and
-     * there are multiple keys starting with this prefix.
-     */
-    @Test
-    public void testGetKeysWithKeyAsPrefixMultiple()
-    {
-        config.addProperty("order.key1", "value1");
-        config.addProperty("order.key1.test", "value2");
-        config.addProperty("order.key1.test.complex", "value2");
-        Iterator<String> it = config.getKeys("order.key1");
-        assertEquals("Wrong key 1", "order.key1", it.next());
-        assertEquals("Wrong key 2", "order.key1.test", it.next());
-        assertEquals("Wrong key 3", "order.key1.test.complex", it.next());
-        assertFalse("More keys than expected", it.hasNext());
-    }
-
-    @Test
-    public void testAddProperty()
-    {
-        config.addProperty("tables.table(0).fields.field(-1).name", "phone");
-        Object prop = config.getProperty("tables.table(0).fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(6, ((Collection<?>) prop).size());
-
-        config.addProperty("tables.table(0).fields.field.name", "fax");
-        prop = config.getProperty("tables.table.fields.field(5).name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof List);
-        List<?> list = (List<?>) prop;
-        assertEquals("phone", list.get(0));
-        assertEquals("fax", list.get(1));
-
-        config.addProperty("tables.table(-1).name", "config");
-        prop = config.getProperty("tables.table.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(3, ((Collection<?>) prop).size());
-        config.addProperty("tables.table(2).fields.field(0).name", "cid");
-        config.addProperty("tables.table(2).fields.field(-1).name",
-        "confName");
-        prop = config.getProperty("tables.table(2).fields.field.name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(2, ((Collection<?>) prop).size());
-        assertEquals("confName",
-        config.getProperty("tables.table(2).fields.field(1).name"));
-
-        config.addProperty("connection.user", "scott");
-        config.addProperty("connection.passwd", "tiger");
-        assertEquals("tiger", config.getProperty("connection.passwd"));
-
-        DefaultConfigurationKey key = createConfigurationKey();
-        key.append("tables").append("table").appendIndex(0);
-        key.appendAttribute("tableType");
-        config.addProperty(key.toString(), "system");
-        assertEquals("system", config.getProperty(key.toString()));
     }
 
     /**
@@ -453,52 +66,24 @@ public class TestHierarchicalConfigurati
         return new DefaultConfigurationKey(DefaultExpressionEngine.INSTANCE);
     }
 
-    @Test(expected = IllegalArgumentException.class)
-    public void testAddPropertyInvalidKey()
-    {
-        config.addProperty(".", "InvalidKey");
-    }
-
-    @Test
-    public void testGetMaxIndex()
-    {
-        assertEquals(4, config.getMaxIndex("tables.table(0).fields.field"));
-        assertEquals(4, config.getMaxIndex("tables.table(1).fields.field"));
-        assertEquals(1, config.getMaxIndex("tables.table"));
-        assertEquals(1, config.getMaxIndex("tables.table.name"));
-        assertEquals(0, config.getMaxIndex("tables.table(0).name"));
-        assertEquals(0, config.getMaxIndex("tables.table(1).fields.field(1)"));
-        assertEquals(-1, config.getMaxIndex("tables.table(2).fields"));
-
-        int maxIdx = config.getMaxIndex("tables.table(0).fields.field.name");
-        for(int i = 0; i <= maxIdx; i++)
-        {
-            DefaultConfigurationKey key =
-                    new DefaultConfigurationKey(DefaultExpressionEngine.INSTANCE,
-                            "tables.table(0).fields");
-            key.append("field").appendIndex(i).append("name");
-            assertNotNull(config.getProperty(key.toString()));
-        }
-    }
-
     @Test
     public void testSubset()
     {
         // test the subset on the first table
         Configuration subset = config.subset("tables.table(0)");
-        assertEquals(tables[0], subset.getProperty("name"));
+        assertEquals(NodeStructureHelper.table(0), subset.getProperty("name"));
 
         Object prop = subset.getProperty("fields.field.name");
         assertNotNull(prop);
         assertTrue(prop instanceof Collection);
         assertEquals(5, ((Collection<?>) prop).size());
 
-        for (int i = 0; i < fields[0].length; i++)
+        for (int i = 0; i < NodeStructureHelper.fieldsLength(0); i++)
         {
             DefaultConfigurationKey key = createConfigurationKey();
             key.append("fields").append("field").appendIndex(i);
             key.append("name");
-            assertEquals(fields[0][i], subset.getProperty(key.toString()));
+            assertEquals(NodeStructureHelper.field(0, i), subset.getProperty(key.toString()));
         }
 
         // test the subset on the second table
@@ -508,9 +93,15 @@ public class TestHierarchicalConfigurati
         subset = config.subset("tables.table.fields.field");
         prop = subset.getProperty("name");
         assertTrue("prop is not a collection", prop instanceof Collection);
-        assertEquals(10, ((Collection<?>) prop).size());
+        int expectedFieldCount = 0;
+        for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
+        {
+            expectedFieldCount += NodeStructureHelper.fieldsLength(i);
+        }
+        assertEquals("Wrong number of fields", expectedFieldCount,
+                ((Collection<?>) prop).size());
 
-        assertEquals(fields[0][0], subset.getProperty("name(0)"));
+        assertEquals(NodeStructureHelper.field(0, 0), subset.getProperty("name(0)"));
 
         // test the subset on the field names
         subset = config.subset("tables.table.fields.field.name");
@@ -518,7 +109,7 @@ public class TestHierarchicalConfigurati
     }
 
     /**
-     * Tests the subset() method when the specified node has a value. This value
+     * Tests the subset() method if the specified node has a value. This value
      * must be available in the subset, too. Related to CONFIGURATION-295.
      */
     @Test
@@ -526,13 +117,13 @@ public class TestHierarchicalConfigurati
     {
         config.setProperty("tables.table(0).fields", "My fields");
         Configuration subset = config.subset("tables.table(0).fields");
-        assertEquals("Wrong field name", fields[0][0], subset
+        assertEquals("Wrong field name", NodeStructureHelper.field(0, 0), subset
                 .getString("field(0).name"));
         assertEquals("Wrong value of root", "My fields", subset.getString(""));
     }
 
     /**
-     * Tests the subset() method when the specified key selects multiple keys.
+     * Tests the subset() method if the specified key selects multiple keys.
      * The resulting root node should have a value only if exactly one of the
      * selected nodes has a value. Related to CONFIGURATION-295.
      */
@@ -549,29 +140,99 @@ public class TestHierarchicalConfigurati
     }
 
     /**
-     * Tests the configurationAt() method to obtain a configuration for a sub
-     * tree.
+     * Tests subset() if the passed in key selects an attribute.
      */
     @Test
-    public void testConfigurationAt()
+    public void testSubsetAttributeResult()
     {
-        BaseHierarchicalConfiguration subConfig = config
-                .configurationAt("tables.table(1)");
-        assertEquals("Wrong table name", tables[1], subConfig.getString("name"));
+        String key = "tables.table(0)[@type]";
+        config.addProperty(key, "system");
+        BaseHierarchicalConfiguration subset =
+                (BaseHierarchicalConfiguration) config.subset(key);
+        assertTrue("Got children of root node", subset.getRootNode()
+                .getChildren().isEmpty());
+        assertEquals("Attribute not found", "system",
+                subset.getString("[@type]"));
+    }
+
+    /**
+     * Tests whether a configuration obtained via configurationAt() contains the
+     * expected properties.
+     */
+    @Test
+    public void testConfigurationAtReadAccess()
+    {
+        HierarchicalConfiguration<ImmutableNode> subConfig =
+                config.configurationAt("tables.table(1)");
+        assertEquals("Wrong table name", NodeStructureHelper.table(1),
+                subConfig.getString("name"));
         List<Object> lstFlds = subConfig.getList("fields.field.name");
-        assertEquals("Wrong number of fields", fields[1].length, lstFlds.size());
-        for (int i = 0; i < fields[1].length; i++)
+        assertEquals("Wrong number of fields",
+                NodeStructureHelper.fieldsLength(1), lstFlds.size());
+        for (int i = 0; i < NodeStructureHelper.fieldsLength(1); i++)
         {
-            assertEquals("Wrong field at position " + i, fields[1][i], lstFlds
-                    .get(i));
+            assertEquals("Wrong field at position " + i,
+                    NodeStructureHelper.field(1, i), lstFlds.get(i));
         }
+    }
 
+    /**
+     * Tests an update operation on a sub configuration which is independent on
+     * its parent.
+     */
+    @Test
+    public void testConfigurationAtUpdateSubConfigIndependent()
+    {
+        HierarchicalConfiguration<ImmutableNode> subConfig =
+                config.configurationAt("tables.table(1)");
         subConfig.setProperty("name", "testTable");
-        assertEquals("Change not visible in parent", "testTable", config
-                .getString("tables.table(1).name"));
+        assertEquals("Value not changed", "testTable",
+                subConfig.getString("name"));
+        assertEquals("Change visible in parent", NodeStructureHelper.table(1),
+                config.getString("tables.table(1).name"));
+    }
+
+    /**
+     * Tests an update operation on a parent configuration if the sub
+     * configuration is independent.
+     */
+    @Test
+    public void testConfigurationAtUpdateParentIndependent()
+    {
+        HierarchicalConfiguration<ImmutableNode> subConfig =
+                config.configurationAt("tables.table(1)");
         config.setProperty("tables.table(1).fields.field(2).name", "testField");
-        assertEquals("Change not visible in sub config", "testField", subConfig
-                .getString("fields.field(2).name"));
+        assertEquals("Change visible in sub config",
+                NodeStructureHelper.field(1, 2),
+                subConfig.getString("fields.field(2).name"));
+    }
+
+    /**
+     * Tests an update operation on a sub configuration which is connected to
+     * its parent.
+     */
+    @Test
+    public void testConfigurationAtUpdateSubConfigConnected()
+    {
+        HierarchicalConfiguration<ImmutableNode> subConfig =
+                config.configurationAt("tables.table(1)", true);
+        subConfig.setProperty("name", "testTable");
+        assertEquals("Change not visible in parent", "testTable",
+                config.getString("tables.table(1).name"));
+    }
+
+    /**
+     * Tests an update operation on a parent configuration if the sub
+     * configuration is connected.
+     */
+    @Test
+    public void testConfigurationAtUpdateParentConnected()
+    {
+        HierarchicalConfiguration<ImmutableNode> subConfig =
+                config.configurationAt("tables.table(1)", true);
+        config.setProperty("tables.table(1).fields.field(2).name", "testField");
+        assertEquals("Change visible in sub config", "testField",
+                subConfig.getString("fields.field(2).name"));
     }
 
     /**
@@ -582,13 +243,15 @@ public class TestHierarchicalConfigurati
     {
         ImmutableHierarchicalConfiguration subConfig =
                 config.immutableConfigurationAt("tables.table(1)");
-        assertEquals("Wrong table name", tables[1], subConfig.getString("name"));
+        assertEquals("Wrong table name", NodeStructureHelper.table(1),
+                subConfig.getString("name"));
         List<Object> lstFlds = subConfig.getList("fields.field.name");
-        assertEquals("Wrong number of fields", fields[1].length, lstFlds.size());
-        for (int i = 0; i < fields[1].length; i++)
+        assertEquals("Wrong number of fields",
+                NodeStructureHelper.fieldsLength(1), lstFlds.size());
+        for (int i = 0; i < NodeStructureHelper.fieldsLength(1); i++)
         {
-            assertEquals("Wrong field at position " + i, fields[1][i],
-                    lstFlds.get(i));
+            assertEquals("Wrong field at position " + i,
+                    NodeStructureHelper.field(1, i), lstFlds.get(i));
         }
     }
 
@@ -599,7 +262,7 @@ public class TestHierarchicalConfigurati
     @Test
     public void testImmutableConfigurationAtSupportUpdates()
     {
-        String newTableName = tables[1] + "_other";
+        String newTableName = NodeStructureHelper.table(1) + "_other";
         ImmutableHierarchicalConfiguration subConfig =
                 config.immutableConfigurationAt("tables.table(1)", true);
         config.addProperty("tables.table(-1).name", newTableName);
@@ -609,41 +272,71 @@ public class TestHierarchicalConfigurati
     }
 
     /**
-     * Tests the configurationAt() method when the passed in key does not exist.
+     * Tests the configurationAt() method if the passed in key does not exist.
      */
-    @Test(expected = IllegalArgumentException.class)
+    @Test(expected = ConfigurationRuntimeException.class)
     public void testConfigurationAtUnknownSubTree()
     {
         config.configurationAt("non.existing.key");
     }
 
     /**
-     * Tests the configurationAt() method when the passed in key selects
+     * Tests configurationAt() for a non existing key if the update flag is set.
+     */
+    @Test(expected = ConfigurationRuntimeException.class)
+    public void testConfigurationAtUnknownSubTreeWithUpdates()
+    {
+        config.configurationAt("non.existing.key", true);
+    }
+
+    /**
+     * Tests the configurationAt() method if the passed in key selects
      * multiple nodes. This should cause an exception.
      */
-    @Test(expected = IllegalArgumentException.class)
+    @Test(expected = ConfigurationRuntimeException.class)
     public void testConfigurationAtMultipleNodes()
     {
         config.configurationAt("tables.table.name");
     }
 
     /**
-     * Tests whether a sub configuration obtained by configurationAt() can be
-     * cleared.
+     * Tests configurationAt() if the passed in key selects multiple nodes and the
+     * update flag is set.
      */
-    @Test
-    public void testConfigurationAtClear()
+    @Test(expected = ConfigurationRuntimeException.class)
+    public void testConfigurationAtMultipleNodesWithUpdates()
     {
-        config.addProperty("test.sub.test", "fail");
-        assertEquals("Wrong index (1)", 0, config.getMaxIndex("test"));
-        SubnodeConfiguration sub = config.configurationAt("test.sub");
-        assertEquals("Wrong value", "fail", sub.getString("test"));
-        sub.clear();
-        assertNull("Key still found", config.getString("test.sub.test"));
-        sub.setProperty("test", "success");
-        assertEquals("Property not set", "success",
-                config.getString("test.sub.test"));
-        assertEquals("Wrong index (2)", 0, config.getMaxIndex("test"));
+        config.configurationAt("tables.table.name", true);
+    }
+
+    /**
+     * Checks configurationAt() if the passed in key selects an attribute.
+     * @param withUpdates the updates flag
+     */
+    private void checkConfigurationAtAttributeNode(boolean withUpdates)
+    {
+        final String key = "tables.table(0)[@type]";
+        config.addProperty(key, "system");
+        config.configurationAt(key, withUpdates);
+    }
+
+    /**
+     * Tests configurationAt() if the passed in key selects an attribute result.
+     */
+    @Test(expected = ConfigurationRuntimeException.class)
+    public void testConfigurationAtAttributeNode()
+    {
+        checkConfigurationAtAttributeNode(false);
+    }
+
+    /**
+     * Tests configurationAt() if the passed in key selects an attribute result and the
+     * updates flag is set.
+     */
+    @Test(expected = ConfigurationRuntimeException.class)
+    public void testConfigurationAtAttributeNodeWithUpdates()
+    {
+        checkConfigurationAtAttributeNode(true);
     }
 
     /**
@@ -655,8 +348,9 @@ public class TestHierarchicalConfigurati
     {
         config.addProperty("test.sub.test", "success");
         config.addProperty("test.other", "check");
-        SubnodeConfiguration sub = config.configurationAt("test.sub");
-        sub.clearAndDetachFromParent();
+        HierarchicalConfiguration<ImmutableNode> sub =
+                config.configurationAt("test.sub", true);
+        sub.clear();
         assertTrue("Sub not empty", sub.isEmpty());
         assertNull("Key still found", config.getString("test.sub.test"));
         sub.setProperty("test", "failure!");
@@ -672,195 +366,114 @@ public class TestHierarchicalConfigurati
     private void checkSubConfigurations(
             List<? extends ImmutableConfiguration> lstFlds)
     {
-        assertEquals("Wrong size of fields", fields[1].length, lstFlds.size());
-        for (int i = 0; i < fields[1].length; i++)
+        assertEquals("Wrong size of fields",
+                NodeStructureHelper.fieldsLength(1), lstFlds.size());
+        for (int i = 0; i < NodeStructureHelper.fieldsLength(1); i++)
         {
             ImmutableConfiguration sub = lstFlds.get(i);
-            assertEquals("Wrong field at position " + i, fields[1][i],
-                    sub.getString("name"));
+            assertEquals("Wrong field at position " + i,
+                    NodeStructureHelper.field(1, i), sub.getString("name"));
         }
     }
 
     /**
-     * Tests the configurationsAt() method.
-     */
-    @Test
-    public void testConfigurationsAt()
-    {
-        List<SubnodeConfiguration> lstFlds =
-                config.configurationsAt("tables.table(1).fields.field");
-        checkSubConfigurations(lstFlds);
-    }
-
-    /**
-     * Tests whether a list of immutable sub configurations can be queried.
+     * Helper method for checking a configurationsAt() method. It is also tested
+     * whether the configuration is connected to its parent.
+     *
+     * @param withUpdates the updates flag
+     * @param expName the expected name in the parent configuration
      */
-    @Test
-    public void testImmutableConfigurationsAt()
+    private void checkConfigurationsAtWithUpdate(boolean withUpdates,
+            String expName)
     {
-        List<ImmutableHierarchicalConfiguration> lstFlds =
-                config.immutableConfigurationsAt("tables.table(1).fields.field");
+        String key = "tables.table(1).fields.field";
+        List<HierarchicalConfiguration<ImmutableNode>> lstFlds =
+                withUpdates ? config.configurationsAt(key, true) : config
+                        .configurationsAt(key);
         checkSubConfigurations(lstFlds);
+        lstFlds.get(0).setProperty("name", NEW_NAME);
+        assertEquals("Wrong name in parent", expName,
+                config.getString("tables.table(1).fields.field(0).name"));
     }
 
     /**
-     * Tests the configurationsAt() method when the passed in key does not
-     * select any sub nodes.
+     * Tests the configurationsAt() method if the sub configurations are not
+     * connected..
      */
     @Test
-    public void testConfigurationsAtEmpty()
+    public void testConfigurationsAtNoUpdate()
     {
-        assertTrue("List is not empty", config.configurationsAt("unknown.key")
-                .isEmpty());
-    }
-
-    @Test
-    public void testClone()
-    {
-        Configuration copy = (Configuration) config.clone();
-        assertTrue(copy instanceof BaseHierarchicalConfiguration);
-        checkContent(copy);
+        checkConfigurationsAtWithUpdate(false, NodeStructureHelper.field(1, 0));
     }
 
     /**
-     * Tests whether registered event handlers are handled correctly when a
-     * configuration is cloned. They should not be registered at the clone.
+     * Tests configurationsAt() if the sub configurations are connected.
      */
     @Test
-    public void testCloneWithEventListeners()
+    public void testConfigurationsAtWithUpdates()
     {
-        ConfigurationListener l = new ConfigurationListener()
-        {
-            @Override
-            public void configurationChanged(ConfigurationEvent event)
-            {
-                // just a dummy
-            }
-        };
-        config.addConfigurationListener(l);
-        BaseHierarchicalConfiguration copy = (BaseHierarchicalConfiguration) config
-                .clone();
-        assertFalse("Event listener registered at clone", copy
-                .getConfigurationListeners().contains(l));
+        checkConfigurationsAtWithUpdate(true, NEW_NAME);
     }
 
     /**
-     * Tests whether interpolation works as expected after cloning.
+     * Tests whether a connected configuration is correctly initialized with
+     * properties of its parent.
      */
     @Test
-    public void testCloneInterpolation()
+    public void testConfigurationAtWithUpdateInitialized()
     {
-        final String keyAnswer = "answer";
-        final String keyValue = "value";
-        config.addProperty(keyAnswer, "The answer is ${" + keyValue + "}.");
-        config.addProperty(keyValue, 42);
-        BaseHierarchicalConfiguration clone =
-                (BaseHierarchicalConfiguration) config.clone();
-        clone.setProperty(keyValue, 43);
-        assertEquals("Wrong interpolation in original", "The answer is 42.",
-                config.getString(keyAnswer));
-        assertEquals("Wrong interpolation in clone", "The answer is 43.",
-                clone.getString(keyAnswer));
-    }
-
-    @Test
-    public void testAddNodes()
-    {
-        Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
-        nodes.add(createFieldNode("birthDate"));
-        nodes.add(createFieldNode("lastLogin"));
-        nodes.add(createFieldNode("language"));
-        config.addNodes("tables.table(0).fields", nodes);
-        assertEquals(7, config.getMaxIndex("tables.table(0).fields.field"));
-        assertEquals("birthDate", config.getString("tables.table(0).fields.field(5).name"));
-        assertEquals("lastLogin", config.getString("tables.table(0).fields.field(6).name"));
-        assertEquals("language", config.getString("tables.table(0).fields.field(7).name"));
+        String key = "tables.table";
+        config.setListDelimiterHandler(new DefaultListDelimiterHandler(';'));
+        config.setThrowExceptionOnMissing(true);
+        List<HierarchicalConfiguration<ImmutableNode>> subs =
+                config.configurationsAt(key, true);
+        BaseHierarchicalConfiguration sub =
+                (BaseHierarchicalConfiguration) subs.get(0);
+        assertEquals("Wrong delimiter handler",
+                config.getListDelimiterHandler(), sub.getListDelimiterHandler());
+        assertTrue("Wrong exception flag", sub.isThrowExceptionOnMissing());
     }
 
     /**
-     * Tests the addNodes() method when the provided key does not exist. In
-     * this case, a new node (or even a complete new branch) will be created.
+     * Tests whether a list of immutable sub configurations can be queried.
      */
     @Test
-    public void testAddNodesForNonExistingKey()
-    {
-        Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
-        nodes.add(createNode("usr", "scott"));
-        ConfigurationNode nd = createNode("pwd", "tiger");
-        nd.setAttribute(true);
-        nodes.add(nd);
-        config.addNodes("database.connection.settings", nodes);
-
-        assertEquals("Usr node not found", "scott", config.getString("database.connection.settings.usr"));
-        assertEquals("Pwd node not found", "tiger", config.getString("database.connection.settings[@pwd]"));
-    }
-
-    /**
-     * Tests the addNodes() method when the new nodes should be added to an
-     * attribute node. This is not allowed.
-     */
-    @Test(expected = IllegalArgumentException.class)
-    public void testAddNodesWithAttributeKey()
+    public void testImmutableConfigurationsAt()
     {
-        Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
-        nodes.add(createNode("testNode", "yes"));
-        config.addNodes("database.connection[@settings]", nodes);
+        List<ImmutableHierarchicalConfiguration> lstFlds =
+                config.immutableConfigurationsAt("tables.table(1).fields.field");
+        checkSubConfigurations(lstFlds);
     }
 
     /**
-     * Tests copying nodes from one configuration to another one.
+     * Tests the configurationsAt() method when the passed in key does not
+     * select any sub nodes.
      */
     @Test
-    public void testAddNodesCopy()
+    public void testConfigurationsAtEmpty()
     {
-        BaseHierarchicalConfiguration configDest = new BaseHierarchicalConfiguration();
-        configDest.addProperty("test", "TEST");
-        Collection<ConfigurationNode> nodes = config.getRootNode().getChildren();
-        assertEquals("Wrong number of children", 1, nodes.size());
-        configDest.addNodes("newNodes", nodes);
-        for (int i = 0; i < tables.length; i++)
-        {
-            String keyTab = "newNodes.tables.table(" + i + ").";
-            assertEquals("Table " + i + " not found", tables[i], configDest
-                    .getString(keyTab + "name"));
-            for (int j = 0; j < fields[i].length; j++)
-            {
-                assertEquals("Invalid field " + j + " in table " + i,
-                        fields[i][j], configDest.getString(keyTab
-                                + "fields.field(" + j + ").name"));
-            }
-        }
+        assertTrue("List is not empty", config.configurationsAt("unknown.key")
+                .isEmpty());
     }
 
     /**
-     * Tests adding an attribute node with the addNodes() method.
+     * Tests configurationsAt() if an attribute key is passed in.
      */
     @Test
-    public void testAddNodesAttributeNode()
+    public void testConfigurationsAtAttributeKey()
     {
-        Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
-        ConfigurationNode nd = createNode("length", "10");
-        nd.setAttribute(true);
-        nodes.add(nd);
-        config.addNodes("tables.table(0).fields.field(1)", nodes);
-        assertEquals("Attribute was not added", "10", config
-                .getString("tables.table(0).fields.field(1)[@length]"));
+        String attrKey = "tables.table(0)[@type]";
+        config.addProperty(attrKey, "user");
+        assertTrue("Got configurations", config.configurationsAt(attrKey).isEmpty());
     }
 
-    /**
-     * Tests setting a custom expression engine, which uses a slightly different
-     * syntax.
-     */
     @Test
-    public void testSetExpressionEngine()
+    public void testClone()
     {
-        config.setExpressionEngine(null);
-        assertNotNull("Expression engine is null", config.getExpressionEngine());
-        assertSame("Default engine is not used",
-                DefaultExpressionEngine.INSTANCE, config.getExpressionEngine());
-
-        config.setExpressionEngine(createAlternativeExpressionEngine());
-        checkAlternativeSyntax();
+        Configuration copy = (Configuration) config.clone();
+        assertTrue(copy instanceof BaseHierarchicalConfiguration);
+        config.setProperty("tables.table(0).name", "changed table name");
+        checkContent(copy);
     }
 
     /**
@@ -886,54 +499,6 @@ public class TestHierarchicalConfigurati
     }
 
     /**
-     * Tests interpolation facilities.
-     */
-    @Test
-    public void testInterpolation()
-    {
-        config.addProperty("base.dir", "/home/foo");
-        config.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
-        config.addProperty("test.absolute.dir.dir2", "${base.dir}/path2");
-        config.addProperty("test.absolute.dir.dir3", "${base.dir}/path3");
-
-        Configuration sub = config.subset("test.absolute.dir");
-        for (int i = 1; i < 4; i++)
-        {
-            assertEquals("Wrong interpolation in parent", "/home/foo/path" + i,
-                    config.getString("test.absolute.dir.dir" + i));
-            assertEquals("Wrong interpolation in subnode",
-                    "/home/foo/path" + i, sub.getString("dir" + i));
-        }
-    }
-
-    /**
-     * Basic interpolation tests.
-     */
-    @Test
-    public void testInterpolationBasic()
-    {
-        InterpolationTestHelper.testInterpolation(config);
-    }
-
-    /**
-     * Tests multiple levels of interpolation.
-     */
-    @Test
-    public void testInterpolationMultipleLevels()
-    {
-        InterpolationTestHelper.testMultipleInterpolation(config);
-    }
-
-    /**
-     * Tests an invalid interpolation that causes an endless loop.
-     */
-    @Test
-    public void testInterpolationLoop()
-    {
-        InterpolationTestHelper.testInterpolationLoop(config);
-    }
-
-    /**
      * Tests interpolation with a subset.
      */
     @Test
@@ -958,51 +523,6 @@ public class TestHierarchicalConfigurati
     }
 
     /**
-     * Tests interpolation of a variable, which cannot be resolved.
-     */
-    @Test
-    public void testInterpolationUnknownProperty()
-    {
-        InterpolationTestHelper.testInterpolationUnknownProperty(config);
-    }
-
-    /**
-     * Tests interpolation with system properties.
-     */
-    @Test
-    public void testInterpolationSysProperties()
-    {
-        InterpolationTestHelper.testInterpolationSystemProperties(config);
-    }
-
-    /**
-     * Tests interpolation with constant values.
-     */
-    @Test
-    public void testInterpolationConstants()
-    {
-        InterpolationTestHelper.testInterpolationConstants(config);
-    }
-
-    /**
-     * Tests escaping variables.
-     */
-    @Test
-    public void testInterpolationEscaped()
-    {
-        InterpolationTestHelper.testInterpolationEscaped(config);
-    }
-
-    /**
-     * Tests manipulating the interpolator.
-     */
-    @Test
-    public void testInterpolator()
-    {
-        InterpolationTestHelper.testGetInterpolator(config);
-    }
-
-    /**
      * Tests obtaining a configuration with all variables substituted.
      */
     @Test
@@ -1013,70 +533,29 @@ public class TestHierarchicalConfigurati
                 .testInterpolatedConfiguration(config);
 
         // tests whether the hierarchical structure has been maintained
-        config = c;
-        testGetProperty();
-    }
-
-    /**
-     * Tests the copy constructor when a null reference is passed.
-     */
-    @Test
-    public void testInitCopyNull()
-    {
-        BaseHierarchicalConfiguration copy =
-                new BaseHierarchicalConfiguration(
-                        (HierarchicalConfiguration) null);
-        assertTrue("Configuration not empty", copy.isEmpty());
-    }
-
-    /**
-     * Tests the parents of nodes when setRootNode() is involved. This is
-     * related to CONFIGURATION-334.
-     */
-    @Test
-    public void testNodeParentsAfterSetRootNode()
-    {
-        DefaultConfigurationNode root = new DefaultConfigurationNode();
-        DefaultConfigurationNode child1 = new DefaultConfigurationNode(
-                "child1", "test1");
-        root.addChild(child1);
-        config.setRootNode(root);
-        config.addProperty("child2", "test2");
-        List<ConfigurationNode> nodes = config.getExpressionEngine().query(config.getRootNode(),
-                "child2");
-        assertEquals("Wrong number of result nodes", 1, nodes.size());
-        ConfigurationNode child2 = nodes.get(0);
-        assertEquals("Different parent nodes", child1.getParentNode(), child2
-                .getParentNode());
+        checkContent(c);
     }
 
     /**
-     * Tests calling getRoot() after a root node was set using setRootNode() and
-     * further child nodes have been added. The newly add child nodes should be
-     * present in the root node returned.
+     * Tests whether interpolation works on an empty configuration.
      */
     @Test
-    public void testGetRootAfterSetRootNode()
+    public void testInterpolatedConfigurationEmpty()
     {
-        DefaultConfigurationNode root = new DefaultConfigurationNode();
-        DefaultConfigurationNode child1 = new DefaultConfigurationNode(
-                "child1", "test1");
-        root.addChild(child1);
-        config.setRootNode(root);
-        config.addProperty("child2", "test2");
-        ConfigurationNode oldRoot = config.getRootNode();
-        assertEquals("Wrong number of children", 2, oldRoot.getChildrenCount());
+        config = new BaseHierarchicalConfiguration();
+        assertTrue("Got content", config.interpolatedConfiguration().isEmpty());
     }
 
     /**
-     * Tests whether keys that contains brackets can be used.
+     * Tests the copy constructor when a null reference is passed.
      */
     @Test
-    public void testGetPropertyKeyWithBrackets()
+    public void testInitCopyNull()
     {
-        final String key = "test.directory.platform(x86)";
-        config.addProperty(key, "C:\\Temp");
-        assertEquals("Wrong property value", "C:\\Temp", config.getString(key));
+        BaseHierarchicalConfiguration copy =
+                new BaseHierarchicalConfiguration(
+                        (HierarchicalConfiguration) null);
+        assertTrue("Configuration not empty", copy.isEmpty());
     }
 
     /**
@@ -1091,144 +570,74 @@ public class TestHierarchicalConfigurati
         assertEquals("Wrong number of elements", 2, children.size());
         ImmutableHierarchicalConfiguration c1 = children.get(0);
         assertEquals("Wrong name (1)", "name", c1.getRootElementName());
-        assertEquals("Wrong table name", tables[0], c1.getString(null));
+        assertEquals("Wrong table name", NodeStructureHelper.table(0), c1.getString(null));
         ImmutableHierarchicalConfiguration c2 = children.get(1);
         assertEquals("Wrong name (2)", "fields", c2.getRootElementName());
-        assertEquals("Wrong field name", fields[0][0],
+        assertEquals("Wrong field name", NodeStructureHelper.field(0, 0),
                 c2.getString("field(0).name"));
     }
 
     /**
-     * Tests whether sub configurations for the children of a given node can be
-     * queried.
+     * Tests access to sub configurations as children of a defined node.
+     *
+     * @param withUpdates the updates flag
+     * @param expectedName the expected table name when reading a property
      */
-    @Test
-    public void testChildConfigurationsAt()
+    private void checkChildConfigurationsAtWithUpdates(boolean withUpdates,
+            String expectedName)
     {
-        List<SubnodeConfiguration> children =
-                config.childConfigurationsAt("tables.table(0)");
+        String key = "tables.table(0)";
+        List<HierarchicalConfiguration<ImmutableNode>> children =
+                withUpdates ? config.childConfigurationsAt(key, true) : config
+                        .childConfigurationsAt(key);
         assertEquals("Wrong number of elements", 2, children.size());
-        SubnodeConfiguration sub = children.get(0);
-        String newTabName = "otherTabe";
-        sub.setProperty(null, newTabName);
-        assertEquals("Table name not changed", newTabName,
-                config.getString("tables.table(0).name"));
+        HierarchicalConfiguration<ImmutableNode> sub = children.get(0);
+        sub.setProperty(null, NEW_NAME);
+        assertEquals("Wrong value in parent", expectedName,
+                config.getString(key + ".name"));
     }
 
     /**
-     * Tests the result of childConfigurationsAt() if the key selects multiple
-     * nodes.
+     * Tests whether sub configurations for the children of a given node can be
+     * queried if no updates are propagated.
      */
     @Test
-    public void testChildConfigurationsAtNoUniqueKey()
+    public void testChildConfigurationsAtNoUpdates()
     {
-        assertTrue("Got children", config.childConfigurationsAt("tables.table")
-                .isEmpty());
+        checkChildConfigurationsAtWithUpdates(false,
+                NodeStructureHelper.table(0));
     }
 
     /**
-     * Tests the result of childConfigurationsAt() if the key does not point to
-     * an existing node.
+     * Tests whether sub configurations for the children of a given node can be
+     * queried that support updates.
      */
     @Test
-    public void testChildConfigurationsAtNotFound()
+    public void testChildConfigurationsAtWithUpdates()
     {
-        assertTrue("Got children",
-                config.childConfigurationsAt("not.existing.key").isEmpty());
+        checkChildConfigurationsAtWithUpdates(true, NEW_NAME);
     }
 
     /**
-     * Tests the initialize() method. We can only test that a new configuration
-     * listener was added.
+     * Tests the result of childConfigurationsAt() if the key selects multiple
+     * nodes.
      */
     @Test
-    public void testInitialize()
+    public void testChildConfigurationsAtNoUniqueKey()
     {
-        Collection<ConfigurationListener> listeners =
-                config.getConfigurationListeners();
-        config.initialize();
-        assertEquals("No new listener added", listeners.size() + 1, config
-                .getConfigurationListeners().size());
+        assertTrue("Got children", config.childConfigurationsAt("tables.table")
+                .isEmpty());
     }
 
     /**
-     * Tests that calling initialize() multiple times does not initialize
-     * internal structures more than once.
+     * Tests the result of childConfigurationsAt() if the key does not point to
+     * an existing node.
      */
     @Test
-    public void testInitializeTwice()
-    {
-        Collection<ConfigurationListener> listeners =
-                config.getConfigurationListeners();
-        config.initialize();
-        config.initialize();
-        assertEquals("Too many listener added", listeners.size() + 1, config
-                .getConfigurationListeners().size());
-    }
-
-    /**
-     * Helper method for testing the getKeys(String) method.
-     *
-     * @param prefix the key to pass into getKeys()
-     * @param expected the expected result
-     */
-    private void checkKeys(String prefix, String[] expected)
-    {
-        Set<String> values = new HashSet<String>();
-        for (String element : expected) {
-            values.add((element.startsWith(prefix)) ? element :  prefix + "." + element);
-        }
-
-        Iterator<String> itKeys = config.getKeys(prefix);
-        while(itKeys.hasNext())
-        {
-            String key = itKeys.next();
-            if(!values.contains(key))
-            {
-                fail("Found unexpected key: " + key);
-            }
-            else
-            {
-                values.remove(key);
-            }
-        }
-
-        assertTrue("Remaining keys " + values, values.isEmpty());
-    }
-
-    /**
-     * Helper method for checking keys using an alternative syntax.
-     */
-    private void checkAlternativeSyntax()
+    public void testChildConfigurationsAtNotFound()
     {
-        assertNull(config.getProperty("tables/table/resultset"));
-        assertNull(config.getProperty("tables/table/fields/field"));
-
-        Object prop = config.getProperty("tables/table[0]/fields/field/name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(5, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables/table/fields/field/name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(10, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables/table/fields/field[3]/name");
-        assertNotNull(prop);
-        assertTrue(prop instanceof Collection);
-        assertEquals(2, ((Collection<?>) prop).size());
-
-        prop = config.getProperty("tables/table[1]/fields/field[2]/name");
-        assertNotNull(prop);
-        assertEquals("creationDate", prop.toString());
-
-        Set<String> keys = new HashSet<String>();
-        CollectionUtils.addAll(keys, config.getKeys());
-        assertEquals("Wrong number of defined keys", 2, keys.size());
-        assertTrue("Key not found", keys.contains("tables/table/name"));
-        assertTrue("Key not found", keys
-                .contains("tables/table/fields/field/name"));
+        assertTrue("Got children",
+                config.childConfigurationsAt("not.existing.key").isEmpty());
     }
 
     /**
@@ -1239,51 +648,17 @@ public class TestHierarchicalConfigurati
      */
     private void checkContent(Configuration c)
     {
-        for (int i = 0; i < tables.length; i++)
+        for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
         {
-            assertEquals(tables[i], c.getString("tables.table(" + i + ").name"));
-            for (int j = 0; j < fields[i].length; j++)
+            assertEquals(NodeStructureHelper.table(i),
+                    c.getString("tables.table(" + i + ").name"));
+            for (int j = 0; j < NodeStructureHelper.fieldsLength(i); j++)
             {
-                assertEquals(fields[i][j], c.getString("tables.table(" + i
-                        + ").fields.field(" + j + ").name"));
+                assertEquals(
+                        NodeStructureHelper.field(i, j),
+                        c.getString("tables.table(" + i + ").fields.field(" + j
+                                + ").name"));
             }
         }
     }
-
-    private ExpressionEngine createAlternativeExpressionEngine()
-    {
-        DefaultExpressionEngine engine =
-                new DefaultExpressionEngine(
-                        new DefaultExpressionEngineSymbols.Builder(
-                                DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
-                                .setPropertyDelimiter("/").setIndexStart("[")
-                                .setIndexEnd("]").create());
-        return engine;
-    }
-
-    /**
-     * Helper method for creating a field node with its children.
-     *
-     * @param name the name of the field
-     * @return the field node
-     */
-    private static ConfigurationNode createFieldNode(String name)
-    {
-        ConfigurationNode fld = createNode("field", null);
-        fld.addChild(createNode("name", name));
-        return fld;
-    }
-
-    /**
-     * Helper method for creating a configuration node.
-     * @param name the node's name
-     * @param value the node's value
-     * @return the new node
-     */
-    private static ConfigurationNode createNode(String name, Object value)
-    {
-        ConfigurationNode node = new DefaultConfigurationNode(name);
-        node.setValue(value);
-        return node;
-    }
 }

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java Sun Apr 20 19:32:08 2014
@@ -25,6 +25,7 @@ import javax.xml.transform.dom.DOMResult
 import javax.xml.transform.sax.SAXSource;
 
 import org.apache.commons.configuration.io.FileHandler;
+import org.apache.commons.configuration.tree.ImmutableNode;
 import org.apache.commons.jxpath.JXPathContext;
 import org.junit.Before;
 import org.junit.Test;
@@ -42,7 +43,7 @@ public class TestHierarchicalConfigurati
     private static final String TEST_FILE = ConfigurationAssert.getTestFile(
             "testHierarchicalXMLConfiguration.xml").getAbsolutePath();
 
-    private HierarchicalConfigurationXMLReader parser;
+    private HierarchicalConfigurationXMLReader<ImmutableNode> parser;
 
     @Before
     public void setUp() throws Exception
@@ -50,7 +51,7 @@ public class TestHierarchicalConfigurati
         XMLConfiguration config = new XMLConfiguration();
         FileHandler handler = new FileHandler(config);
         handler.load(TEST_FILE);
-        parser = new HierarchicalConfigurationXMLReader(config);
+        parser = new HierarchicalConfigurationXMLReader<ImmutableNode>(config);
     }
 
     @Test

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestINIConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestINIConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestINIConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestINIConfiguration.java Sun Apr 20 19:32:08 2014
@@ -19,8 +19,8 @@ package org.apache.commons.configuration
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -40,16 +40,15 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.convert.DefaultListDelimiterHandler;
 import org.apache.commons.configuration.ex.ConfigurationException;
 import org.apache.commons.configuration.sync.ReadWriteSynchronizer;
+import org.apache.commons.configuration.tree.ImmutableNode;
+import org.apache.commons.configuration.tree.NodeHandler;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
 /**
- * Test class for INIConfiguration.
+ * Test class for {@code INIConfiguration}.
  *
- * @author <a
- *         href="http://commons.apache.org/configuration/team-list.html">Commons
- *         Configuration team</a>
  * @version $Id$
  */
 public class TestINIConfiguration
@@ -505,6 +504,20 @@ public class TestINIConfiguration
     }
 
     /**
+     * Tests whether the sub configuration for the global section is connected
+     * to its parent.
+     */
+    @Test
+    public void testGlobalSectionConnected() throws ConfigurationException
+    {
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        HierarchicalConfiguration<ImmutableNode> sub = config.getSection(null);
+        config.setProperty("globalVar", "changed");
+        assertEquals("Wrong value in sub", "changed",
+                sub.getString("globalVar"));
+    }
+
+    /**
      * Tests whether the specified configuration contains exactly the expected
      * sections.
      *
@@ -544,7 +557,7 @@ public class TestINIConfiguration
     @Test
     public void testGetSectionsWithGlobal() throws ConfigurationException
     {
-        checkSectionNames(INI_DATA_GLOBAL, new String[] {
+        checkSectionNames(INI_DATA_GLOBAL, new String[]{
                 null, "section1", "section2", "section3"
         });
     }
@@ -555,7 +568,7 @@ public class TestINIConfiguration
     @Test
     public void testGetSectionsNoGlobal() throws ConfigurationException
     {
-        checkSectionNames(INI_DATA, new String[] {
+        checkSectionNames(INI_DATA, new String[]{
                 "section1", "section2", "section3"
         });
     }
@@ -567,8 +580,8 @@ public class TestINIConfiguration
     @Test
     public void testGetSectionsGlobalOnly() throws ConfigurationException
     {
-        checkSectionNames(INI_DATA_GLOBAL_ONLY, new String[] {
-            null
+        checkSectionNames(INI_DATA_GLOBAL_ONLY, new String[]{
+                null
         });
     }
 
@@ -596,7 +609,7 @@ public class TestINIConfiguration
     {
         INIConfiguration config = setUpConfig(INI_DATA2);
         config.addProperty("section5.test", Boolean.TRUE);
-        checkSectionNames(config, new String[] {
+        checkSectionNames(config, new String[]{
                 "section4", "section5"
         });
     }
@@ -608,12 +621,28 @@ public class TestINIConfiguration
     public void testGetSectionExisting() throws ConfigurationException
     {
         INIConfiguration config = setUpConfig(INI_DATA);
-        SubnodeConfiguration section = config.getSection("section1");
+        HierarchicalConfiguration<ImmutableNode> section =
+                config.getSection("section1");
         assertEquals("Wrong value of var1", "foo", section.getString("var1"));
         assertEquals("Wrong value of var2", "451", section.getString("var2"));
     }
 
     /**
+     * Tests whether the sub configuration returned by getSection() is connected
+     * to the parent.
+     */
+    @Test
+    public void testGetSectionConnected() throws ConfigurationException
+    {
+        INIConfiguration config = setUpConfig(INI_DATA);
+        HierarchicalConfiguration<ImmutableNode> section =
+                config.getSection("section1");
+        section.setProperty("var1", "foo2");
+        assertEquals("Not connected to parent", "foo2",
+                config.getString("section1.var1"));
+    }
+
+    /**
      * Tests querying the properties of a section that was merged from two
      * sections with the same name.
      */
@@ -623,7 +652,7 @@ public class TestINIConfiguration
         final String data = INI_DATA + "[section1]" + LINE_SEPARATOR
                 + "var3 = merged" + LINE_SEPARATOR;
         INIConfiguration config = setUpConfig(data);
-        SubnodeConfiguration section = config.getSection("section1");
+        HierarchicalConfiguration<ImmutableNode> section = config.getSection("section1");
         assertEquals("Wrong value of var1", "foo", section.getString("var1"));
         assertEquals("Wrong value of var2", "451", section.getString("var2"));
         assertEquals("Wrong value of var3", "merged", section.getString("var3"));
@@ -636,7 +665,7 @@ public class TestINIConfiguration
     public void testGetSectionGlobal() throws ConfigurationException
     {
         INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
-        SubnodeConfiguration section = config.getSection(null);
+        HierarchicalConfiguration<ImmutableNode> section = config.getSection(null);
         assertEquals("Wrong value of global variable", "testGlobal", section
                 .getString("globalVar"));
     }
@@ -671,7 +700,7 @@ public class TestINIConfiguration
     public void testGetSectionGlobalNonExisting() throws ConfigurationException
     {
         INIConfiguration config = setUpConfig(INI_DATA);
-        SubnodeConfiguration section = config.getSection(null);
+        HierarchicalConfiguration<ImmutableNode> section = config.getSection(null);
         assertTrue("Sub config not empty", section.isEmpty());
     }
 
@@ -682,7 +711,7 @@ public class TestINIConfiguration
     public void testGetSectionNonExisting() throws ConfigurationException
     {
         INIConfiguration config = setUpConfig(INI_DATA);
-        SubnodeConfiguration section = config
+        HierarchicalConfiguration<ImmutableNode> section = config
                 .getSection("Non existing section");
         assertTrue("Sub config not empty", section.isEmpty());
     }
@@ -864,6 +893,8 @@ public class TestINIConfiguration
         SubnodeConfiguration sub = config.getSection("section");
         assertFalse("No content", sub.isEmpty());
         sub.clear();
+        sub.close();
+        sub = config.getSection("section");
         sub.setProperty("test", "success");
         StringWriter writer = new StringWriter();
         config.write(writer);
@@ -883,7 +914,7 @@ public class TestINIConfiguration
         INIConfiguration config = setUpConfig(data);
         assertEquals("Wrong value 1", "sec1", config.getString("section.var1"));
         assertEquals("Wrong value 2", "sec2", config.getString("section.var2"));
-        SubnodeConfiguration sub = config.getSection("section");
+        HierarchicalConfiguration<ImmutableNode> sub = config.getSection("section");
         assertEquals("Wrong sub value 1", "sec1", sub.getString("var1"));
         assertEquals("Wrong sub value 2", "sec2", sub.getString("var2"));
         StringWriter writer = new StringWriter();
@@ -904,7 +935,7 @@ public class TestINIConfiguration
             throws ConfigurationException, IOException
     {
         INIConfiguration config = setUpConfig(INI_DATA);
-        SubnodeConfiguration section = config.getSection("newSection");
+        HierarchicalConfiguration<ImmutableNode> section = config.getSection("newSection");
         section.addProperty("test", "success");
         assertEquals("Main config not updated", "success",
                 config.getString("newSection.test"));
@@ -925,7 +956,7 @@ public class TestINIConfiguration
                 new INIConfiguration();
         config.addProperty("section.var1", "value1");
         config.addProperty("section(-1).var2", "value2");
-        SubnodeConfiguration section = config.getSection("section");
+        HierarchicalConfiguration<ImmutableNode> section = config.getSection("section");
         Iterator<String> keys = section.getKeys();
         assertEquals("Wrong key", "var1", keys.next());
         assertFalse("Too many keys", keys.hasNext());
@@ -974,105 +1005,133 @@ public class TestINIConfiguration
     }
 
     /**
-     * Helper method for testing whether the access to a section is
-     * synchronized. This method delegates to the method with the same name
-     * passing in default methods.
-     *
-     * @param sectionName the name of the section to be queried
-     * @throws ConfigurationException if an error occurs
+     * Tests whether the configuration deals correctly with list delimiters.
      */
-    private void checkGetSectionSynchronized(String sectionName)
-            throws ConfigurationException
+    @Test
+    public void testListDelimiterHandling() throws ConfigurationException
     {
-        checkGetSectionSynchronized(sectionName, Methods.BEGIN_WRITE,
-                Methods.END_WRITE);
+        INIConfiguration config = new INIConfiguration();
+        config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
+        config.addProperty("list", "a,b,c");
+        config.addProperty("listesc", "3\\,1415");
+        String output = saveToString(config);
+        INIConfiguration config2 = setUpConfig(output);
+        assertEquals("Wrong list size", 3, config2.getList("list").size());
+        assertEquals("Wrong list element", "b", config2.getList("list").get(1));
+        assertEquals("Wrong escaped list element", "3,1415",
+                config2.getString("listesc"));
     }
 
     /**
-     * Helper method for testing whether the access to a section causes the
-     * specified methods to be called on the synchronizer.
-     *
-     * @param sectionName the name of the section to be queried
-     * @param expMethods the expected methods
-     * @throws ConfigurationException if an error occurs
+     * Tests whether property values are correctly escaped even if they are part
+     * of a property with multiple values.
      */
-    private void checkGetSectionSynchronized(String sectionName,
-            Methods... expMethods) throws ConfigurationException
+    @Test
+    public void testListDelimiterHandlingInList() throws ConfigurationException
     {
-        INIConfiguration config = setUpConfig(INI_DATA);
-        SynchronizerTestImpl sync = new SynchronizerTestImpl();
-        config.setSynchronizer(sync);
-        assertNotNull("No global section", config.getSection(sectionName));
-        sync.verify(expMethods);
+        String data =
+                INI_DATA + "[sectest]" + LINE_SEPARATOR
+                        + "list = 3\\,1415,pi,\\\\Test\\,5" + LINE_SEPARATOR;
+        INIConfiguration config = setUpConfig(data);
+        INIConfiguration config2 = setUpConfig(saveToString(config));
+        List<Object> list = config2.getList("sectest.list");
+        assertEquals("Wrong number of values", 3, list.size());
+        assertEquals("Wrong element 1", "3,1415", list.get(0));
+        assertEquals("Wrong element 3", "\\Test,5", list.get(2));
     }
 
     /**
-     * Tests whether access to the global section is synchronized.
+     * Tests whether only properties with values occur in the enumeration of the
+     * global section.
      */
     @Test
-    public void testGetSectionGlobalSynchronized()
-            throws ConfigurationException
+    public void testKeysOfGlobalSection() throws ConfigurationException
     {
-        checkGetSectionSynchronized(null);
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        HierarchicalConfiguration<ImmutableNode> sub = config.getSection(null);
+        Iterator<String> keys = sub.getKeys();
+        assertEquals("Wrong key", "globalVar", keys.next());
+        if (keys.hasNext())
+        {
+            StringBuilder buf = new StringBuilder();
+            do
+            {
+                buf.append(keys.next()).append(' ');
+            } while (keys.hasNext());
+            fail("Got additional keys: " + buf);
+        }
     }
 
     /**
-     * Tests whether access to an existing section is synchronized.
+     * Tests whether the node handler of a global section correctly filters
+     * named children.
      */
     @Test
-    public void testGetSectionExistingSynchronized()
+    public void testGlobalSectionNodeHandlerGetChildrenByName()
             throws ConfigurationException
     {
-        // 1 x configurationAt(), then direct access to root node
-        checkGetSectionSynchronized("section1");
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        SubnodeConfiguration sub = config.getSection(null);
+        NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
+        assertTrue("Sections not filtered",
+                handler.getChildren(sub.getRootNode(), "section1").isEmpty());
     }
 
     /**
-     * Tests whether access to a non-existing section is synchronized.
+     * Tests whether the node handler of a global section correctly determines
+     * the number of children.
      */
     @Test
-    public void testGetSectionNonExistingSynchronized()
+    public void testGlobalSectionNodeHandlerGetChildrenCount()
             throws ConfigurationException
     {
-        checkGetSectionSynchronized("Non-existing-section?",
-                Methods.BEGIN_WRITE, Methods.END_WRITE, Methods.BEGIN_WRITE,
-                Methods.END_WRITE);
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        SubnodeConfiguration sub = config.getSection(null);
+        NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
+        assertEquals("Wrong number of children", 1,
+                handler.getChildrenCount(handler.getRootNode(), null));
     }
 
     /**
-     * Tests whether the configuration deals correctly with list delimiters.
+     * Tests whether the node handler of a global section correctly returns a
+     * child by index.
      */
     @Test
-    public void testListDelimiterHandling() throws ConfigurationException
+    public void testGlobalSectionNodeHandlerGetChildByIndex()
+            throws ConfigurationException
     {
-        INIConfiguration config = new INIConfiguration();
-        config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
-        config.addProperty("list", "a,b,c");
-        config.addProperty("listesc", "3\\,1415");
-        String output = saveToString(config);
-        INIConfiguration config2 = setUpConfig(output);
-        assertEquals("Wrong list size", 3, config2.getList("list").size());
-        assertEquals("Wrong list element", "b", config2.getList("list").get(1));
-        assertEquals("Wrong escaped list element", "3,1415",
-                config2.getString("listesc"));
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        SubnodeConfiguration sub = config.getSection(null);
+        NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
+        ImmutableNode child = handler.getChild(handler.getRootNode(), 0);
+        assertEquals("Wrong child", "globalVar", child.getNodeName());
+        try
+        {
+            handler.getChild(handler.getRootNode(), 1);
+            fail("Could obtain child with invalid index!");
+        }
+        catch (IndexOutOfBoundsException iex)
+        {
+            // ok
+        }
     }
 
     /**
-     * Tests whether property values are correctly escaped even if they are part
-     * of a property with multiple values.
+     * Tests whether the node handler of a global section correctly determines
+     * the index of a child.
      */
     @Test
-    public void testListDelimiterHandlingInList() throws ConfigurationException
+    public void testGlobalSectionNodeHandlerIndexOfChild()
+            throws ConfigurationException
     {
-        String data =
-                INI_DATA + "[sectest]" + LINE_SEPARATOR
-                        + "list = 3\\,1415,pi,\\\\Test\\,5" + LINE_SEPARATOR;
-        INIConfiguration config = setUpConfig(data);
-        INIConfiguration config2 = setUpConfig(saveToString(config));
-        List<Object> list = config2.getList("sectest.list");
-        assertEquals("Wrong number of values", 3, list.size());
-        assertEquals("Wrong element 1", "3,1415", list.get(0));
-        assertEquals("Wrong element 3", "\\Test,5", list.get(2));
+        INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        SubnodeConfiguration sub = config.getSection(null);
+        NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
+        List<ImmutableNode> children = handler.getRootNode().getChildren();
+        assertEquals("Wrong index", 0,
+                handler.indexOfChild(handler.getRootNode(), children.get(0)));
+        assertEquals("Wrong index of section child", -1,
+                handler.indexOfChild(handler.getRootNode(), children.get(1)));
     }
 
     /**