blob: 4d9ba32bf53894d9a842b63a33b6f8e0fad6d802 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.configuration2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.List;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
import org.apache.commons.configuration2.tree.DefaultConfigurationKey;
import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.NodeStructureHelper;
import org.junit.Before;
import org.junit.Test;
/**
* Test class for {@code BaseHierarchicalConfiguration}.
*
* @version $Id$
*/
public class TestHierarchicalConfiguration
{
/** 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();
config.getNodeModel().setRootNode(root);
}
/**
* Creates a {@code DefaultConfigurationKey} object.
*
* @return the new key object
*/
private static DefaultConfigurationKey createConfigurationKey()
{
return new DefaultConfigurationKey(DefaultExpressionEngine.INSTANCE);
}
@Test
public void testSubset()
{
// test the subset on the first table
Configuration subset = config.subset("tables.table(0)");
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 < NodeStructureHelper.fieldsLength(0); i++)
{
DefaultConfigurationKey key = createConfigurationKey();
key.append("fields").append("field").appendIndex(i);
key.append("name");
assertEquals(NodeStructureHelper.field(0, i), subset.getProperty(key.toString()));
}
// test the subset on the second table
assertTrue("subset is not empty", config.subset("tables.table(2)").isEmpty());
// test the subset on the fields
subset = config.subset("tables.table.fields.field");
prop = subset.getProperty("name");
assertTrue("prop is not a collection", prop instanceof Collection);
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(NodeStructureHelper.field(0, 0), subset.getProperty("name(0)"));
// test the subset on the field names
subset = config.subset("tables.table.fields.field.name");
assertTrue("subset is not empty", subset.isEmpty());
}
/**
* 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
public void testSubsetNodeWithValue()
{
config.setProperty("tables.table(0).fields", "My fields");
Configuration subset = config.subset("tables.table(0).fields");
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 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.
*/
@Test
public void testSubsetMultipleNodesWithValues()
{
config.setProperty("tables.table(0).fields", "My fields");
Configuration subset = config.subset("tables.table.fields");
assertEquals("Wrong value of root", "My fields", subset.getString(""));
config.setProperty("tables.table(1).fields", "My other fields");
subset = config.subset("tables.table.fields");
assertNull("Root value is not null though there are multiple values",
subset.getString(""));
}
/**
* Tests subset() if the passed in key selects an attribute.
*/
@Test
public void testSubsetAttributeResult()
{
String key = "tables.table(0)[@type]";
config.addProperty(key, "system");
BaseHierarchicalConfiguration subset =
(BaseHierarchicalConfiguration) config.subset(key);
assertTrue("Got children of root node", subset.getModel()
.getNodeHandler().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",
NodeStructureHelper.fieldsLength(1), lstFlds.size());
for (int i = 0; i < NodeStructureHelper.fieldsLength(1); 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("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 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"));
}
/**
* Tests whether an immutable configuration for a sub tree can be obtained.
*/
@Test
public void testImmutableConfigurationAt()
{
ImmutableHierarchicalConfiguration subConfig =
config.immutableConfigurationAt("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",
NodeStructureHelper.fieldsLength(1), lstFlds.size());
for (int i = 0; i < NodeStructureHelper.fieldsLength(1); i++)
{
assertEquals("Wrong field at position " + i,
NodeStructureHelper.field(1, i), lstFlds.get(i));
}
}
/**
* Tests whether the support updates flag is taken into account when
* creating an immutable sub configuration.
*/
@Test
public void testImmutableConfigurationAtSupportUpdates()
{
String newTableName = NodeStructureHelper.table(1) + "_other";
ImmutableHierarchicalConfiguration subConfig =
config.immutableConfigurationAt("tables.table(1)", true);
config.addProperty("tables.table(-1).name", newTableName);
config.clearTree("tables.table(1)");
assertEquals("Name not updated", newTableName,
subConfig.getString("name"));
}
/**
* Tests the configurationAt() method if the passed in key does not exist.
*/
@Test(expected = ConfigurationRuntimeException.class)
public void testConfigurationAtUnknownSubTree()
{
config.configurationAt("non.existing.key");
}
/**
* 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 = ConfigurationRuntimeException.class)
public void testConfigurationAtMultipleNodes()
{
config.configurationAt("tables.table.name");
}
/**
* Tests configurationAt() if the passed in key selects multiple nodes and the
* update flag is set.
*/
@Test(expected = ConfigurationRuntimeException.class)
public void testConfigurationAtMultipleNodesWithUpdates()
{
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);
}
/**
* Tests whether a {@code SubnodeConfiguration} can be cleared and its root
* node can be removed from its parent configuration.
*/
@Test
public void testConfigurationAtClearAndDetach()
{
config.addProperty("test.sub.test", "success");
config.addProperty("test.other", "check");
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!");
assertNull("Node not detached", config.getString("test.sub.test"));
}
/**
* Helper method for checking a list of sub configurations pointing to the
* single fields of the table configuration.
*
* @param lstFlds the list with sub configurations
*/
private void checkSubConfigurations(
List<? extends ImmutableConfiguration> lstFlds)
{
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,
NodeStructureHelper.field(1, i), sub.getString("name"));
}
}
/**
* 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
*/
private void checkConfigurationsAtWithUpdate(boolean withUpdates,
String expName)
{
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 if the sub configurations are not
* connected..
*/
@Test
public void testConfigurationsAtNoUpdate()
{
checkConfigurationsAtWithUpdate(false, NodeStructureHelper.field(1, 0));
}
/**
* Tests configurationsAt() if the sub configurations are connected.
*/
@Test
public void testConfigurationsAtWithUpdates()
{
checkConfigurationsAtWithUpdate(true, NEW_NAME);
}
/**
* Tests whether a connected configuration is correctly initialized with
* properties of its parent.
*/
@Test
public void testConfigurationAtWithUpdateInitialized()
{
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 whether a list of immutable sub configurations can be queried.
*/
@Test
public void testImmutableConfigurationsAt()
{
List<ImmutableHierarchicalConfiguration> lstFlds =
config.immutableConfigurationsAt("tables.table(1).fields.field");
checkSubConfigurations(lstFlds);
}
/**
* Tests the configurationsAt() method when the passed in key does not
* select any sub nodes.
*/
@Test
public void testConfigurationsAtEmpty()
{
assertTrue("List is not empty", config.configurationsAt("unknown.key")
.isEmpty());
}
/**
* Tests configurationsAt() if an attribute key is passed in.
*/
@Test
public void testConfigurationsAtAttributeKey()
{
String attrKey = "tables.table(0)[@type]";
config.addProperty(attrKey, "user");
assertTrue("Got configurations", config.configurationsAt(attrKey).isEmpty());
}
@Test
public void testClone()
{
Configuration copy = (Configuration) config.clone();
assertTrue(copy instanceof BaseHierarchicalConfiguration);
config.setProperty("tables.table(0).name", "changed table name");
checkContent(copy);
}
/**
* Tests the copy constructor.
*/
@Test
public void testInitCopy()
{
BaseHierarchicalConfiguration copy = new BaseHierarchicalConfiguration(config);
checkContent(copy);
}
/**
* Tests whether the nodes of a copied configuration are independent from
* the source configuration.
*/
@Test
public void testInitCopyUpdate()
{
BaseHierarchicalConfiguration copy = new BaseHierarchicalConfiguration(config);
config.setProperty("tables.table(0).name", "NewTable");
checkContent(copy);
}
/**
* Tests interpolation with a subset.
*/
@Test
public void testInterpolationSubset()
{
InterpolationTestHelper.testInterpolationSubset(config);
}
/**
* Tests whether interpolation with a subset configuration works over
* multiple layers.
*/
@Test
public void testInterpolationSubsetMultipleLayers()
{
config.clear();
config.addProperty("var", "value");
config.addProperty("prop2.prop[@attr]", "${var}");
Configuration sub1 = config.subset("prop2");
Configuration sub2 = sub1.subset("prop");
assertEquals("Wrong value", "value", sub2.getString("[@attr]"));
}
/**
* Tests obtaining a configuration with all variables substituted.
*/
@Test
public void testInterpolatedConfiguration()
{
config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
BaseHierarchicalConfiguration c = (BaseHierarchicalConfiguration) InterpolationTestHelper
.testInterpolatedConfiguration(config);
// tests whether the hierarchical structure has been maintained
checkContent(c);
}
/**
* Tests whether interpolation works on an empty configuration.
*/
@Test
public void testInterpolatedConfigurationEmpty()
{
config = new BaseHierarchicalConfiguration();
assertTrue("Got content", config.interpolatedConfiguration().isEmpty());
}
/**
* Tests the copy constructor when a null reference is passed.
*/
@Test
public void testInitCopyNull()
{
BaseHierarchicalConfiguration copy =
new BaseHierarchicalConfiguration(
(HierarchicalConfiguration<ImmutableNode>) null);
assertTrue("Configuration not empty", copy.isEmpty());
}
/**
* Tests whether immutable configurations for the children of a given node
* can be queried.
*/
@Test
public void testImmutableChildConfigurationsAt()
{
List<ImmutableHierarchicalConfiguration> children =
config.immutableChildConfigurationsAt("tables.table(0)");
assertEquals("Wrong number of elements", 2, children.size());
ImmutableHierarchicalConfiguration c1 = children.get(0);
assertEquals("Wrong name (1)", "name", c1.getRootElementName());
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", NodeStructureHelper.field(0, 0),
c2.getString("field(0).name"));
}
/**
* 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
*/
private void checkChildConfigurationsAtWithUpdates(boolean withUpdates,
String expectedName)
{
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());
HierarchicalConfiguration<ImmutableNode> sub = children.get(0);
sub.setProperty(null, NEW_NAME);
assertEquals("Wrong value in parent", expectedName,
config.getString(key + ".name"));
}
/**
* Tests whether sub configurations for the children of a given node can be
* queried if no updates are propagated.
*/
@Test
public void testChildConfigurationsAtNoUpdates()
{
checkChildConfigurationsAtWithUpdates(false,
NodeStructureHelper.table(0));
}
/**
* Tests whether sub configurations for the children of a given node can be
* queried that support updates.
*/
@Test
public void testChildConfigurationsAtWithUpdates()
{
checkChildConfigurationsAtWithUpdates(true, NEW_NAME);
}
/**
* Tests the result of childConfigurationsAt() if the key selects multiple
* nodes.
*/
@Test
public void testChildConfigurationsAtNoUniqueKey()
{
assertTrue("Got children", config.childConfigurationsAt("tables.table")
.isEmpty());
}
/**
* Tests the result of childConfigurationsAt() if the key does not point to
* an existing node.
*/
@Test
public void testChildConfigurationsAtNotFound()
{
assertTrue("Got children",
config.childConfigurationsAt("not.existing.key").isEmpty());
}
/**
* Checks the content of the passed in configuration object. Used by some
* tests that copy a configuration.
*
* @param c the configuration to check
*/
private void checkContent(Configuration c)
{
for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
{
assertEquals(NodeStructureHelper.table(i),
c.getString("tables.table(" + i + ").name"));
for (int j = 0; j < NodeStructureHelper.fieldsLength(i); j++)
{
assertEquals(
NodeStructureHelper.field(i, j),
c.getString("tables.table(" + i + ").fields.field(" + j
+ ").name"));
}
}
}
}