    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 java.io.File;
    21  import java.util.ArrayList;
    22  import java.util.Iterator;
    23  import java.util.List;
    24  import java.util.NoSuchElementException;
    25  import java.util.Collection;
    26
    27  import org.apache.commons.configuration.event.ConfigurationEvent;
    28  import org.apache.commons.configuration.event.ConfigurationListener;
    29
    30  import junit.framework.TestCase;
    31
    32  /***
    33   * Test loading multiple configurations.
    34   *
    35   * @version $Id: TestCompositeConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
    36   */
    37  public class TestCompositeConfiguration extends TestCase
    38  {
    39      protected PropertiesConfiguration conf1;
    40      protected PropertiesConfiguration conf2;
    41      protected XMLConfiguration xmlConf;
    42      protected CompositeConfiguration cc;
    43
    44      /***
    45       * The File that we test with
    46       */
    47      private String testProperties = new File("conf/test.properties").getAbsolutePath();
    48      private String testProperties2 = new File("conf/test2.properties").getAbsolutePath();
    49      private String testPropertiesXML = new File("conf/test.xml").getAbsolutePath();
    50
    51      protected void setUp() throws Exception
    52      {
    53          cc = new CompositeConfiguration();
    54          conf1 = new PropertiesConfiguration(testProperties);
    55          conf2 = new PropertiesConfiguration(testProperties2);
    56          xmlConf = new XMLConfiguration(new File(testPropertiesXML));
    57
    58          cc.setThrowExceptionOnMissing(true);
    59      }
    60
    61      public void testThrowExceptionOnMissing()
    62      {
    63          assertTrue("Throw Exception Property is not set!", cc.isThrowExceptionOnMissing());
    64      }
    65
    66      public void testAddRemoveConfigurations() throws Exception
    67      {
    68          cc.addConfiguration(conf1);
    69          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
    70          cc.addConfiguration(conf1);
    71          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
    72          cc.addConfiguration(conf2);
    73          assertEquals("Number of configurations", 3, cc.getNumberOfConfigurations());
    74          cc.removeConfiguration(conf1);
    75          assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations());
    76          cc.clear();
    77          assertEquals("Number of configurations", 1, cc.getNumberOfConfigurations());
    78      }
    79
    80      public void testGetPropertyWIncludes() throws Exception
    81      {
    82          cc.addConfiguration(conf1);
    83          cc.addConfiguration(conf2);
    84          List l = cc.getList("packages");
    85          assertTrue(l.contains("packagea"));
    86      }
    87
    88      public void testGetProperty() throws Exception
    89      {
    90          cc.addConfiguration(conf1);
    91          cc.addConfiguration(conf2);
    92          assertEquals("Make sure we get the property from conf1 first", "test.properties", cc.getString("propertyInOrder"));
    93          cc.clear();
    94
    95          cc.addConfiguration(conf2);
    96          cc.addConfiguration(conf1);
    97          assertEquals("Make sure we get the property from conf2 first", "test2.properties", cc.getString("propertyInOrder"));
    98      }
    99
    100     public void testCantRemoveMemoryConfig() throws Exception
    101     {
    102         cc.clear();
    103         assertEquals(1, cc.getNumberOfConfigurations());
    104
    105         Configuration internal = cc.getConfiguration(0);
    106         cc.removeConfiguration(internal);
    107
    108         assertEquals(1, cc.getNumberOfConfigurations());
    109     }
    110
    111     public void testGetPropertyMissing() throws Exception
    112     {
    113         cc.addConfiguration(conf1);
    114         cc.addConfiguration(conf2);
    115         try
    116         {
    117             assertNull(cc.getString("bogus.property"));
    118             fail("Should have thrown a NoSuchElementException");
    119         }
    120         catch (NoSuchElementException nsee)
    121         {
    122             assertTrue(nsee.getMessage().indexOf("bogus.property") > -1);
    123         }
    124
    125         assertTrue("Should be false", !cc.getBoolean("test.missing.boolean", false));
    126         assertTrue("Should be true", cc.getBoolean("test.missing.boolean.true", true));
    127     }
    128
    129     /***
    130      * Tests <code>List</code> parsing.
    131      */
    132     public void testMultipleTypesOfConfigs() throws Exception
    133     {
    134         cc.addConfiguration(conf1);
    135         cc.addConfiguration(xmlConf);
    136         assertEquals("Make sure we get the property from conf1 first", 1, cc.getInt("test.short"));
    137         cc.clear();
    138
    139         cc.addConfiguration(xmlConf);
    140         cc.addConfiguration(conf1);
    141         assertEquals("Make sure we get the property from xml", 8, cc.getInt("test.short"));
    142     }
    143
    144     /***
    145      * Tests <code>List</code> parsing.
    146      */
    147     public void testPropertyExistsInOnlyOneConfig() throws Exception
    148     {
    149         cc.addConfiguration(conf1);
    150         cc.addConfiguration(xmlConf);
    151         assertEquals("value", cc.getString("element"));
    152     }
    153
    154     /***
    155      * Tests getting a default when the key doesn't exist
    156      */
    157     public void testDefaultValueWhenKeyMissing() throws Exception
    158     {
    159         cc.addConfiguration(conf1);
    160         cc.addConfiguration(xmlConf);
    161         assertEquals("default", cc.getString("bogus", "default"));
    162         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
    163         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
    164     }
    165
    166     /***
    167      * Tests <code>List</code> parsing.
    168      */
    169     public void testGettingConfiguration() throws Exception
    170     {
    171         cc.addConfiguration(conf1);
    172         cc.addConfiguration(xmlConf);
    173         assertEquals(PropertiesConfiguration.class, cc.getConfiguration(0).getClass());
    174         assertEquals(XMLConfiguration.class, cc.getConfiguration(1).getClass());
    175     }
    176
    177     /***
    178      * Tests setting values.  These are set in memory mode only!
    179      */
    180     public void testClearingProperty() throws Exception
    181     {
    182         cc.addConfiguration(conf1);
    183         cc.addConfiguration(xmlConf);
    184         cc.clearProperty("test.short");
    185         assertTrue("Make sure test.short is gone!", !cc.containsKey("test.short"));
    186     }
    187
    188     /***
    189      * Tests adding values.  Make sure they _DON'T_ override any other properties but add to the
    190      * existing properties  and keep sequence
    191      */
    192     public void testAddingProperty() throws Exception
    193     {
    194         cc.addConfiguration(conf1);
    195         cc.addConfiguration(xmlConf);
    196
    197         String[] values = cc.getStringArray("test.short");
    198
    199         assertEquals("Number of values before add is wrong!", 1, values.length);
    200         assertEquals("First Value before add is wrong", "1", values[0]);
    201
    202         cc.addProperty("test.short", "88");
    203
    204         values = cc.getStringArray("test.short");
    205
    206         assertEquals("Number of values is wrong!", 2, values.length);
    207         assertEquals("First Value is wrong", "1", values[0]);
    208         assertEquals("Third Value is wrong", "88", values[1]);
    209     }
    210
    211     /***
    212      * Tests setting values.  These are set in memory mode only!
    213      */
    214     public void testSettingMissingProperty() throws Exception
    215     {
    216         cc.addConfiguration(conf1);
    217         cc.addConfiguration(xmlConf);
    218         cc.setProperty("my.new.property", "supernew");
    219         assertEquals("supernew", cc.getString("my.new.property"));
    220     }
    221
    222     /***
    223      * Tests retrieving subsets of configurations
    224      */
    225     public void testGettingSubset() throws Exception
    226     {
    227         cc.addConfiguration(conf1);
    228         cc.addConfiguration(xmlConf);
    229
    230         Configuration subset = cc.subset("test");
    231         assertNotNull(subset);
    232         assertFalse("Shouldn't be empty", subset.isEmpty());
    233         assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "1", subset.getString("short"));
    234
    235         cc.setProperty("test.short", "43");
    236         subset = cc.subset("test");
    237         assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "43", subset.getString("short"));
    238     }
    239
    240     /***
    241      * Tests subsets and still can resolve elements
    242      */
    243     public void testSubsetCanResolve() throws Exception
    244     {
    245         cc = new CompositeConfiguration();
    246         final BaseConfiguration config = new BaseConfiguration();
    247         config.addProperty("subset.tempfile", "${java.io.tmpdir}/file.tmp");
    248         cc.addConfiguration(config);
    249         cc.addConfiguration(ConfigurationConverter.getConfiguration(System.getProperties()));
    250
    251         Configuration subset = cc.subset("subset");
    252         assertEquals(System.getProperty("java.io.tmpdir") + "/file.tmp", subset.getString("tempfile"));
    253     }
    254
    255     /***
    256      * Tests <code>List</code> parsing.
    257      */
    258     public void testList() throws Exception
    259     {
    260         cc.addConfiguration(conf1);
    261         cc.addConfiguration(xmlConf);
    262
    263         List packages = cc.getList("packages");
    264         // we should get 3 packages here
    265         assertEquals(3, packages.size());
    266
    267         List defaultList = new ArrayList();
    268         defaultList.add("1");
    269         defaultList.add("2");
    270
    271         packages = cc.getList("packages.which.dont.exist", defaultList);
    272         // we should get 2 packages here
    273         assertEquals(2, packages.size());
    274
    275     }
    276
    277     /***
    278      * Tests <code>String</code> array parsing.
    279      */
    280     public void testStringArray() throws Exception
    281     {
    282         cc.addConfiguration(conf1);
    283         cc.addConfiguration(xmlConf);
    284
    285         String[] packages = cc.getStringArray("packages");
    286         // we should get 3 packages here
    287         assertEquals(3, packages.length);
    288
    289         packages = cc.getStringArray("packages.which.dont.exist");
    290         // we should get 0 packages here
    291         assertEquals(0, packages.length);
    292     }
    293
    294     public void testGetList()
    295     {
    296         Configuration conf1 = new BaseConfiguration();
    297         conf1.addProperty("array", "value1");
    298         conf1.addProperty("array", "value2");
    299
    300         Configuration conf2 = new BaseConfiguration();
    301         conf2.addProperty("array", "value3");
    302         conf2.addProperty("array", "value4");
    303
    304         cc.addConfiguration(conf1);
    305         cc.addConfiguration(conf2);
    306
    307         // check the composite 'array' property
    308         List list = cc.getList("array");
    309         assertNotNull("null list", list);
    310         assertEquals("list size", 2, list.size());
    311         assertTrue("'value1' not found in the list", list.contains("value1"));
    312         assertTrue("'value2' not found in the list", list.contains("value2"));
    313
    314         // add an element to the list in the composite configuration
    315         cc.addProperty("array", "value5");
    316
    317         // test the new list
    318         list = cc.getList("array");
    319         assertNotNull("null list", list);
    320         assertEquals("list size", 3, list.size());
    321         assertTrue("'value1' not found in the list", list.contains("value1"));
    322         assertTrue("'value2' not found in the list", list.contains("value2"));
    323         assertTrue("'value5' not found in the list", list.contains("value5"));
    324     }
    325
    326     /***
    327      * Tests <code>getKeys</code> preserves the order
    328      */
    329     public void testGetKeysPreservesOrder() throws Exception
    330     {
    331         cc.addConfiguration(conf1);
    332         List orderedList = new ArrayList();
    333         for (Iterator keys = conf1.getKeys(); keys.hasNext();)
    334         {
    335             orderedList.add(keys.next());
    336         }
    337         List iteratedList = new ArrayList();
    338         for (Iterator keys = cc.getKeys(); keys.hasNext();)
    339         {
    340             iteratedList.add(keys.next());
    341         }
    342         assertEquals(orderedList.size(), iteratedList.size());
    343         for (int i = 0; i < orderedList.size(); i++)
    344         {
    345             assertEquals(orderedList.get(i), iteratedList.get(i));
    346         }
    347     }
    348
    349     /***
    350      * Tests <code>getKeys(String key)</code> preserves the order
    351      */
    352     public void testGetKeys2PreservesOrder() throws Exception
    353     {
    354         cc.addConfiguration(conf1);
    355         List orderedList = new ArrayList();
    356         for (Iterator keys = conf1.getKeys("test"); keys.hasNext();)
    357         {
    358             orderedList.add(keys.next());
    359         }
    360         List iteratedList = new ArrayList();
    361         for (Iterator keys = cc.getKeys("test"); keys.hasNext();)
    362         {
    363             iteratedList.add(keys.next());
    364         }
    365         assertEquals(orderedList.size(), iteratedList.size());
    366         for (int i = 0; i < orderedList.size(); i++)
    367         {
    368             assertEquals(orderedList.get(i), iteratedList.get(i));
    369         }
    370     }
    371
    372     public void testGetStringWithDefaults()
    373     {
    374         BaseConfiguration defaults = new BaseConfiguration();
    375         defaults.addProperty("default", "default string");
    376
    377         CompositeConfiguration c = new CompositeConfiguration(defaults);
    378         c.setThrowExceptionOnMissing(cc.isThrowExceptionOnMissing());
    379         c.addProperty("string", "test string");
    380
    381         assertEquals("test string", c.getString("string"));
    382         try
    383         {
    384             c.getString("XXX");
    385             fail("Should throw NoSuchElementException exception");
    386         }
    387         catch (NoSuchElementException e)
    388         {
    389             //ok
    390         }
    391         catch (Exception e)
    392         {
    393             fail("Should throw NoSuchElementException exception, not " + e);
    394         }
    395
    396         //test defaults
    397         assertEquals("test string", c.getString("string", "some default value"));
    398         assertEquals("default string", c.getString("default"));
    399         assertEquals("default string", c.getString("default", "some default value"));
    400         assertEquals("some default value", c.getString("XXX", "some default value"));
    401     }
    402
    403     public void testCheckingInMemoryConfiguration() throws Exception
    404     {
    405         String TEST_KEY = "testKey";
    406         Configuration defaults = new PropertiesConfiguration();
    407         defaults.setProperty(TEST_KEY, "testValue");
    408         Configuration testConfiguration = new CompositeConfiguration(defaults);
    409         assertTrue(testConfiguration.containsKey(TEST_KEY));
    410         assertFalse(testConfiguration.isEmpty());
    411         boolean foundTestKey = false;
    412         Iterator i = testConfiguration.getKeys();
    413         //assertTrue(i instanceof IteratorChain);
    414         //IteratorChain ic = (IteratorChain)i;
    415         //assertEquals(2,i.size());
    416         for (; i.hasNext();)
    417         {
    418             String key = (String) i.next();
    419             if (key.equals(TEST_KEY))
    420             {
    421                 foundTestKey = true;
    422             }
    423         }
    424         assertTrue(foundTestKey);
    425         testConfiguration.clearProperty(TEST_KEY);
    426         assertFalse(testConfiguration.containsKey(TEST_KEY));
    427     }
    428
    429     public void testStringArrayInterpolation()
    430     {
    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     public void testInstanciateWithCollection()
    445     {
    446         Collection configs = new ArrayList();
    447         configs.add(xmlConf);
    448         configs.add(conf1);
    449         configs.add(conf2);
    450
    451         CompositeConfiguration config = new CompositeConfiguration(configs);
    452         assertEquals("Number of configurations", 4, config.getNumberOfConfigurations());
    453         assertTrue("The in memory configuration is not empty", config.getInMemoryConfiguration().isEmpty());
    454     }
    455
    456     public void testClone()
    457     {
    458         CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone();
    459         assertEquals("Wrong number of contained configurations", cc
    460                 .getNumberOfConfigurations(), cc2.getNumberOfConfigurations());
    461
    462         StrictConfigurationComparator comp = new StrictConfigurationComparator();
    463         for (int i = 0; i < cc.getNumberOfConfigurations(); i++)
    464         {
    465             assertEquals("Wrong configuration class at " + i, cc
    466                     .getConfiguration(i).getClass(), cc2.getConfiguration(i)
    467                     .getClass());
    468             assertNotSame("Configuration was not cloned", cc
    469                     .getConfiguration(i), cc2.getConfiguration(i));
    470             assertTrue("Configurations at " + i + " not equal", comp.compare(cc
    471                     .getConfiguration(i), cc2.getConfiguration(i)));
    472         }
    473
    474         assertTrue("Configurations are not equal", comp.compare(cc, cc2));
    475     }
    476
    477     /***
    478      * Tests cloning if one of the contained configurations does not support
    479      * this operation. This should cause an exception.
    480      */
    481     public void testCloneNotSupported()
    482     {
    483         cc.addConfiguration(new NonCloneableConfiguration());
    484         try
    485         {
    486             cc.clone();
    487             fail("Could clone non cloneable configuration!");
    488         }
    489         catch (ConfigurationRuntimeException crex)
    490         {
    491             // ok
    492         }
    493     }
    494
    495     /***
    496      * Ensures that event listeners are not cloned.
    497      */
    498     public void testCloneEventListener()
    499     {
    500         cc.addConfigurationListener(new ConfigurationListener()
    501         {
    502             public void configurationChanged(ConfigurationEvent event)
    503             {
    504                 // Just a dummy
    505             }
    506         });
    507         CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone();
    508         assertTrue("Listeners have been cloned", cc2
    509                 .getConfigurationListeners().isEmpty());
    510     }
    511 }