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