blob: 0f3e44b2bb731115bcf7d527fb8fe58722413b9b [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.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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.event.ConfigurationEvent;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.event.EventListenerTestImpl;
import org.apache.commons.configuration2.tree.DefaultConfigurationKey;
import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;
import org.apache.commons.configuration2.tree.ExpressionEngine;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.InMemoryNodeModel;
import org.apache.commons.configuration2.tree.NodeHandler;
import org.apache.commons.configuration2.tree.NodeModel;
import org.apache.commons.configuration2.tree.NodeStructureHelper;
import org.junit.Before;
import org.junit.Test;
/**
* Test class for {@code AbstractHierarchicalConfiguration}.
*
*/
public class TestAbstractHierarchicalConfiguration
{
/** The test configuration. */
private AbstractHierarchicalConfiguration<ImmutableNode> config;
@Before
public void setUp() throws Exception
{
final ImmutableNode root =
new ImmutableNode.Builder(1).addChild(
NodeStructureHelper.ROOT_TABLES_TREE).create();
config =
new AbstractHierarchicalConfigurationTestImpl(
new InMemoryNodeModel(root));
}
/**
* Convenience method for obtaining the root node of the test configuration.
*
* @return the root node of the test configuration
*/
private ImmutableNode getRootNode()
{
return config.getModel().getNodeHandler().getRootNode();
}
@Test
public void testIsEmptyFalse()
{
assertFalse(config.isEmpty());
}
/**
* Tests isEmpty() if only the root node exists.
*/
@Test
public void testIsEmptyRootOnly()
{
config =
new AbstractHierarchicalConfigurationTestImpl(
new InMemoryNodeModel());
assertTrue("Not empty", config.isEmpty());
}
/**
* Tests isEmpty() if the structure contains some nodes without values.
*/
@Test
public void testIsEmptyNodesWithNoValues()
{
final ImmutableNode.Builder rootBuilder = new ImmutableNode.Builder(1);
final ImmutableNode.Builder nodeBuilder = new ImmutableNode.Builder(1);
nodeBuilder.addChild(NodeStructureHelper.createNode("child", null));
rootBuilder.addChild(nodeBuilder.create());
config =
new AbstractHierarchicalConfigurationTestImpl(
new InMemoryNodeModel(rootBuilder.create()));
assertTrue("Not empty", config.isEmpty());
}
private static void checkGetProperty(final AbstractHierarchicalConfiguration<?> testConfig)
{
assertNull(testConfig.getProperty("tables.table.resultset"));
assertNull(testConfig.getProperty("tables.table.fields.field"));
Object prop = testConfig.getProperty("tables.table(0).fields.field.name");
assertNotNull(prop);
assertTrue(prop instanceof Collection);
assertEquals(NodeStructureHelper.fieldsLength(0), ((Collection<?>) prop).size());
prop = testConfig.getProperty("tables.table.fields.field.name");
assertNotNull(prop);
assertTrue(prop instanceof Collection);
assertEquals(totalFieldCount(), ((Collection<?>) prop).size());
prop = testConfig.getProperty("tables.table.fields.field(3).name");
assertNotNull(prop);
assertTrue(prop instanceof Collection);
assertEquals(2, ((Collection<?>) prop).size());
prop = testConfig.getProperty("tables.table(1).fields.field(2).name");
assertNotNull(prop);
assertEquals("creationDate", prop.toString());
}
@Test
public void testGetProperty()
{
checkGetProperty(config);
}
@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)", Integer.valueOf(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", Integer.valueOf(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(NodeStructureHelper.fieldsLength(1), ((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++)
{
final 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++)
{
final 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()
{
final List<String> keys = new ArrayList<>();
for (final 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"));
}
/**
* Tests whether keys are returned in a defined order.
*/
@Test
public void testGetKeysOrder()
{
config.addProperty("order.key1", "value1");
config.addProperty("order.key2", "value2");
config.addProperty("order.key3", "value3");
final 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());
}
/**
* Tests whether attribute keys are contained in the iteration of keys.
*/
@Test
public void testGetKeysAttribute()
{
config.addProperty("tables.table(0)[@type]", "system");
final Set<String> keys = new HashSet<>();
for (final Iterator<String> it = config.getKeys(); it.hasNext();)
{
keys.add(it.next());
}
assertTrue("Attribute key not found: " + keys, keys.contains("tables.table[@type]"));
}
/**
* Tests whether a prefix that points to an attribute is correctly handled.
*/
@Test
public void testGetKeysAttributePrefix()
{
config.addProperty("tables.table(0)[@type]", "system");
final Iterator<String> itKeys = config.getKeys("tables.table[@type]");
assertEquals("Wrong key", "tables.table[@type]", itKeys.next());
assertFalse("Too many keys", itKeys.hasNext());
}
@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");
final 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");
final 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());
}
/**
* Tests whether the correct size is calculated.
*/
@Test
public void testSize()
{
assertEquals("Wrong size", 2, config.size());
}
@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);
final 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"));
final DefaultConfigurationKey key = createConfigurationKey();
key.append("tables").append("table").appendIndex(0);
key.appendAttribute("tableType");
config.addProperty(key.toString(), "system");
assertEquals("system", config.getProperty(key.toString()));
}
/**
* Creates a {@code DefaultConfigurationKey} object.
*
* @return the new key object
*/
private static DefaultConfigurationKey createConfigurationKey()
{
return new DefaultConfigurationKey(DefaultExpressionEngine.INSTANCE);
}
@Test(expected = IllegalArgumentException.class)
public void testAddPropertyInvalidKey()
{
config.addProperty(".", "InvalidKey");
}
@Test
public void testGetMaxIndex()
{
assertEquals(NodeStructureHelper.fieldsLength(0) - 1,
config.getMaxIndex("tables.table(0).fields.field"));
assertEquals(NodeStructureHelper.fieldsLength(1) - 1,
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"));
final int maxIdx = config.getMaxIndex("tables.table(0).fields.field.name");
for(int i = 0; i <= maxIdx; i++)
{
final 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 testClone()
{
final Configuration copy = (Configuration) config.clone();
assertTrue("Wrong clone result", copy instanceof AbstractHierarchicalConfiguration);
checkContent(copy);
}
/**
* Tests whether registered event handlers are handled correctly when a
* configuration is cloned. They should not be registered at the clone.
*/
@Test
public void testCloneWithEventListeners()
{
final EventListener<ConfigurationEvent> l = new EventListenerTestImpl(null);
config.addEventListener(ConfigurationEvent.ANY, l);
final AbstractHierarchicalConfiguration<?> copy =
(AbstractHierarchicalConfiguration<?>) config.clone();
assertFalse("Event listener registered at clone", copy
.getEventListeners(ConfigurationEvent.ANY).contains(l));
}
/**
* Tests whether interpolation works as expected after cloning.
*/
@Test
public void testCloneInterpolation()
{
final String keyAnswer = "answer";
final String keyValue = "value";
config.addProperty(keyAnswer, "The answer is ${" + keyValue + "}.");
config.addProperty(keyValue, 42);
final Configuration clone = (Configuration) 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()
{
final Collection<ImmutableNode> nodes = new ArrayList<>();
nodes.add(NodeStructureHelper.createFieldNode("birthDate"));
nodes.add(NodeStructureHelper.createFieldNode("lastLogin"));
nodes.add(NodeStructureHelper.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"));
}
/**
* Tests the addNodes() method if the provided key does not exist. In
* this case, a new node (or even a completely new branch) is created.
*/
@Test
public void testAddNodesForNonExistingKey()
{
final Collection<ImmutableNode> nodes = new ArrayList<>();
final ImmutableNode newNode =
new ImmutableNode.Builder().name("usr").value("scott")
.addAttribute("pwd", "tiger").create();
nodes.add(newNode);
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.usr[@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()
{
final Collection<ImmutableNode> nodes = new ArrayList<>();
nodes.add(NodeStructureHelper.createNode("testNode", "yes"));
config.addNodes("database.connection[@settings]", nodes);
}
/**
* Tests copying nodes from one configuration to another one.
*/
@Test
public void testAddNodesCopy()
{
final AbstractHierarchicalConfigurationTestImpl configDest =
new AbstractHierarchicalConfigurationTestImpl(
new InMemoryNodeModel());
configDest.addProperty("test", "TEST");
final Collection<ImmutableNode> nodes = getRootNode().getChildren();
assertEquals("Wrong number of children", 1, nodes.size());
configDest.addNodes("newNodes", nodes);
for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
{
final String keyTab = "newNodes.tables.table(" + i + ").";
assertEquals("Table " + i + " not found",
NodeStructureHelper.table(i),
configDest.getString(keyTab + "name"));
for (int j = 0; j < NodeStructureHelper.fieldsLength(i); j++)
{
assertEquals(
"Invalid field " + j + " in table " + i,
NodeStructureHelper.field(i, j),
configDest.getString(keyTab + "fields.field(" + j
+ ").name"));
}
}
}
/**
* Tests setting a custom expression engine, which uses a slightly different
* syntax.
*/
@Test
public void testSetExpressionEngine()
{
config.setExpressionEngine(null);
assertNotNull("Expression engine is null", config.getExpressionEngine());
assertSame("Default engine is not used",
DefaultExpressionEngine.INSTANCE, config.getExpressionEngine());
config.setExpressionEngine(createAlternativeExpressionEngine());
checkAlternativeSyntax();
}
/**
* 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");
final 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
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}");
final Configuration sub1 = config.subset("prop2");
final Configuration sub2 = sub1.subset("prop");
assertEquals("Wrong value", "value", sub2.getString("[@attr]"));
}
/**
* Tests interpolation of a variable, which cannot be resolved.
*/
@Test
public void testInterpolationUnknownProperty()
{
InterpolationTestHelper.testInterpolationUnknownProperty(config);
}
/**
* Tests interpolation with system properties.
*/
@Test
public void testInterpolationSystemProperties()
{
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 interpolation with localhost values.
*/
@Test
public void testInterpolationLocalhost()
{
InterpolationTestHelper.testInterpolationLocalhost(config);
}
/**
* Tests manipulating the interpolator.
*/
@Test
public void testInterpolator()
{
InterpolationTestHelper.testGetInterpolator(config);
}
/**
* Tests obtaining a configuration with all variables substituted.
*/
@Test
public void testInterpolatedConfiguration()
{
config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
final AbstractHierarchicalConfiguration<?> c = (AbstractHierarchicalConfiguration<?>) InterpolationTestHelper
.testInterpolatedConfiguration(config);
// tests whether the hierarchical structure has been maintained
checkGetProperty(c);
}
/**
* Tests the copy constructor when a null reference is passed.
*/
@Test
public void testInitCopyNull()
{
final BaseHierarchicalConfiguration copy =
new BaseHierarchicalConfiguration(
(BaseHierarchicalConfiguration) null);
assertTrue("Configuration not empty", copy.isEmpty());
}
/**
* Tests whether keys that contains brackets can be used.
*/
@Test
public void testGetPropertyKeyWithBrackets()
{
final String key = "test.directory.platform(x86)";
config.addProperty(key, "C:\\Temp");
assertEquals("Wrong property value", "C:\\Temp", config.getString(key));
}
/**
* Tests whether list handling works correctly when adding properties.
*/
@Test
public void testAddPropertyWithListHandling()
{
config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
final String key = "list.delimiter.value";
config.addProperty(key + ".escaped", "3\\,1415");
config.addProperty(key + ".elements", "3,1415");
assertEquals("Wrong escaped property", "3,1415", config.getString(key + ".escaped"));
assertEquals("Wrong list property", "3", config.getString(key + ".elements"));
}
/**
* Tests whether node keys can be resolved.
*/
@Test
public void testResolveNodeKey()
{
final List<ImmutableNode> nodes =
config.resolveNodeKey(getRootNode(),
"tables.table.name", config.getModel().getNodeHandler());
assertEquals("Wrong number of nodes",
NodeStructureHelper.tablesLength(), nodes.size());
for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
{
assertEquals("Wrong node value at " + i,
NodeStructureHelper.table(i), nodes.get(i).getValue());
}
}
/**
* Tests whether attribute keys are filtered out when resolving node keys.
*/
@Test
public void testResolveNodeKeyAttribute()
{
final String attrKey = "tables.table(0)[@type]";
config.addProperty(attrKey, "system");
assertTrue(
"Got attribute results",
config.resolveNodeKey(getRootNode(), attrKey,
config.getModel().getNodeHandler()).isEmpty());
}
/**
* Tests whether a correct node key is generated if no data is contained in
* the cache.
*/
@Test
public void testNodeKeyEmptyCache()
{
final Map<ImmutableNode, String> cache = new HashMap<>();
final ImmutableNode nodeTabName =
NodeStructureHelper.nodeForKey(getRootNode(),
"tables/table(0)/name");
final ImmutableNode nodeFldName =
NodeStructureHelper.nodeForKey(getRootNode(),
"tables/table(0)/fields/field(1)/name");
assertEquals("Wrong key (1)", "tables(0).table(0).name(0)",
config.nodeKey(nodeTabName, cache, config.getModel()
.getNodeHandler()));
assertEquals("Wrong key (2)",
"tables(0).table(0).fields(0).field(1).name(0)",
config.nodeKey(nodeFldName, cache, config.getModel()
.getNodeHandler()));
}
/**
* Tests whether the cache map is filled while generating node keys.
*/
@Test
public void testNodeKeyCachePopulated()
{
final Map<ImmutableNode, String> cache = new HashMap<>();
final ImmutableNode nodeTabName =
NodeStructureHelper.nodeForKey(getRootNode(),
"tables/table(0)/name");
final NodeHandler<ImmutableNode> handler = config.getModel().getNodeHandler();
config.nodeKey(nodeTabName, cache, handler);
assertEquals("Wrong number of elements", 4, cache.size());
assertEquals("Wrong entry (1)", "tables(0).table(0).name(0)",
cache.get(nodeTabName));
assertEquals("Wrong entry (2)", "tables(0).table(0)",
cache.get(handler.getParent(nodeTabName)));
assertEquals("Wrong entry (3)", "tables(0)",
cache.get(handler.getParent(handler.getParent(nodeTabName))));
assertEquals("Wrong root entry", "", cache.get(getRootNode()));
}
/**
* Tests whether the cache is used by nodeKey().
*/
@Test
public void testNodeKeyCacheUsage()
{
final Map<ImmutableNode, String> cache = new HashMap<>();
final ImmutableNode nodeTabName =
NodeStructureHelper.nodeForKey(getRootNode(),
"tables/table(0)/name");
final NodeHandler<ImmutableNode> handler = config.getModel().getNodeHandler();
cache.put(handler.getParent(nodeTabName), "somePrefix");
assertEquals("Wrong key", "somePrefix.name(0)",
config.nodeKey(nodeTabName, cache, handler));
}
/**
* Tests whether a node key for the root node can be generated.
*/
@Test
public void testNodeKeyRootNode()
{
final Map<ImmutableNode, String> cache = new HashMap<>();
assertEquals("Wrong root node key", "",
config.nodeKey(getRootNode(), cache, config.getModel()
.getNodeHandler()));
}
/**
* Tests nodeKey() if the key is directly found in the cache.
*/
@Test
public void testNodeKeyCacheHit()
{
final Map<ImmutableNode, String> cache = new HashMap<>();
final String key = "someResultKey";
cache.put(getRootNode(), key);
assertEquals("Wrong result", key, config.nodeKey(getRootNode(),
cache, config.getModel().getNodeHandler()));
}
/**
* Tests whether the configuration's node model can be correctly accessed.
*/
@Test
public void testGetNodeModel()
{
final SynchronizerTestImpl sync = new SynchronizerTestImpl();
config.setSynchronizer(sync);
final NodeModel<ImmutableNode> model = config.getNodeModel();
assertTrue("Wrong node model: " + model,
model instanceof InMemoryNodeModel);
final ImmutableNode rootNode = model.getNodeHandler().getRootNode();
assertEquals("Wrong number of children of root node", 1, rootNode
.getChildren().size());
assertTrue("Wrong children of root node", rootNode.getChildren()
.contains(NodeStructureHelper.ROOT_TABLES_TREE));
sync.verify(SynchronizerTestImpl.Methods.BEGIN_READ,
SynchronizerTestImpl.Methods.END_READ);
}
/**
* Helper method for testing the getKeys(String) method.
*
* @param prefix the key to pass into getKeys()
* @param expected the expected result
*/
private void checkKeys(final String prefix, final String[] expected)
{
final Set<String> values = new HashSet<>();
for (final String anExpected : expected) {
values.add(anExpected.startsWith(prefix) ? anExpected : prefix + "." + anExpected);
}
final Iterator<String> itKeys = config.getKeys(prefix);
while(itKeys.hasNext())
{
final 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()
{
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(NodeStructureHelper.fieldsLength(0), ((Collection<?>) prop).size());
prop = config.getProperty("tables/table/fields/field/name");
assertNotNull(prop);
assertTrue(prop instanceof Collection);
assertEquals(totalFieldCount(), ((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());
final Set<String> keys = ConfigurationAssert.keysToSet(config);
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"));
}
/**
* Returns the total number of fields in the test data structure.
*
* @return the total number of fields
*/
private static int totalFieldCount()
{
int fieldCount = 0;
for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
{
fieldCount += NodeStructureHelper.fieldsLength(i);
}
return fieldCount;
}
/**
* Checks the content of the passed in configuration object. Used by some
* tests that copy a configuration.
*
* @param c the configuration to check
*/
private static void checkContent(final 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"));
}
}
}
private ExpressionEngine createAlternativeExpressionEngine()
{
return new DefaultExpressionEngine(
new DefaultExpressionEngineSymbols.Builder(
DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
.setPropertyDelimiter("/").setIndexStart("[")
.setIndexEnd("]").create());
}
/**
* A concrete test implementation of
* {@code AbstractHierarchicalConfiguration}.
*/
private static class AbstractHierarchicalConfigurationTestImpl extends
AbstractHierarchicalConfiguration<ImmutableNode>
{
public AbstractHierarchicalConfigurationTestImpl(final InMemoryNodeModel model)
{
super(model);
}
@Override
protected NodeModel<ImmutableNode> cloneNodeModel()
{
return new InMemoryNodeModel(getModel().getNodeHandler().getRootNode());
}
@Override
public SubnodeConfiguration configurationAt(final String key,
final boolean supportUpdates)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public SubnodeConfiguration configurationAt(final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(final String key, final boolean supportUpdates) {
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<HierarchicalConfiguration<ImmutableNode>> childConfigurationsAt(final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<HierarchicalConfiguration<ImmutableNode>> childConfigurationsAt(final String key, final boolean supportUpdates) {
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public ImmutableHierarchicalConfiguration immutableConfigurationAt(
final String key, final boolean supportUpdates)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public ImmutableHierarchicalConfiguration immutableConfigurationAt(
final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<ImmutableHierarchicalConfiguration> immutableConfigurationsAt(
final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
@Override
public List<ImmutableHierarchicalConfiguration> immutableChildConfigurationsAt(
final String key)
{
throw new UnsupportedOperationException("Unexpected method call!");
}
}
}