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:
018: package org.apache.commons.configuration;
019:
020: import java.io.File;
021: import java.io.FileWriter;
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.NoSuchElementException;
028: import java.util.Collection;
029:
030: import org.apache.commons.configuration.event.ConfigurationEvent;
031: import org.apache.commons.configuration.event.ConfigurationListener;
032: import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
033:
034: import junit.framework.TestCase;
035:
036: /**
037: * Test loading multiple configurations.
038: *
039: * @version $Id: TestCompositeConfiguration.java 524000 2007-03-30 09:14:03Z oheger $
040: */
041: public class TestCompositeConfiguration extends TestCase {
042: protected PropertiesConfiguration conf1;
043: protected PropertiesConfiguration conf2;
044: protected XMLConfiguration xmlConf;
045: protected CompositeConfiguration cc;
046:
047: /**
048: * The File that we test with
049: */
050: private String testProperties = new File("conf/test.properties")
051: .getAbsolutePath();
052: private String testProperties2 = new File("conf/test2.properties")
053: .getAbsolutePath();
054: private String testPropertiesXML = new File("conf/test.xml")
055: .getAbsolutePath();
056:
057: protected void setUp() throws Exception {
058: cc = new CompositeConfiguration();
059: conf1 = new PropertiesConfiguration(testProperties);
060: conf2 = new PropertiesConfiguration(testProperties2);
061: xmlConf = new XMLConfiguration(new File(testPropertiesXML));
062:
063: cc.setThrowExceptionOnMissing(true);
064: }
065:
066: public void testThrowExceptionOnMissing() {
067: assertTrue("Throw Exception Property is not set!", cc
068: .isThrowExceptionOnMissing());
069: }
070:
071: public void testAddRemoveConfigurations() throws Exception {
072: cc.addConfiguration(conf1);
073: assertEquals("Number of configurations", 2, cc
074: .getNumberOfConfigurations());
075: cc.addConfiguration(conf1);
076: assertEquals("Number of configurations", 2, cc
077: .getNumberOfConfigurations());
078: cc.addConfiguration(conf2);
079: assertEquals("Number of configurations", 3, cc
080: .getNumberOfConfigurations());
081: cc.removeConfiguration(conf1);
082: assertEquals("Number of configurations", 2, cc
083: .getNumberOfConfigurations());
084: cc.clear();
085: assertEquals("Number of configurations", 1, cc
086: .getNumberOfConfigurations());
087: }
088:
089: public void testGetPropertyWIncludes() throws Exception {
090: cc.addConfiguration(conf1);
091: cc.addConfiguration(conf2);
092: List l = cc.getList("packages");
093: assertTrue(l.contains("packagea"));
094: }
095:
096: public void testGetProperty() throws Exception {
097: cc.addConfiguration(conf1);
098: cc.addConfiguration(conf2);
099: assertEquals("Make sure we get the property from conf1 first",
100: "test.properties", cc.getString("propertyInOrder"));
101: cc.clear();
102:
103: cc.addConfiguration(conf2);
104: cc.addConfiguration(conf1);
105: assertEquals("Make sure we get the property from conf2 first",
106: "test2.properties", cc.getString("propertyInOrder"));
107: }
108:
109: public void testCantRemoveMemoryConfig() throws Exception {
110: cc.clear();
111: assertEquals(1, cc.getNumberOfConfigurations());
112:
113: Configuration internal = cc.getConfiguration(0);
114: cc.removeConfiguration(internal);
115:
116: assertEquals(1, cc.getNumberOfConfigurations());
117: }
118:
119: public void testGetPropertyMissing() throws Exception {
120: cc.addConfiguration(conf1);
121: cc.addConfiguration(conf2);
122: try {
123: assertNull(cc.getString("bogus.property"));
124: fail("Should have thrown a NoSuchElementException");
125: } catch (NoSuchElementException nsee) {
126: assertTrue(nsee.getMessage().indexOf("bogus.property") > -1);
127: }
128:
129: assertTrue("Should be false", !cc.getBoolean(
130: "test.missing.boolean", false));
131: assertTrue("Should be true", cc.getBoolean(
132: "test.missing.boolean.true", true));
133: }
134:
135: /**
136: * Tests <code>List</code> parsing.
137: */
138: public void testMultipleTypesOfConfigs() throws Exception {
139: cc.addConfiguration(conf1);
140: cc.addConfiguration(xmlConf);
141: assertEquals("Make sure we get the property from conf1 first",
142: 1, cc.getInt("test.short"));
143: cc.clear();
144:
145: cc.addConfiguration(xmlConf);
146: cc.addConfiguration(conf1);
147: assertEquals("Make sure we get the property from xml", 8, cc
148: .getInt("test.short"));
149: }
150:
151: /**
152: * Tests <code>List</code> parsing.
153: */
154: public void testPropertyExistsInOnlyOneConfig() throws Exception {
155: cc.addConfiguration(conf1);
156: cc.addConfiguration(xmlConf);
157: assertEquals("value", cc.getString("element"));
158: }
159:
160: /**
161: * Tests getting a default when the key doesn't exist
162: */
163: public void testDefaultValueWhenKeyMissing() throws Exception {
164: cc.addConfiguration(conf1);
165: cc.addConfiguration(xmlConf);
166: assertEquals("default", cc.getString("bogus", "default"));
167: assertTrue(1.4 == cc.getDouble("bogus", 1.4));
168: assertTrue(1.4 == cc.getDouble("bogus", 1.4));
169: }
170:
171: /**
172: * Tests <code>List</code> parsing.
173: */
174: public void testGettingConfiguration() throws Exception {
175: cc.addConfiguration(conf1);
176: cc.addConfiguration(xmlConf);
177: assertEquals(PropertiesConfiguration.class, cc
178: .getConfiguration(0).getClass());
179: assertEquals(XMLConfiguration.class, cc.getConfiguration(1)
180: .getClass());
181: }
182:
183: /**
184: * Tests setting values. These are set in memory mode only!
185: */
186: public void testClearingProperty() throws Exception {
187: cc.addConfiguration(conf1);
188: cc.addConfiguration(xmlConf);
189: cc.clearProperty("test.short");
190: assertTrue("Make sure test.short is gone!", !cc
191: .containsKey("test.short"));
192: }
193:
194: /**
195: * Tests adding values. Make sure they _DON'T_ override any other properties but add to the
196: * existing properties and keep sequence
197: */
198: public void testAddingProperty() throws Exception {
199: cc.addConfiguration(conf1);
200: cc.addConfiguration(xmlConf);
201:
202: String[] values = cc.getStringArray("test.short");
203:
204: assertEquals("Number of values before add is wrong!", 1,
205: values.length);
206: assertEquals("First Value before add is wrong", "1", values[0]);
207:
208: cc.addProperty("test.short", "88");
209:
210: values = cc.getStringArray("test.short");
211:
212: assertEquals("Number of values is wrong!", 2, values.length);
213: assertEquals("First Value is wrong", "1", values[0]);
214: assertEquals("Third Value is wrong", "88", values[1]);
215: }
216:
217: /**
218: * Tests setting values. These are set in memory mode only!
219: */
220: public void testSettingMissingProperty() throws Exception {
221: cc.addConfiguration(conf1);
222: cc.addConfiguration(xmlConf);
223: cc.setProperty("my.new.property", "supernew");
224: assertEquals("supernew", cc.getString("my.new.property"));
225: }
226:
227: /**
228: * Tests retrieving subsets of configurations
229: */
230: public void testGettingSubset() throws Exception {
231: cc.addConfiguration(conf1);
232: cc.addConfiguration(xmlConf);
233:
234: Configuration subset = cc.subset("test");
235: assertNotNull(subset);
236: assertFalse("Shouldn't be empty", subset.isEmpty());
237: assertEquals(
238: "Make sure the initial loaded configs subset overrides any later add configs subset",
239: "1", subset.getString("short"));
240:
241: cc.setProperty("test.short", "43");
242: subset = cc.subset("test");
243: assertEquals(
244: "Make sure the initial loaded configs subset overrides any later add configs subset",
245: "43", subset.getString("short"));
246: }
247:
248: /**
249: * Tests subsets and still can resolve elements
250: */
251: public void testSubsetCanResolve() throws Exception {
252: cc = new CompositeConfiguration();
253: final BaseConfiguration config = new BaseConfiguration();
254: config.addProperty("subset.tempfile",
255: "${java.io.tmpdir}/file.tmp");
256: cc.addConfiguration(config);
257: cc.addConfiguration(ConfigurationConverter
258: .getConfiguration(System.getProperties()));
259:
260: Configuration subset = cc.subset("subset");
261: assertEquals(
262: System.getProperty("java.io.tmpdir") + "/file.tmp",
263: subset.getString("tempfile"));
264: }
265:
266: /**
267: * Tests <code>List</code> parsing.
268: */
269: public void testList() throws Exception {
270: cc.addConfiguration(conf1);
271: cc.addConfiguration(xmlConf);
272:
273: List packages = cc.getList("packages");
274: // we should get 3 packages here
275: assertEquals(3, packages.size());
276:
277: List defaultList = new ArrayList();
278: defaultList.add("1");
279: defaultList.add("2");
280:
281: packages = cc.getList("packages.which.dont.exist", defaultList);
282: // we should get 2 packages here
283: assertEquals(2, packages.size());
284:
285: }
286:
287: /**
288: * Tests <code>String</code> array parsing.
289: */
290: public void testStringArray() throws Exception {
291: cc.addConfiguration(conf1);
292: cc.addConfiguration(xmlConf);
293:
294: String[] packages = cc.getStringArray("packages");
295: // we should get 3 packages here
296: assertEquals(3, packages.length);
297:
298: packages = cc.getStringArray("packages.which.dont.exist");
299: // we should get 0 packages here
300: assertEquals(0, packages.length);
301: }
302:
303: public void testGetList() {
304: Configuration conf1 = new BaseConfiguration();
305: conf1.addProperty("array", "value1");
306: conf1.addProperty("array", "value2");
307:
308: Configuration conf2 = new BaseConfiguration();
309: conf2.addProperty("array", "value3");
310: conf2.addProperty("array", "value4");
311:
312: cc.addConfiguration(conf1);
313: cc.addConfiguration(conf2);
314:
315: // check the composite 'array' property
316: List list = cc.getList("array");
317: assertNotNull("null list", list);
318: assertEquals("list size", 2, list.size());
319: assertTrue("'value1' not found in the list", list
320: .contains("value1"));
321: assertTrue("'value2' not found in the list", list
322: .contains("value2"));
323:
324: // add an element to the list in the composite configuration
325: cc.addProperty("array", "value5");
326:
327: // test the new list
328: list = cc.getList("array");
329: assertNotNull("null list", list);
330: assertEquals("list size", 3, list.size());
331: assertTrue("'value1' not found in the list", list
332: .contains("value1"));
333: assertTrue("'value2' not found in the list", list
334: .contains("value2"));
335: assertTrue("'value5' not found in the list", list
336: .contains("value5"));
337: }
338:
339: /**
340: * Tests <code>getKeys</code> preserves the order
341: */
342: public void testGetKeysPreservesOrder() throws Exception {
343: cc.addConfiguration(conf1);
344: List orderedList = new ArrayList();
345: for (Iterator keys = conf1.getKeys(); keys.hasNext();) {
346: orderedList.add(keys.next());
347: }
348: List iteratedList = new ArrayList();
349: for (Iterator keys = cc.getKeys(); keys.hasNext();) {
350: iteratedList.add(keys.next());
351: }
352: assertEquals(orderedList.size(), iteratedList.size());
353: for (int i = 0; i < orderedList.size(); i++) {
354: assertEquals(orderedList.get(i), iteratedList.get(i));
355: }
356: }
357:
358: /**
359: * Tests <code>getKeys(String key)</code> preserves the order
360: */
361: public void testGetKeys2PreservesOrder() throws Exception {
362: cc.addConfiguration(conf1);
363: List orderedList = new ArrayList();
364: for (Iterator keys = conf1.getKeys("test"); keys.hasNext();) {
365: orderedList.add(keys.next());
366: }
367: List iteratedList = new ArrayList();
368: for (Iterator keys = cc.getKeys("test"); keys.hasNext();) {
369: iteratedList.add(keys.next());
370: }
371: assertEquals(orderedList.size(), iteratedList.size());
372: for (int i = 0; i < orderedList.size(); i++) {
373: assertEquals(orderedList.get(i), iteratedList.get(i));
374: }
375: }
376:
377: public void testGetStringWithDefaults() {
378: BaseConfiguration defaults = new BaseConfiguration();
379: defaults.addProperty("default", "default string");
380:
381: CompositeConfiguration c = new CompositeConfiguration(defaults);
382: c.setThrowExceptionOnMissing(cc.isThrowExceptionOnMissing());
383: c.addProperty("string", "test string");
384:
385: assertEquals("test string", c.getString("string"));
386: try {
387: c.getString("XXX");
388: fail("Should throw NoSuchElementException exception");
389: } catch (NoSuchElementException e) {
390: //ok
391: } catch (Exception e) {
392: fail("Should throw NoSuchElementException exception, not "
393: + e);
394: }
395:
396: //test defaults
397: assertEquals("test string", c.getString("string",
398: "some default value"));
399: assertEquals("default string", c.getString("default"));
400: assertEquals("default string", c.getString("default",
401: "some default value"));
402: assertEquals("some default value", c.getString("XXX",
403: "some default value"));
404: }
405:
406: public void testCheckingInMemoryConfiguration() throws Exception {
407: String TEST_KEY = "testKey";
408: Configuration defaults = new PropertiesConfiguration();
409: defaults.setProperty(TEST_KEY, "testValue");
410: Configuration testConfiguration = new CompositeConfiguration(
411: defaults);
412: assertTrue(testConfiguration.containsKey(TEST_KEY));
413: assertFalse(testConfiguration.isEmpty());
414: boolean foundTestKey = false;
415: Iterator i = testConfiguration.getKeys();
416: //assertTrue(i instanceof IteratorChain);
417: //IteratorChain ic = (IteratorChain)i;
418: //assertEquals(2,i.size());
419: for (; i.hasNext();) {
420: String key = (String) i.next();
421: if (key.equals(TEST_KEY)) {
422: foundTestKey = true;
423: }
424: }
425: assertTrue(foundTestKey);
426: testConfiguration.clearProperty(TEST_KEY);
427: assertFalse(testConfiguration.containsKey(TEST_KEY));
428: }
429:
430: public void testStringArrayInterpolation() {
431: CompositeConfiguration config = new CompositeConfiguration();
432: config.addProperty("base", "foo");
433: config.addProperty("list", "${base}.bar1");
434: config.addProperty("list", "${base}.bar2");
435: config.addProperty("list", "${base}.bar3");
436:
437: String[] array = config.getStringArray("list");
438: assertEquals("size", 3, array.length);
439: assertEquals("1st element", "foo.bar1", array[0]);
440: assertEquals("2nd element", "foo.bar2", array[1]);
441: assertEquals("3rd element", "foo.bar3", array[2]);
442: }
443:
444: /**
445: * Tests whether global interpolation works with lists.
446: */
447: public void testListInterpolation() {
448: PropertiesConfiguration c1 = new PropertiesConfiguration();
449: c1.addProperty("c1.value", "test1");
450: c1.addProperty("c1.value", "${c2.value}");
451: cc.addConfiguration(c1);
452: PropertiesConfiguration c2 = new PropertiesConfiguration();
453: c2.addProperty("c2.value", "test2");
454: cc.addConfiguration(c2);
455: List lst = cc.getList("c1.value");
456: assertEquals("Wrong list size", 2, lst.size());
457: assertEquals("Wrong first element", "test1", lst.get(0));
458: assertEquals("Wrong second element", "test2", lst.get(1));
459: }
460:
461: /**
462: * Tests interpolation in combination with reloading.
463: */
464: public void testInterpolationWithReload() throws IOException,
465: ConfigurationException {
466: File testFile = new File("target/testConfig.properties");
467: final String propFirst = "first.name";
468: final String propFull = "full.name";
469:
470: try {
471: writeTestConfig(testFile, propFirst, "John");
472: PropertiesConfiguration c1 = new PropertiesConfiguration(
473: testFile);
474: c1.setReloadingStrategy(new FileAlwaysReloadingStrategy());
475: PropertiesConfiguration c2 = new PropertiesConfiguration();
476: c2.addProperty(propFull, "${" + propFirst + "} Doe");
477: CompositeConfiguration cc = new CompositeConfiguration();
478: cc.addConfiguration(c1);
479: cc.addConfiguration(c2);
480: assertEquals("Wrong name", "John Doe", cc
481: .getString(propFull));
482:
483: writeTestConfig(testFile, propFirst, "Jane");
484: assertEquals("First name not changed", "Jane", c1
485: .getString(propFirst));
486: assertEquals("First name not changed in composite", "Jane",
487: cc.getString(propFirst));
488: assertEquals("Full name not changed", "Jane Doe", cc
489: .getString(propFull));
490: } finally {
491: if (testFile.exists()) {
492: testFile.delete();
493: }
494: }
495: }
496:
497: /**
498: * Writes a test properties file containing a single property definition.
499: *
500: * @param f the file to write
501: * @param prop the property name
502: * @param value the property value
503: * @throws IOException if an error occurs
504: */
505: private void writeTestConfig(File f, String prop, String value)
506: throws IOException {
507: PrintWriter out = new PrintWriter(new FileWriter(f));
508: out.print(prop);
509: out.print("=");
510: out.println(value);
511: out.close();
512: }
513:
514: public void testInstanciateWithCollection() {
515: Collection configs = new ArrayList();
516: configs.add(xmlConf);
517: configs.add(conf1);
518: configs.add(conf2);
519:
520: CompositeConfiguration config = new CompositeConfiguration(
521: configs);
522: assertEquals("Number of configurations", 4, config
523: .getNumberOfConfigurations());
524: assertTrue("The in memory configuration is not empty", config
525: .getInMemoryConfiguration().isEmpty());
526: }
527:
528: public void testClone() {
529: CompositeConfiguration cc2 = (CompositeConfiguration) cc
530: .clone();
531: assertEquals("Wrong number of contained configurations", cc
532: .getNumberOfConfigurations(), cc2
533: .getNumberOfConfigurations());
534:
535: StrictConfigurationComparator comp = new StrictConfigurationComparator();
536: for (int i = 0; i < cc.getNumberOfConfigurations(); i++) {
537: assertEquals("Wrong configuration class at " + i, cc
538: .getConfiguration(i).getClass(), cc2
539: .getConfiguration(i).getClass());
540: assertNotSame("Configuration was not cloned", cc
541: .getConfiguration(i), cc2.getConfiguration(i));
542: assertTrue("Configurations at " + i + " not equal", comp
543: .compare(cc.getConfiguration(i), cc2
544: .getConfiguration(i)));
545: }
546:
547: assertTrue("Configurations are not equal", comp
548: .compare(cc, cc2));
549: }
550:
551: /**
552: * Tests cloning if one of the contained configurations does not support
553: * this operation. This should cause an exception.
554: */
555: public void testCloneNotSupported() {
556: cc.addConfiguration(new NonCloneableConfiguration());
557: try {
558: cc.clone();
559: fail("Could clone non cloneable configuration!");
560: } catch (ConfigurationRuntimeException crex) {
561: // ok
562: }
563: }
564:
565: /**
566: * Ensures that event listeners are not cloned.
567: */
568: public void testCloneEventListener() {
569: cc.addConfigurationListener(new TestEventListenerImpl());
570: CompositeConfiguration cc2 = (CompositeConfiguration) cc
571: .clone();
572: assertTrue("Listeners have been cloned", cc2
573: .getConfigurationListeners().isEmpty());
574: }
575:
576: /**
577: * Tests whether add property events are triggered.
578: */
579: public void testEventAddProperty() {
580: TestEventListenerImpl l = new TestEventListenerImpl();
581: cc.addConfigurationListener(l);
582: cc.addProperty("test", "value");
583: assertEquals("No add events received", 2, l.eventCount);
584: }
585:
586: /**
587: * Tests whether set property events are triggered.
588: */
589: public void testEventSetProperty() {
590: TestEventListenerImpl l = new TestEventListenerImpl();
591: cc.addConfigurationListener(l);
592: cc.setProperty("test", "value");
593: assertEquals("No set events received", 2, l.eventCount);
594: }
595:
596: /**
597: * Tests whether clear property events are triggered.
598: */
599: public void testEventClearProperty() {
600: cc.addConfiguration(conf1);
601: assertTrue("Wrong value for property", cc
602: .getBoolean("configuration.loaded"));
603: TestEventListenerImpl l = new TestEventListenerImpl();
604: cc.addConfigurationListener(l);
605: cc.clearProperty("configuration.loaded");
606: assertFalse("Key still present", cc
607: .containsKey("configuration.loaded"));
608: assertEquals("No clear events received", 2, l.eventCount);
609: }
610:
611: /**
612: * Tests chaning the list delimiter character.
613: */
614: public void testSetListDelimiter() {
615: cc.setListDelimiter('/');
616: checkSetListDelimiter();
617: }
618:
619: /**
620: * Tests whether the correct list delimiter is set after a clear operation.
621: */
622: public void testSetListDelimiterAfterClear() {
623: cc.setListDelimiter('/');
624: cc.clear();
625: checkSetListDelimiter();
626: }
627:
628: /**
629: * Helper method for testing whether the list delimiter is correctly
630: * handled.
631: */
632: private void checkSetListDelimiter() {
633: cc.addProperty("test.list", "a/b/c");
634: cc.addProperty("test.property", "a,b,c");
635: assertEquals("Wrong number of list elements", 3, cc.getList(
636: "test.list").size());
637: assertEquals("Wrong value of property", "a,b,c", cc
638: .getString("test.property"));
639: }
640:
641: /**
642: * Tests whether list splitting can be disabled.
643: */
644: public void testSetDelimiterParsingDisabled() {
645: cc.setDelimiterParsingDisabled(true);
646: checkSetListDelimiterParsingDisabled();
647: }
648:
649: /**
650: * Tests whether the list parsing flag is correctly handled after a clear()
651: * operation.
652: */
653: public void testSetDelimiterParsingDisabledAfterClear() {
654: cc.setDelimiterParsingDisabled(true);
655: cc.clear();
656: checkSetListDelimiterParsingDisabled();
657: }
658:
659: /**
660: * Helper method for checking whether the list parsing flag is correctly
661: * handled.
662: */
663: private void checkSetListDelimiterParsingDisabled() {
664: cc.addProperty("test.property", "a,b,c");
665: assertEquals("Wrong value of property", "a,b,c", cc
666: .getString("test.property"));
667: }
668:
669: /**
670: * A test configuration event listener that counts the number of received
671: * events. Used for testing the event facilities.
672: */
673: static class TestEventListenerImpl implements ConfigurationListener {
674: /** The number of received events.*/
675: int eventCount;
676:
677: public void configurationChanged(ConfigurationEvent event) {
678: eventCount++;
679: }
680: }
681: }
|