View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.configuration;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNotNull;
23  import static org.junit.Assert.assertNotSame;
24  import static org.junit.Assert.assertNull;
25  import static org.junit.Assert.assertSame;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.File;
30  import java.io.FileWriter;
31  import java.io.IOException;
32  import java.io.PrintWriter;
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.NoSuchElementException;
38  
39  import org.apache.commons.configuration.event.ConfigurationEvent;
40  import org.apache.commons.configuration.event.ConfigurationListener;
41  import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
42  import org.easymock.EasyMock;
43  import org.junit.Before;
44  import org.junit.Test;
45  
46  /**
47   * Test loading multiple configurations.
48   *
49   * @version $Id: TestCompositeConfiguration.java 1233058 2012-01-18 20:49:12Z oheger $
50   */
51  public class TestCompositeConfiguration
52  {
53      /** Constant for a test property to be checked.*/
54      private static final String TEST_PROPERTY = "test.source.property";
55  
56      protected PropertiesConfiguration conf1;
57      protected PropertiesConfiguration conf2;
58      protected XMLConfiguration xmlConf;
59      protected CompositeConfiguration cc;
60  
61      /**
62       * The File that we test with
63       */
64      private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath();
65      private String testProperties2 = ConfigurationAssert.getTestFile("test2.properties").getAbsolutePath();
66      private String testPropertiesXML = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath();
67  
68      @Before
69      public void setUp() throws Exception
70      {
71          cc = new CompositeConfiguration();
72          conf1 = new PropertiesConfiguration(testProperties);
73          conf2 = new PropertiesConfiguration(testProperties2);
74          xmlConf = new XMLConfiguration(new File(testPropertiesXML));
75  
76          cc.setThrowExceptionOnMissing(true);
77      }
78  
79      @Test
80      public void testThrowExceptionOnMissing()
81      {
82          assertTrue("Throw Exception Property is not set!", cc.isThrowExceptionOnMissing());
83      }
84  
85      @Test
86      public void testAddRemoveConfigurations() throws Exception
87      {
88          cc.addConfiguration(conf1);
89          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
90          cc.addConfiguration(conf1);
91          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
92          cc.addConfiguration(conf2);
93          assertEquals("Number of configurations", 3, cc.getNumberOfConfigurations());
94          cc.removeConfiguration(conf1);
95          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
96          cc.clear();
97          assertEquals("Number of configurations", 1, cc.getNumberOfConfigurations());
98      }
99  
100     @Test
101     public void testGetPropertyWIncludes() throws Exception
102     {
103         cc.addConfiguration(conf1);
104         cc.addConfiguration(conf2);
105         List<Object> l = cc.getList("packages");
106         assertTrue(l.contains("packagea"));
107     }
108 
109     @Test
110     public void testGetProperty() throws Exception
111     {
112         cc.addConfiguration(conf1);
113         cc.addConfiguration(conf2);
114         assertEquals("Make sure we get the property from conf1 first", "test.properties", cc.getString("propertyInOrder"));
115         cc.clear();
116 
117         cc.addConfiguration(conf2);
118         cc.addConfiguration(conf1);
119         assertEquals("Make sure we get the property from conf2 first", "test2.properties", cc.getString("propertyInOrder"));
120     }
121 
122     @Test
123     public void testCantRemoveMemoryConfig() throws Exception
124     {
125         cc.clear();
126         assertEquals(1, cc.getNumberOfConfigurations());
127 
128         Configuration internal = cc.getConfiguration(0);
129         cc.removeConfiguration(internal);
130 
131         assertEquals(1, cc.getNumberOfConfigurations());
132     }
133 
134     @Test
135     public void testGetPropertyMissing() throws Exception
136     {
137         cc.addConfiguration(conf1);
138         cc.addConfiguration(conf2);
139         try
140         {
141             assertNull(cc.getString("bogus.property"));
142             fail("Should have thrown a NoSuchElementException");
143         }
144         catch (NoSuchElementException nsee)
145         {
146             assertTrue(nsee.getMessage().indexOf("bogus.property") > -1);
147         }
148 
149         assertTrue("Should be false", !cc.getBoolean("test.missing.boolean", false));
150         assertTrue("Should be true", cc.getBoolean("test.missing.boolean.true", true));
151     }
152 
153     /**
154      * Tests {@code List} parsing.
155      */
156     @Test
157     public void testMultipleTypesOfConfigs() throws Exception
158     {
159         cc.addConfiguration(conf1);
160         cc.addConfiguration(xmlConf);
161         assertEquals("Make sure we get the property from conf1 first", 1, cc.getInt("test.short"));
162         cc.clear();
163 
164         cc.addConfiguration(xmlConf);
165         cc.addConfiguration(conf1);
166         assertEquals("Make sure we get the property from xml", 8, cc.getInt("test.short"));
167     }
168 
169     @Test
170     public void testPropertyExistsInOnlyOneConfig() throws Exception
171     {
172         cc.addConfiguration(conf1);
173         cc.addConfiguration(xmlConf);
174         assertEquals("value", cc.getString("element"));
175     }
176 
177     /**
178      * Tests getting a default when the key doesn't exist
179      */
180     @Test
181     public void testDefaultValueWhenKeyMissing() throws Exception
182     {
183         cc.addConfiguration(conf1);
184         cc.addConfiguration(xmlConf);
185         assertEquals("default", cc.getString("bogus", "default"));
186         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
187         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
188     }
189 
190     @Test
191     public void testGettingConfiguration() throws Exception
192     {
193         cc.addConfiguration(conf1);
194         cc.addConfiguration(xmlConf);
195         assertEquals(PropertiesConfiguration.class, cc.getConfiguration(0).getClass());
196         assertEquals(XMLConfiguration.class, cc.getConfiguration(1).getClass());
197     }
198 
199     /**
200      * Tests setting values.  These are set in memory mode only!
201      */
202     @Test
203     public void testClearingProperty() throws Exception
204     {
205         cc.addConfiguration(conf1);
206         cc.addConfiguration(xmlConf);
207         cc.clearProperty("test.short");
208         assertTrue("Make sure test.short is gone!", !cc.containsKey("test.short"));
209     }
210 
211     /**
212      * Tests adding values.  Make sure they _DON'T_ override any other properties but add to the
213      * existing properties  and keep sequence
214      */
215     @Test
216     public void testAddingProperty() throws Exception
217     {
218         cc.addConfiguration(conf1);
219         cc.addConfiguration(xmlConf);
220 
221         String[] values = cc.getStringArray("test.short");
222 
223         assertEquals("Number of values before add is wrong!", 1, values.length);
224         assertEquals("First Value before add is wrong", "1", values[0]);
225 
226         cc.addProperty("test.short", "88");
227 
228         values = cc.getStringArray("test.short");
229 
230         assertEquals("Number of values is wrong!", 2, values.length);
231         assertEquals("First Value is wrong", "1", values[0]);
232         assertEquals("Third Value is wrong", "88", values[1]);
233     }
234 
235     /**
236      * Tests setting values.  These are set in memory mode only!
237      */
238     @Test
239     public void testSettingMissingProperty() throws Exception
240     {
241         cc.addConfiguration(conf1);
242         cc.addConfiguration(xmlConf);
243         cc.setProperty("my.new.property", "supernew");
244         assertEquals("supernew", cc.getString("my.new.property"));
245     }
246 
247     /**
248      * Tests retrieving subsets of configurations
249      */
250     @Test
251     public void testGettingSubset() throws Exception
252     {
253         cc.addConfiguration(conf1);
254         cc.addConfiguration(xmlConf);
255 
256         Configuration subset = cc.subset("test");
257         assertNotNull(subset);
258         assertFalse("Shouldn't be empty", subset.isEmpty());
259         assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "1", subset.getString("short"));
260 
261         cc.setProperty("test.short", "43");
262         subset = cc.subset("test");
263         assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "43", subset.getString("short"));
264     }
265 
266     /**
267      * Tests subsets and still can resolve elements
268      */
269     @Test
270     public void testSubsetCanResolve() throws Exception
271     {
272         cc = new CompositeConfiguration();
273         final BaseConfiguration config = new BaseConfiguration();
274         config.addProperty("subset.tempfile", "${java.io.tmpdir}/file.tmp");
275         cc.addConfiguration(config);
276         cc.addConfiguration(ConfigurationConverter.getConfiguration(System.getProperties()));
277 
278         Configuration subset = cc.subset("subset");
279         assertEquals(System.getProperty("java.io.tmpdir") + "/file.tmp", subset.getString("tempfile"));
280     }
281 
282     /**
283      * Tests {@code List} parsing.
284      */
285     @Test
286     public void testList() throws Exception
287     {
288         cc.addConfiguration(conf1);
289         cc.addConfiguration(xmlConf);
290 
291         List<Object> packages = cc.getList("packages");
292         // we should get 3 packages here
293         assertEquals(3, packages.size());
294 
295         List<Object> defaultList = new ArrayList<Object>();
296         defaultList.add("1");
297         defaultList.add("2");
298 
299         packages = cc.getList("packages.which.dont.exist", defaultList);
300         // we should get 2 packages here
301         assertEquals(2, packages.size());
302 
303     }
304 
305     /**
306      * Tests {@code String} array parsing.
307      */
308     @Test
309     public void testStringArray() throws Exception
310     {
311         cc.addConfiguration(conf1);
312         cc.addConfiguration(xmlConf);
313 
314         String[] packages = cc.getStringArray("packages");
315         // we should get 3 packages here
316         assertEquals(3, packages.length);
317 
318         packages = cc.getStringArray("packages.which.dont.exist");
319         // we should get 0 packages here
320         assertEquals(0, packages.length);
321     }
322 
323     @Test
324     public void testGetList()
325     {
326         Configuration conf1 = new BaseConfiguration();
327         conf1.addProperty("array", "value1");
328         conf1.addProperty("array", "value2");
329 
330         Configuration conf2 = new BaseConfiguration();
331         conf2.addProperty("array", "value3");
332         conf2.addProperty("array", "value4");
333 
334         cc.addConfiguration(conf1);
335         cc.addConfiguration(conf2);
336 
337         // check the composite 'array' property
338         List<Object> list = cc.getList("array");
339         assertNotNull("null list", list);
340         assertEquals("list size", 2, list.size());
341         assertTrue("'value1' not found in the list", list.contains("value1"));
342         assertTrue("'value2' not found in the list", list.contains("value2"));
343 
344         // add an element to the list in the composite configuration
345         cc.addProperty("array", "value5");
346 
347         // test the new list
348         list = cc.getList("array");
349         assertNotNull("null list", list);
350         assertEquals("list size", 3, list.size());
351         assertTrue("'value1' not found in the list", list.contains("value1"));
352         assertTrue("'value2' not found in the list", list.contains("value2"));
353         assertTrue("'value5' not found in the list", list.contains("value5"));
354     }
355 
356     /**
357      * Tests {@code getKeys} preserves the order
358      */
359     @Test
360     public void testGetKeysPreservesOrder() throws Exception
361     {
362         cc.addConfiguration(conf1);
363         List<String> orderedList = new ArrayList<String>();
364         for (Iterator<String> keys = conf1.getKeys(); keys.hasNext();)
365         {
366             orderedList.add(keys.next());
367         }
368         List<String> iteratedList = new ArrayList<String>();
369         for (Iterator<String> keys = cc.getKeys(); keys.hasNext();)
370         {
371             iteratedList.add(keys.next());
372         }
373         assertEquals(orderedList.size(), iteratedList.size());
374         for (int i = 0; i < orderedList.size(); i++)
375         {
376             assertEquals(orderedList.get(i), iteratedList.get(i));
377         }
378     }
379 
380     /**
381      * Tests {@code getKeys(String key)} preserves the order
382      */
383     @Test
384     public void testGetKeys2PreservesOrder() throws Exception
385     {
386         cc.addConfiguration(conf1);
387         List<String> orderedList = new ArrayList<String>();
388         for (Iterator<String> keys = conf1.getKeys("test"); keys.hasNext();)
389         {
390             orderedList.add(keys.next());
391         }
392         List<String> iteratedList = new ArrayList<String>();
393         for (Iterator<String> keys = cc.getKeys("test"); keys.hasNext();)
394         {
395             iteratedList.add(keys.next());
396         }
397         assertEquals(orderedList.size(), iteratedList.size());
398         for (int i = 0; i < orderedList.size(); i++)
399         {
400             assertEquals(orderedList.get(i), iteratedList.get(i));
401         }
402     }
403 
404     @Test
405     public void testGetStringWithDefaults()
406     {
407         BaseConfiguration defaults = new BaseConfiguration();
408         defaults.addProperty("default", "default string");
409 
410         CompositeConfiguration c = new CompositeConfiguration(defaults);
411         c.setThrowExceptionOnMissing(cc.isThrowExceptionOnMissing());
412         c.addProperty("string", "test string");
413 
414         assertEquals("test string", c.getString("string"));
415         try
416         {
417             c.getString("XXX");
418             fail("Should throw NoSuchElementException exception");
419         }
420         catch (NoSuchElementException e)
421         {
422             //ok
423         }
424         catch (Exception e)
425         {
426             fail("Should throw NoSuchElementException exception, not " + e);
427         }
428 
429         //test defaults
430         assertEquals("test string", c.getString("string", "some default value"));
431         assertEquals("default string", c.getString("default"));
432         assertEquals("default string", c.getString("default", "some default value"));
433         assertEquals("some default value", c.getString("XXX", "some default value"));
434     }
435 
436     @Test
437     public void testCheckingInMemoryConfiguration() throws Exception
438     {
439         String TEST_KEY = "testKey";
440         Configuration defaults = new PropertiesConfiguration();
441         defaults.setProperty(TEST_KEY, "testValue");
442         Configuration testConfiguration = new CompositeConfiguration(defaults);
443         assertTrue(testConfiguration.containsKey(TEST_KEY));
444         assertFalse(testConfiguration.isEmpty());
445         boolean foundTestKey = false;
446         Iterator<String> i = testConfiguration.getKeys();
447         //assertTrue(i instanceof IteratorChain);
448         //IteratorChain ic = (IteratorChain)i;
449         //assertEquals(2,i.size());
450         for (; i.hasNext();)
451         {
452             String key = i.next();
453             if (key.equals(TEST_KEY))
454             {
455                 foundTestKey = true;
456             }
457         }
458         assertTrue(foundTestKey);
459         testConfiguration.clearProperty(TEST_KEY);
460         assertFalse(testConfiguration.containsKey(TEST_KEY));
461     }
462 
463     @Test
464     public void testStringArrayInterpolation()
465     {
466         CompositeConfiguration config = new CompositeConfiguration();
467         config.addProperty("base", "foo");
468         config.addProperty("list", "${base}.bar1");
469         config.addProperty("list", "${base}.bar2");
470         config.addProperty("list", "${base}.bar3");
471 
472         String[] array = config.getStringArray("list");
473         assertEquals("size", 3, array.length);
474         assertEquals("1st element", "foo.bar1", array[0]);
475         assertEquals("2nd element", "foo.bar2", array[1]);
476         assertEquals("3rd element", "foo.bar3", array[2]);
477     }
478 
479     /**
480      * Tests whether global interpolation works with lists.
481      */
482     @Test
483     public void testListInterpolation()
484     {
485         PropertiesConfiguration c1 = new PropertiesConfiguration();
486         c1.addProperty("c1.value", "test1");
487         c1.addProperty("c1.value", "${c2.value}");
488         cc.addConfiguration(c1);
489         PropertiesConfiguration c2 = new PropertiesConfiguration();
490         c2.addProperty("c2.value", "test2");
491         cc.addConfiguration(c2);
492         List<Object> lst = cc.getList("c1.value");
493         assertEquals("Wrong list size", 2, lst.size());
494         assertEquals("Wrong first element", "test1", lst.get(0));
495         assertEquals("Wrong second element", "test2", lst.get(1));
496     }
497 
498     /**
499      * Tests interpolation in combination with reloading.
500      */
501     @Test
502     public void testInterpolationWithReload() throws IOException,
503             ConfigurationException
504     {
505         File testFile = new File("target/testConfig.properties");
506         final String propFirst = "first.name";
507         final String propFull = "full.name";
508 
509         try
510         {
511             writeTestConfig(testFile, propFirst, "John");
512             PropertiesConfiguration c1 = new PropertiesConfiguration(testFile);
513             c1.setReloadingStrategy(new FileAlwaysReloadingStrategy());
514             PropertiesConfiguration c2 = new PropertiesConfiguration();
515             c2.addProperty(propFull, "${" + propFirst + "} Doe");
516             CompositeConfiguration cc = new CompositeConfiguration();
517             cc.addConfiguration(c1);
518             cc.addConfiguration(c2);
519             assertEquals("Wrong name", "John Doe", cc.getString(propFull));
520 
521             writeTestConfig(testFile, propFirst, "Jane");
522             assertEquals("First name not changed", "Jane", c1
523                     .getString(propFirst));
524             assertEquals("First name not changed in composite", "Jane", cc
525                     .getString(propFirst));
526             assertEquals("Full name not changed", "Jane Doe", cc
527                     .getString(propFull));
528         }
529         finally
530         {
531             if (testFile.exists())
532             {
533                 testFile.delete();
534             }
535         }
536     }
537 
538     /**
539      * Writes a test properties file containing a single property definition.
540      *
541      * @param f the file to write
542      * @param prop the property name
543      * @param value the property value
544      * @throws IOException if an error occurs
545      */
546     private void writeTestConfig(File f, String prop, String value)
547             throws IOException
548     {
549         PrintWriter out = new PrintWriter(new FileWriter(f));
550         out.print(prop);
551         out.print("=");
552         out.println(value);
553         out.close();
554     }
555 
556     @Test
557     public void testInstanciateWithCollection()
558     {
559         Collection<Configuration> configs = new ArrayList<Configuration>();
560         configs.add(xmlConf);
561         configs.add(conf1);
562         configs.add(conf2);
563 
564         CompositeConfiguration config = new CompositeConfiguration(configs);
565         assertEquals("Number of configurations", 4, config.getNumberOfConfigurations());
566         assertTrue("The in memory configuration is not empty", config.getInMemoryConfiguration().isEmpty());
567     }
568 
569     @Test
570     public void testClone()
571     {
572         CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone();
573         assertEquals("Wrong number of contained configurations", cc
574                 .getNumberOfConfigurations(), cc2.getNumberOfConfigurations());
575 
576         StrictConfigurationComparator comp = new StrictConfigurationComparator();
577         for (int i = 0; i < cc.getNumberOfConfigurations(); i++)
578         {
579             assertEquals("Wrong configuration class at " + i, cc
580                     .getConfiguration(i).getClass(), cc2.getConfiguration(i)
581                     .getClass());
582             assertNotSame("Configuration was not cloned", cc
583                     .getConfiguration(i), cc2.getConfiguration(i));
584             assertTrue("Configurations at " + i + " not equal", comp.compare(cc
585                     .getConfiguration(i), cc2.getConfiguration(i)));
586         }
587 
588         assertTrue("Configurations are not equal", comp.compare(cc, cc2));
589     }
590 
591     /**
592      * Tests cloning if one of the contained configurations does not support
593      * this operation. This should cause an exception.
594      */
595     @Test(expected = ConfigurationRuntimeException.class)
596     public void testCloneNotSupported()
597     {
598         cc.addConfiguration(new NonCloneableConfiguration());
599         cc.clone();
600     }
601 
602     /**
603      * Ensures that event listeners are not cloned.
604      */
605     @Test
606     public void testCloneEventListener()
607     {
608         cc.addConfigurationListener(new TestEventListenerImpl());
609         CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone();
610         assertTrue("Listeners have been cloned", cc2
611                 .getConfigurationListeners().isEmpty());
612     }
613 
614     /**
615      * Tests whether add property events are triggered.
616      */
617     @Test
618     public void testEventAddProperty()
619     {
620         TestEventListenerImpl l = new TestEventListenerImpl();
621         cc.addConfigurationListener(l);
622         cc.addProperty("test", "value");
623         assertEquals("No add events received", 2, l.eventCount);
624     }
625 
626     /**
627      * Tests whether set property events are triggered.
628      */
629     @Test
630     public void testEventSetProperty()
631     {
632         TestEventListenerImpl l = new TestEventListenerImpl();
633         cc.addConfigurationListener(l);
634         cc.setProperty("test", "value");
635         assertEquals("No set events received", 2, l.eventCount);
636     }
637 
638     /**
639      * Tests whether clear property events are triggered.
640      */
641     @Test
642     public void testEventClearProperty()
643     {
644         cc.addConfiguration(conf1);
645         assertTrue("Wrong value for property", cc
646                 .getBoolean("configuration.loaded"));
647         TestEventListenerImpl l = new TestEventListenerImpl();
648         cc.addConfigurationListener(l);
649         cc.clearProperty("configuration.loaded");
650         assertFalse("Key still present", cc.containsKey("configuration.loaded"));
651         assertEquals("No clear events received", 2, l.eventCount);
652     }
653 
654     /**
655      * Tests changing the list delimiter character.
656      */
657     @Test
658     public void testSetListDelimiter()
659     {
660         cc.setListDelimiter('/');
661         checkSetListDelimiter();
662     }
663 
664     /**
665      * Tests whether the correct list delimiter is set after a clear operation.
666      */
667     @Test
668     public void testSetListDelimiterAfterClear()
669     {
670         cc.setListDelimiter('/');
671         cc.clear();
672         checkSetListDelimiter();
673     }
674 
675     /**
676      * Helper method for testing whether the list delimiter is correctly
677      * handled.
678      */
679     private void checkSetListDelimiter()
680     {
681         cc.addProperty("test.list", "a/b/c");
682         cc.addProperty("test.property", "a,b,c");
683         assertEquals("Wrong number of list elements", 3, cc
684                 .getList("test.list").size());
685         assertEquals("Wrong value of property", "a,b,c", cc
686                 .getString("test.property"));
687     }
688 
689     /**
690      * Tests whether list splitting can be disabled.
691      */
692     @Test
693     public void testSetDelimiterParsingDisabled()
694     {
695         cc.setDelimiterParsingDisabled(true);
696         checkSetListDelimiterParsingDisabled();
697     }
698 
699     /**
700      * Tests whether the list parsing flag is correctly handled after a clear()
701      * operation.
702      */
703     @Test
704     public void testSetDelimiterParsingDisabledAfterClear()
705     {
706         cc.setDelimiterParsingDisabled(true);
707         cc.clear();
708         checkSetListDelimiterParsingDisabled();
709     }
710 
711     /**
712      * Helper method for checking whether the list parsing flag is correctly
713      * handled.
714      */
715     private void checkSetListDelimiterParsingDisabled()
716     {
717         cc.addProperty("test.property", "a,b,c");
718         assertEquals("Wrong value of property", "a,b,c", cc
719                 .getString("test.property"));
720     }
721 
722     /**
723      * Prepares a test of the getSource() method.
724      */
725     private void setUpSourceTest()
726     {
727         cc.addConfiguration(conf1);
728         cc.addConfiguration(conf2);
729     }
730 
731     /**
732      * Tests the getSource() method if the property is defined in a single child
733      * configuration.
734      */
735     @Test
736     public void testGetSourceSingle()
737     {
738         setUpSourceTest();
739         conf1.addProperty(TEST_PROPERTY, Boolean.TRUE);
740         assertSame("Wrong source configuration", conf1, cc
741                 .getSource(TEST_PROPERTY));
742     }
743 
744     /**
745      * Tests the getSource() method for an unknown property key.
746      */
747     @Test
748     public void testGetSourceUnknown()
749     {
750         setUpSourceTest();
751         assertNull("Wrong source for unknown key", cc.getSource(TEST_PROPERTY));
752     }
753 
754     /**
755      * Tests the getSource() method for a property contained in the in memory
756      * configuration.
757      */
758     @Test
759     public void testGetSourceInMemory()
760     {
761         setUpSourceTest();
762         cc.addProperty(TEST_PROPERTY, Boolean.TRUE);
763         assertSame("Source not found in in-memory config", cc
764                 .getInMemoryConfiguration(), cc.getSource(TEST_PROPERTY));
765     }
766 
767     /**
768      * Tests the getSource() method if the property is defined by multiple child
769      * configurations. In this case an exception should be thrown.
770      */
771     @Test(expected = IllegalArgumentException.class)
772     public void testGetSourceMultiple()
773     {
774         setUpSourceTest();
775         conf1.addProperty(TEST_PROPERTY, Boolean.TRUE);
776         cc.addProperty(TEST_PROPERTY, "a value");
777         cc.getSource(TEST_PROPERTY);
778     }
779 
780     /**
781      * Tests the getSource() method for a null key. This should cause an
782      * exception.
783      */
784     @Test(expected = IllegalArgumentException.class)
785     public void testGetSourceNull()
786     {
787         cc.getSource(null);
788     }
789 
790     /**
791      * Prepares a test for interpolation with multiple configurations and
792      * similar properties.
793      */
794     private void prepareInterpolationTest()
795     {
796         PropertiesConfiguration p = new PropertiesConfiguration();
797         p.addProperty("foo", "initial");
798         p.addProperty("bar", "${foo}");
799         p.addProperty("prefix.foo", "override");
800 
801         cc.addConfiguration(p.subset("prefix"));
802         cc.addConfiguration(p);
803         assertEquals("Wrong value on direct access", "override", cc
804                 .getString("bar"));
805     }
806 
807     /**
808      * Tests querying a list when a tricky interpolation is involved. This is
809      * related to CONFIGURATION-339.
810      */
811     @Test
812     public void testGetListWithInterpolation()
813     {
814         prepareInterpolationTest();
815         List<Object> lst = cc.getList("bar");
816         assertEquals("Wrong number of values", 1, lst.size());
817         assertEquals("Wrong value in list", "override", lst.get(0));
818     }
819 
820     /**
821      * Tests querying a string array when a tricky interpolation is involved.
822      */
823     @Test
824     public void testGetStringArrayWithInterpolation()
825     {
826         prepareInterpolationTest();
827         String[] values = cc.getStringArray("bar");
828         assertEquals("Wrong number of values", 1, values.length);
829         assertEquals("Wrong value in array", "override", values[0]);
830     }
831 
832     /**
833      * Tests whether interpolation works if multiple configurations are
834      * involved. This test is related to CONFIGURATION-441.
835      */
836     @Test
837     public void testInterpolationInMultipleConfigs()
838     {
839         Configuration c1 = new PropertiesConfiguration();
840         c1.addProperty("property.one", "one");
841         c1.addProperty("property.two", "two");
842         Configuration c2 = new PropertiesConfiguration();
843         c2.addProperty("property.one.ref", "${property.one}");
844         cc.addConfiguration(c1);
845         cc.addConfiguration(c2);
846         assertEquals("Wrong interpolated value", "one",
847                 cc.getString("property.one.ref"));
848     }
849 
850     /**
851      * Tests the behavior of setListDelimiter() if the in-memory configuration
852      * is not derived from BaseConfiguration. This test is related to
853      * CONFIGURATION-476.
854      */
855     @Test
856     public void testSetListDelimiterInMemoryConfigNonBaseConfig()
857     {
858         Configuration inMemoryConfig = EasyMock.createMock(Configuration.class);
859         EasyMock.replay(inMemoryConfig);
860         cc = new CompositeConfiguration(inMemoryConfig);
861         cc.setListDelimiter(';');
862     }
863 
864     /**
865      * Tests the behavior of setDelimiterParsingDisabled() if the in-memory
866      * configuration is not derived from BaseConfiguration. This test is related
867      * to CONFIGURATION-476.
868      */
869     @Test
870     public void testSetDelimiterParsingDisabledInMemoryConfigNonBaseConfig()
871     {
872         Configuration inMemoryConfig = EasyMock.createMock(Configuration.class);
873         EasyMock.replay(inMemoryConfig);
874         cc = new CompositeConfiguration(inMemoryConfig);
875         cc.setDelimiterParsingDisabled(true);
876     }
877 
878     /**
879      * Tests whether a configuration can act as both regular child configuration
880      * and in-memory configuration. This test is related to CONFIGURATION-471.
881      */
882     @Test
883     public void testUseChildConfigAsInMemoryConfig()
884     {
885         conf1.setProperty(TEST_PROPERTY, "conf1");
886         conf2.setProperty(TEST_PROPERTY, "conf2");
887         cc.addConfiguration(conf1, true);
888         cc.addConfiguration(conf2);
889         assertEquals("Wrong number of configurations", 2,
890                 cc.getNumberOfConfigurations());
891         assertEquals("Wrong property", "conf1", cc.getString(TEST_PROPERTY));
892         cc.addProperty("newProperty", "newValue");
893         assertEquals("Not added to in-memory config", "newValue",
894                 conf1.getString("newProperty"));
895     }
896 
897     /**
898      * Tests whether the in-memory configuration can be replaced by a new child
899      * configuration.
900      */
901     @Test
902     public void testReplaceInMemoryConfig()
903     {
904         conf1.setProperty(TEST_PROPERTY, "conf1");
905         conf2.setProperty(TEST_PROPERTY, "conf2");
906         cc.addConfiguration(conf1, true);
907         cc.addProperty("newProperty1", "newValue1");
908         cc.addConfiguration(conf2, true);
909         cc.addProperty("newProperty2", "newValue2");
910         assertEquals("Wrong property", "conf1", cc.getString(TEST_PROPERTY));
911         assertEquals("Not added to in-memory config", "newValue1",
912                 conf1.getString("newProperty1"));
913         assertEquals("In-memory config not changed", "newValue2",
914                 conf2.getString("newProperty2"));
915     }
916 
917     /**
918      * A test configuration event listener that counts the number of received
919      * events. Used for testing the event facilities.
920      */
921     static class TestEventListenerImpl implements ConfigurationListener
922     {
923         /** The number of received events.*/
924         int eventCount;
925 
926         public void configurationChanged(ConfigurationEvent event)
927         {
928             eventCount++;
929         }
930     }
931 }