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.io.File;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.io.PrintWriter;
023: import java.util.Collection;
024: import java.util.Set;
025:
026: import org.apache.commons.configuration.event.ConfigurationEvent;
027: import org.apache.commons.configuration.event.ConfigurationListener;
028: import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
029: import org.apache.commons.configuration.tree.NodeCombiner;
030: import org.apache.commons.configuration.tree.UnionCombiner;
031:
032: import junit.framework.Assert;
033: import junit.framework.TestCase;
034:
035: /**
036: * Test class for CombinedConfiguration.
037: *
038: * @version $Id: TestCombinedConfiguration.java 484692 2006-12-08 18:30:15Z oheger $
039: */
040: public class TestCombinedConfiguration extends TestCase {
041: /** Constant for the name of a sub configuration. */
042: static final String TEST_NAME = "SUBCONFIG";
043:
044: /** Constant for a test key. */
045: static final String TEST_KEY = "test.value";
046:
047: /** The configuration to be tested. */
048: CombinedConfiguration config;
049:
050: /** The test event listener. */
051: CombinedListener listener;
052:
053: protected void setUp() throws Exception {
054: super .setUp();
055: config = new CombinedConfiguration();
056: listener = new CombinedListener();
057: config.addConfigurationListener(listener);
058: }
059:
060: /**
061: * Tests accessing a newly created combined configuration.
062: */
063: public void testInit() {
064: assertEquals("Already configurations contained", 0, config
065: .getNumberOfConfigurations());
066: assertTrue("Set of names is not empty", config
067: .getConfigurationNames().isEmpty());
068: assertTrue("Wrong node combiner",
069: config.getNodeCombiner() instanceof UnionCombiner);
070: assertNull("Test config was found", config
071: .getConfiguration(TEST_NAME));
072: assertFalse("Force reload check flag is set", config
073: .isForceReloadCheck());
074: }
075:
076: /**
077: * Tests adding a configuration (without further information).
078: */
079: public void testAddConfiguration() {
080: AbstractConfiguration c = setUpTestConfiguration();
081: config.addConfiguration(c);
082: checkAddConfig(c);
083: assertEquals("Wrong number of configs", 1, config
084: .getNumberOfConfigurations());
085: assertTrue("Name list is not empty", config
086: .getConfigurationNames().isEmpty());
087: assertSame("Added config not found", c, config
088: .getConfiguration(0));
089: assertTrue("Wrong property value", config.getBoolean(TEST_KEY));
090: listener.checkEvent(1, 0);
091: }
092:
093: /**
094: * Tests adding a configuration with a name.
095: */
096: public void testAddConfigurationWithName() {
097: AbstractConfiguration c = setUpTestConfiguration();
098: config.addConfiguration(c, TEST_NAME);
099: checkAddConfig(c);
100: assertEquals("Wrong number of configs", 1, config
101: .getNumberOfConfigurations());
102: assertSame("Added config not found", c, config
103: .getConfiguration(0));
104: assertSame("Added config not found by name", c, config
105: .getConfiguration(TEST_NAME));
106: Set names = config.getConfigurationNames();
107: assertEquals("Wrong number of config names", 1, names.size());
108: assertTrue("Name not found", names.contains(TEST_NAME));
109: assertTrue("Wrong property value", config.getBoolean(TEST_KEY));
110: listener.checkEvent(1, 0);
111: }
112:
113: /**
114: * Tests adding a configuration with a name when this name already exists.
115: * This should cause an exception.
116: */
117: public void testAddConfigurationWithNameTwice() {
118: config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
119: try {
120: config.addConfiguration(setUpTestConfiguration(),
121: TEST_NAME, "prefix");
122: fail("Could add config with same name!");
123: } catch (ConfigurationRuntimeException cex) {
124: // ok
125: }
126: }
127:
128: /**
129: * Tests adding a configuration and specifying an at position.
130: */
131: public void testAddConfigurationAt() {
132: AbstractConfiguration c = setUpTestConfiguration();
133: config.addConfiguration(c, null, "my");
134: checkAddConfig(c);
135: assertTrue("Wrong property value", config.getBoolean("my."
136: + TEST_KEY));
137: }
138:
139: /**
140: * Tests adding a configuration with a complex at position. Here the at path
141: * contains a dot, which must be escaped.
142: */
143: public void testAddConfigurationComplexAt() {
144: AbstractConfiguration c = setUpTestConfiguration();
145: config.addConfiguration(c, null, "This..is.a.complex");
146: checkAddConfig(c);
147: assertTrue("Wrong property value", config
148: .getBoolean("This..is.a.complex." + TEST_KEY));
149: }
150:
151: /**
152: * Checks if a configuration was correctly added to the combined config.
153: *
154: * @param c the config to check
155: */
156: private void checkAddConfig(AbstractConfiguration c) {
157: Collection listeners = c.getConfigurationListeners();
158: assertEquals("Wrong number of configuration listeners", 1,
159: listeners.size());
160: assertTrue("Combined config is no listener", listeners
161: .contains(config));
162: }
163:
164: /**
165: * Tests adding a null configuration. This should cause an exception to be
166: * thrown.
167: */
168: public void testAddNullConfiguration() {
169: try {
170: config.addConfiguration(null);
171: fail("Could add null configuration!");
172: } catch (IllegalArgumentException iex) {
173: // ok
174: }
175: }
176:
177: /**
178: * Tests accessing properties if no configurations have been added.
179: */
180: public void testAccessPropertyEmpty() {
181: assertFalse("Found a key", config.containsKey(TEST_KEY));
182: assertNull("Key has a value", config.getString("test.comment"));
183: assertTrue("Config is not empty", config.isEmpty());
184: }
185:
186: /**
187: * Tests accessing properties if multiple configurations have been added.
188: */
189: public void testAccessPropertyMulti() {
190: config.addConfiguration(setUpTestConfiguration());
191: config.addConfiguration(setUpTestConfiguration(), null,
192: "prefix1");
193: config.addConfiguration(setUpTestConfiguration(), null,
194: "prefix2");
195: assertTrue("Prop1 not found", config.getBoolean(TEST_KEY));
196: assertTrue("Prop 2 not found", config.getBoolean("prefix1."
197: + TEST_KEY));
198: assertTrue("Prop 3 not found", config.getBoolean("prefix2."
199: + TEST_KEY));
200: assertFalse("Configuration is empty", config.isEmpty());
201: listener.checkEvent(3, 0);
202: }
203:
204: /**
205: * Tests removing a configuration.
206: */
207: public void testRemoveConfiguration() {
208: AbstractConfiguration c = setUpTestConfiguration();
209: config.addConfiguration(c);
210: checkAddConfig(c);
211: assertTrue("Config could not be removed", config
212: .removeConfiguration(c));
213: checkRemoveConfig(c);
214: }
215:
216: /**
217: * Tests removing a configuration by index.
218: */
219: public void testRemoveConfigurationAt() {
220: AbstractConfiguration c = setUpTestConfiguration();
221: config.addConfiguration(c);
222: assertSame("Wrong config removed", c, config
223: .removeConfigurationAt(0));
224: checkRemoveConfig(c);
225: }
226:
227: /**
228: * Tests removing a configuration by name.
229: */
230: public void testRemoveConfigurationByName() {
231: AbstractConfiguration c = setUpTestConfiguration();
232: config.addConfiguration(c, TEST_NAME);
233: assertSame("Wrong config removed", c, config
234: .removeConfiguration(TEST_NAME));
235: checkRemoveConfig(c);
236: }
237:
238: /**
239: * Tests removing a configuration with a name.
240: */
241: public void testRemoveNamedConfiguration() {
242: AbstractConfiguration c = setUpTestConfiguration();
243: config.addConfiguration(c, TEST_NAME);
244: config.removeConfiguration(c);
245: checkRemoveConfig(c);
246: }
247:
248: /**
249: * Tests removing a named configuration by index.
250: */
251: public void testRemoveNamedConfigurationAt() {
252: AbstractConfiguration c = setUpTestConfiguration();
253: config.addConfiguration(c, TEST_NAME);
254: assertSame("Wrong config removed", c, config
255: .removeConfigurationAt(0));
256: checkRemoveConfig(c);
257: }
258:
259: /**
260: * Tests removing a configuration that was not added prior.
261: */
262: public void testRemoveNonContainedConfiguration() {
263: assertFalse("Could remove non contained config", config
264: .removeConfiguration(setUpTestConfiguration()));
265: listener.checkEvent(0, 0);
266: }
267:
268: /**
269: * Tests removing a configuration by name, which is not contained.
270: */
271: public void testRemoveConfigurationByUnknownName() {
272: assertNull("Could remove configuration by unknown name", config
273: .removeConfiguration("unknownName"));
274: listener.checkEvent(0, 0);
275: }
276:
277: /**
278: * Tests whether a configuration was completely removed.
279: *
280: * @param c the removed configuration
281: */
282: private void checkRemoveConfig(AbstractConfiguration c) {
283: assertTrue("Listener was not removed", c
284: .getConfigurationListeners().isEmpty());
285: assertEquals("Wrong number of contained configs", 0, config
286: .getNumberOfConfigurations());
287: assertTrue("Name was not removed", config
288: .getConfigurationNames().isEmpty());
289: listener.checkEvent(2, 0);
290: }
291:
292: /**
293: * Tests if an update of a contained configuration leeds to an invalidation
294: * of the combined configuration.
295: */
296: public void testUpdateContainedConfiguration() {
297: AbstractConfiguration c = setUpTestConfiguration();
298: config.addConfiguration(c);
299: c.addProperty("test.otherTest", "yes");
300: assertEquals("New property not found", "yes", config
301: .getString("test.otherTest"));
302: listener.checkEvent(3, 0);
303: }
304:
305: /**
306: * Tests if setting a node combiner causes an invalidation.
307: */
308: public void testSetNodeCombiner() {
309: NodeCombiner combiner = new UnionCombiner();
310: config.setNodeCombiner(combiner);
311: assertSame("Node combiner was not set", combiner, config
312: .getNodeCombiner());
313: listener.checkEvent(1, 0);
314: }
315:
316: /**
317: * Tests setting a null node combiner. This should cause an exception.
318: */
319: public void testSetNullNodeCombiner() {
320: try {
321: config.setNodeCombiner(null);
322: fail("Could set null node combiner!");
323: } catch (IllegalArgumentException iex) {
324: // ok
325: }
326: }
327:
328: /**
329: * Tests cloning a combined configuration.
330: */
331: public void testClone() {
332: config.addConfiguration(setUpTestConfiguration());
333: config.addConfiguration(setUpTestConfiguration(), TEST_NAME,
334: "conf2");
335: config.addConfiguration(new PropertiesConfiguration(), "props");
336:
337: CombinedConfiguration cc2 = (CombinedConfiguration) config
338: .clone();
339: assertEquals("Wrong number of contained configurations", config
340: .getNumberOfConfigurations(), cc2
341: .getNumberOfConfigurations());
342: assertSame("Wrong node combiner", config.getNodeCombiner(), cc2
343: .getNodeCombiner());
344: assertEquals("Wrong number of names", config
345: .getConfigurationNames().size(), cc2
346: .getConfigurationNames().size());
347: assertTrue("Event listeners were cloned", cc2
348: .getConfigurationListeners().isEmpty());
349:
350: StrictConfigurationComparator comp = new StrictConfigurationComparator();
351: for (int i = 0; i < config.getNumberOfConfigurations(); i++) {
352: assertNotSame("Configuration at " + i + " was not cloned",
353: config.getConfiguration(i), cc2.getConfiguration(i));
354: assertEquals("Wrong config class at " + i, config
355: .getConfiguration(i).getClass(), cc2
356: .getConfiguration(i).getClass());
357: assertTrue("Configs not equal at " + i, comp.compare(config
358: .getConfiguration(i), cc2.getConfiguration(i)));
359: }
360:
361: assertTrue("Combined configs not equal", comp.compare(config,
362: cc2));
363: }
364:
365: /**
366: * Tests if the cloned configuration is decoupled from the original.
367: */
368: public void testCloneModify() {
369: config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
370: CombinedConfiguration cc2 = (CombinedConfiguration) config
371: .clone();
372: assertTrue("Name is missing", cc2.getConfigurationNames()
373: .contains(TEST_NAME));
374: cc2.removeConfiguration(TEST_NAME);
375: assertFalse("Names in original changed", config
376: .getConfigurationNames().isEmpty());
377: }
378:
379: /**
380: * Tests clearing a combined configuration. This should remove all contained
381: * configurations.
382: */
383: public void testClear() {
384: config.addConfiguration(setUpTestConfiguration(), TEST_NAME,
385: "test");
386: config.addConfiguration(setUpTestConfiguration());
387:
388: config.clear();
389: assertEquals("Still configs contained", 0, config
390: .getNumberOfConfigurations());
391: assertTrue("Still names contained", config
392: .getConfigurationNames().isEmpty());
393: assertTrue("Config is not empty", config.isEmpty());
394:
395: listener.checkEvent(3, 2);
396: }
397:
398: /**
399: * Tests if file-based configurations can be reloaded.
400: */
401: public void testReloading() throws Exception {
402: config.setForceReloadCheck(true);
403: File testDir = new File("target");
404: File testXmlFile = new File(testDir, "reload.xml");
405: File testPropsFile = new File(testDir, "reload.properties");
406: writeFile(testXmlFile, "<xml><xmlReload>0</xmlReload></xml>");
407: writeFile(testPropsFile, "propsReload = 0");
408: XMLConfiguration c1 = new XMLConfiguration(testXmlFile);
409: c1.setReloadingStrategy(new FileAlwaysReloadingStrategy());
410: PropertiesConfiguration c2 = new PropertiesConfiguration(
411: testPropsFile);
412: c2.setThrowExceptionOnMissing(true);
413: c2.setReloadingStrategy(new FileAlwaysReloadingStrategy());
414: config.addConfiguration(c1);
415: config.addConfiguration(c2);
416: assertEquals("Wrong xml reload value", 0, config
417: .getInt("xmlReload"));
418: assertEquals("Wrong props reload value", 0, config
419: .getInt("propsReload"));
420:
421: writeFile(testXmlFile, "<xml><xmlReload>1</xmlReload></xml>");
422: assertEquals("XML reload not detected", 1, config
423: .getInt("xmlReload"));
424: config.setForceReloadCheck(false);
425: writeFile(testPropsFile, "propsReload = 1");
426: assertEquals(
427: "Props reload detected though check flag is false", 0,
428: config.getInt("propsReload"));
429:
430: assertTrue("XML file cannot be removed", testXmlFile.delete());
431: assertTrue("Props file cannot be removed", testPropsFile
432: .delete());
433: }
434:
435: /**
436: * Helper method for writing a file.
437: *
438: * @param file the file to be written
439: * @param content the file's content
440: * @throws IOException if an error occurs
441: */
442: private static void writeFile(File file, String content)
443: throws IOException {
444: PrintWriter out = null;
445: try {
446: out = new PrintWriter(new FileWriter(file));
447: out.print(content);
448: } finally {
449: if (out != null) {
450: out.close();
451: }
452: }
453: }
454:
455: /**
456: * Helper method for creating a test configuration to be added to the
457: * combined configuration.
458: *
459: * @return the test configuration
460: */
461: private AbstractConfiguration setUpTestConfiguration() {
462: HierarchicalConfiguration config = new HierarchicalConfiguration();
463: config.addProperty(TEST_KEY, Boolean.TRUE);
464: config.addProperty("test.comment", "This is a test");
465: return config;
466: }
467:
468: /**
469: * Test event listener class for checking if the expected invalidate events
470: * are fired.
471: */
472: static class CombinedListener implements ConfigurationListener {
473: int invalidateEvents;
474:
475: int otherEvents;
476:
477: public void configurationChanged(ConfigurationEvent event) {
478: if (event.getType() == CombinedConfiguration.EVENT_COMBINED_INVALIDATE) {
479: invalidateEvents++;
480: } else {
481: otherEvents++;
482: }
483: }
484:
485: /**
486: * Checks if the expected number of events was fired.
487: *
488: * @param expectedInvalidate the expected number of invalidate events
489: * @param expectedOthers the expected number of other events
490: */
491: public void checkEvent(int expectedInvalidate,
492: int expectedOthers) {
493: Assert.assertEquals("Wrong number of invalidate events",
494: expectedInvalidate, invalidateEvents);
495: Assert.assertEquals("Wrong number of other events",
496: expectedOthers, otherEvents);
497: }
498: }
499: }
|