001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.configuration;
018:
019: import java.util.HashSet;
020: import java.util.List;
021: import java.util.NoSuchElementException;
022: import java.util.Set;
023:
024: import org.apache.commons.collections.CollectionUtils;
025: import org.apache.commons.configuration.tree.ConfigurationNode;
026: import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
027:
028: import junit.framework.TestCase;
029:
030: /**
031: * Test case for SubnodeConfiguration.
032: *
033: * @author Oliver Heger
034: * @version $Id: TestSubnodeConfiguration.java 481592 2006-12-02 18:20:43Z oheger $
035: */
036: public class TestSubnodeConfiguration extends TestCase {
037: /** An array with names of tables (test data). */
038: private static final String[] TABLE_NAMES = { "documents", "users" };
039:
040: /** An array with the fields of the test tables (test data). */
041: private static final String[][] TABLE_FIELDS = {
042: { "docid", "docname", "author", "dateOfCreation",
043: "version", "size" },
044: { "userid", "uname", "firstName", "lastName" } };
045:
046: /** The parent configuration. */
047: HierarchicalConfiguration parent;
048:
049: /** The subnode configuration to be tested. */
050: SubnodeConfiguration config;
051:
052: /** Stores the root node of the subnode config. */
053: ConfigurationNode subnode;
054:
055: /** Stores a counter for the created nodes. */
056: int nodeCounter;
057:
058: protected void setUp() throws Exception {
059: super .setUp();
060: parent = setUpParentConfig();
061: nodeCounter = 0;
062: }
063:
064: /**
065: * Tests creation of a subnode config.
066: */
067: public void testInitSubNodeConfig() {
068: setUpSubnodeConfig();
069: assertSame("Wrong root node in subnode",
070: getSubnodeRoot(parent), config.getRoot());
071: assertSame("Wrong parent config", parent, config.getParent());
072: }
073:
074: /**
075: * Tests constructing a subnode configuration with a null parent. This
076: * should cause an exception.
077: */
078: public void testInitSubNodeConfigWithNullParent() {
079: try {
080: config = new SubnodeConfiguration(null,
081: getSubnodeRoot(parent));
082: fail("Could set a null parent config!");
083: } catch (IllegalArgumentException iex) {
084: // ok
085: }
086: }
087:
088: /**
089: * Tests constructing a subnode configuration with a null root node. This
090: * should cause an exception.
091: */
092: public void testInitSubNodeConfigWithNullNode() {
093: try {
094: config = new SubnodeConfiguration(parent, null);
095: fail("Could set a null root node!");
096: } catch (IllegalArgumentException iex) {
097: // ok
098: }
099: }
100:
101: /**
102: * Tests if properties of the sub node can be accessed.
103: */
104: public void testGetProperties() {
105: setUpSubnodeConfig();
106: assertEquals("Wrong table name", TABLE_NAMES[0], config
107: .getString("name"));
108: List fields = config.getList("fields.field.name");
109: assertEquals("Wrong number of fields", TABLE_FIELDS[0].length,
110: fields.size());
111: for (int i = 0; i < TABLE_FIELDS[0].length; i++) {
112: assertEquals("Wrong field at position " + i,
113: TABLE_FIELDS[0][i], fields.get(i));
114: }
115: }
116:
117: /**
118: * Tests setting of properties in both the parent and the subnode
119: * configuration and whether the changes are visible to each other.
120: */
121: public void testSetProperty() {
122: setUpSubnodeConfig();
123: config.setProperty(null, "testTable");
124: config.setProperty("name", TABLE_NAMES[0] + "_tested");
125: assertEquals("Root value was not set", "testTable", parent
126: .getString("tables.table(0)"));
127: assertEquals("Table name was not changed", TABLE_NAMES[0]
128: + "_tested", parent.getString("tables.table(0).name"));
129:
130: parent.setProperty("tables.table(0).fields.field(1).name",
131: "testField");
132: assertEquals("Field name was not changed", "testField", config
133: .getString("fields.field(1).name"));
134: }
135:
136: /**
137: * Tests adding of properties.
138: */
139: public void testAddProperty() {
140: setUpSubnodeConfig();
141: config.addProperty("[@table-type]", "test");
142: assertEquals("parent.createNode() was not called", 1,
143: nodeCounter);
144: assertEquals("Attribute not set", "test", parent
145: .getString("tables.table(0)[@table-type]"));
146:
147: parent.addProperty("tables.table(0).fields.field(-1).name",
148: "newField");
149: List fields = config.getList("fields.field.name");
150: assertEquals("New field was not added",
151: TABLE_FIELDS[0].length + 1, fields.size());
152: assertEquals("Wrong last field", "newField", fields.get(fields
153: .size() - 1));
154: }
155:
156: /**
157: * Tests listing the defined keys.
158: */
159: public void testGetKeys() {
160: setUpSubnodeConfig();
161: Set keys = new HashSet();
162: CollectionUtils.addAll(keys, config.getKeys());
163: assertEquals("Incorrect number of keys", 2, keys.size());
164: assertTrue("Key 1 not contained", keys.contains("name"));
165: assertTrue("Key 2 not contained", keys
166: .contains("fields.field.name"));
167: }
168:
169: /**
170: * Tests setting the exception on missing flag. The subnode config obtains
171: * this flag from its parent.
172: */
173: public void testSetThrowExceptionOnMissing() {
174: parent.setThrowExceptionOnMissing(true);
175: setUpSubnodeConfig();
176: assertTrue("Exception flag not fetchted from parent", config
177: .isThrowExceptionOnMissing());
178: try {
179: config.getString("non existing key");
180: fail("Could fetch non existing key!");
181: } catch (NoSuchElementException nex) {
182: // ok
183: }
184:
185: config.setThrowExceptionOnMissing(false);
186: assertTrue("Exception flag reset on parent", parent
187: .isThrowExceptionOnMissing());
188: }
189:
190: /**
191: * Tests handling of the delimiter parsing disabled flag. This is shared
192: * with the parent, too.
193: */
194: public void testSetDelimiterParsingDisabled() {
195: parent.setDelimiterParsingDisabled(true);
196: setUpSubnodeConfig();
197: parent.setDelimiterParsingDisabled(false);
198: assertTrue(
199: "Delimiter parsing flag was not received from parent",
200: config.isDelimiterParsingDisabled());
201: config.addProperty("newProp", "test1,test2,test3");
202: assertEquals("New property was splitted", "test1,test2,test3",
203: parent.getString("tables.table(0).newProp"));
204: parent.setDelimiterParsingDisabled(true);
205: config.setDelimiterParsingDisabled(false);
206: assertTrue("Delimiter parsing flag was reset on parent", parent
207: .isDelimiterParsingDisabled());
208: }
209:
210: /**
211: * Tests manipulating the list delimiter. This piece of data is derived from
212: * the parent.
213: */
214: public void testSetListDelimiter() {
215: parent.setListDelimiter('/');
216: setUpSubnodeConfig();
217: parent.setListDelimiter(';');
218: assertEquals("List delimiter not obtained from parent", '/',
219: config.getListDelimiter());
220: config.addProperty("newProp", "test1,test2/test3");
221: assertEquals("List was incorrectly splitted", "test1,test2",
222: parent.getString("tables.table(0).newProp"));
223: config.setListDelimiter(',');
224: assertEquals("List delimiter changed on parent", ';', parent
225: .getListDelimiter());
226: }
227:
228: /**
229: * Tests changing the expression engine.
230: */
231: public void testSetExpressionEngine() {
232: parent.setExpressionEngine(new XPathExpressionEngine());
233: setUpSubnodeConfig();
234: assertEquals("Wrong field name", TABLE_FIELDS[0][1], config
235: .getString("fields/field[2]/name"));
236: Set keys = new HashSet();
237: CollectionUtils.addAll(keys, config.getKeys());
238: assertEquals("Wrong number of keys", 2, keys.size());
239: assertTrue("Key 1 not contained", keys.contains("name"));
240: assertTrue("Key 2 not contained", keys
241: .contains("fields/field/name"));
242: config.setExpressionEngine(null);
243: assertTrue("Expression engine reset on parent", parent
244: .getExpressionEngine() instanceof XPathExpressionEngine);
245: }
246:
247: /**
248: * Tests the configurationAt() method.
249: */
250: public void testConfiguarationAt() {
251: setUpSubnodeConfig();
252: SubnodeConfiguration sub2 = (SubnodeConfiguration) config
253: .configurationAt("fields.field(1)");
254: assertEquals("Wrong value of property", TABLE_FIELDS[0][1],
255: sub2.getString("name"));
256: assertEquals("Wrong parent", config.getParent(), sub2
257: .getParent());
258: }
259:
260: /**
261: * Tests interpolation features. The subnode config should use its parent
262: * for interpolation.
263: */
264: public void testInterpolation() {
265: parent.addProperty("tablespaces.tablespace.name", "default");
266: parent.addProperty("tablespaces.tablespace(-1).name", "test");
267: parent.addProperty("tables.table(0).tablespace",
268: "${tablespaces.tablespace(0).name}");
269: assertEquals("Wrong interpolated tablespace", "default", parent
270: .getString("tables.table(0).tablespace"));
271:
272: setUpSubnodeConfig();
273: assertEquals("Wrong interpolated tablespace in subnode",
274: "default", config.getString("tablespace"));
275: }
276:
277: /**
278: * An additional test for interpolation when the configurationAt() method is
279: * involved.
280: */
281: public void testInterpolationFromConfigurationAt() {
282: parent.addProperty("base.dir", "/home/foo");
283: parent.addProperty("test.absolute.dir.dir1",
284: "${base.dir}/path1");
285: parent.addProperty("test.absolute.dir.dir2",
286: "${base.dir}/path2");
287: parent.addProperty("test.absolute.dir.dir3",
288: "${base.dir}/path3");
289:
290: Configuration sub = parent.configurationAt("test.absolute.dir");
291: for (int i = 1; i < 4; i++) {
292: assertEquals("Wrong interpolation in parent",
293: "/home/foo/path" + i, parent
294: .getString("test.absolute.dir.dir" + i));
295: assertEquals("Wrong interpolation in subnode",
296: "/home/foo/path" + i, sub.getString("dir" + i));
297: }
298: }
299:
300: /**
301: * Initializes the parent configuration. This method creates the typical
302: * structure of tables and fields nodes.
303: *
304: * @return the parent configuration
305: */
306: protected HierarchicalConfiguration setUpParentConfig() {
307: HierarchicalConfiguration conf = new HierarchicalConfiguration() {
308: // Provide a special implementation of createNode() to check
309: // if it is called by the subnode config
310: protected Node createNode(String name) {
311: nodeCounter++;
312: return super .createNode(name);
313: }
314: };
315: for (int i = 0; i < TABLE_NAMES.length; i++) {
316: conf.addProperty("tables.table(-1).name", TABLE_NAMES[i]);
317: for (int j = 0; j < TABLE_FIELDS[i].length; j++) {
318: conf.addProperty("tables.table.fields.field(-1).name",
319: TABLE_FIELDS[i][j]);
320: }
321: }
322: return conf;
323: }
324:
325: /**
326: * Returns the root node for the subnode config. This method returns the
327: * first table node.
328: *
329: * @param conf the parent config
330: * @return the root node for the subnode config
331: */
332: protected ConfigurationNode getSubnodeRoot(
333: HierarchicalConfiguration conf) {
334: ConfigurationNode root = conf.getRoot();
335: return root.getChild(0).getChild(0);
336: }
337:
338: /**
339: * Performs a standard initialization of the subnode config to test.
340: */
341: protected void setUpSubnodeConfig() {
342: config = new SubnodeConfiguration(parent,
343: getSubnodeRoot(parent));
344: }
345: }
|