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  package org.apache.commons.configuration;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.collections.CollectionUtils;
32  import org.apache.commons.configuration.event.ConfigurationEvent;
33  import org.apache.commons.configuration.event.ConfigurationListener;
34  import org.junit.Test;
35  
36  /**
37   * A test class for some of the basic functionality implemented by
38   * AbstractConfiguration.
39   *
40   * @version $Id: TestAbstractConfigurationBasicFeatures.java 1222823 2011-12-23 20:03:10Z oheger $
41   */
42  public class TestAbstractConfigurationBasicFeatures
43  {
44      /** Constant for the prefix of test keys.*/
45      private static final String KEY_PREFIX = "key";
46  
47      /** Constant for the number of properties in tests for copy operations.*/
48      private static final int PROP_COUNT = 12;
49  
50      /**
51       * Tests the clear() implementation of AbstractConfiguration if the iterator
52       * returned by getKeys() does not support the remove() operation.
53       */
54      @Test
55      public void testClearIteratorNoRemove()
56      {
57          AbstractConfiguration config = new TestConfigurationImpl(
58                  new BaseConfiguration())
59          {
60              // return an iterator that does not support remove operations
61              @Override
62              public Iterator<String> getKeys()
63              {
64                  Collection<String> keyCol = new ArrayList<String>();
65                  CollectionUtils.addAll(keyCol, getUnderlyingConfiguration()
66                          .getKeys());
67                  String[] keys = keyCol.toArray(new String[keyCol.size()]);
68                  return Arrays.asList(keys).iterator();
69              }
70          };
71          for (int i = 0; i < 20; i++)
72          {
73              config.addProperty("key" + i, "value" + i);
74          }
75          config.clear();
76          assertTrue("Configuration not empty", config.isEmpty());
77      }
78  
79      /**
80       * Tests escaping the variable marker, so that no interpolation will be
81       * performed.
82       */
83      @Test
84      public void testInterpolateEscape()
85      {
86          AbstractConfiguration config = new TestConfigurationImpl(
87                  new PropertiesConfiguration());
88          config
89                  .addProperty(
90                          "mypath",
91                          "$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar\\,$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar");
92          assertEquals(
93                  "Wrong interpolated value",
94                  "${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar,${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar",
95                  config.getString("mypath"));
96      }
97  
98      /**
99       * Tests adding list properties. The single elements of the list should be
100      * added.
101      */
102     @Test
103     public void testAddPropertyList()
104     {
105         checkAddListProperty(new TestConfigurationImpl(
106                 new PropertiesConfiguration()));
107     }
108 
109     /**
110      * Tests adding list properties when delimiter parsing is disabled.
111      */
112     @Test
113     public void testAddPropertyListNoDelimiterParsing()
114     {
115         AbstractConfiguration config = new TestConfigurationImpl(
116                 new PropertiesConfiguration());
117         config.setDelimiterParsingDisabled(true);
118         checkAddListProperty(config);
119     }
120 
121     /**
122      * Helper method for adding properties with multiple values.
123      *
124      * @param config the configuration to be used for testing
125      */
126     private void checkAddListProperty(AbstractConfiguration config)
127     {
128         config.addProperty("test", "value1");
129         Object[] lstValues1 = new Object[]
130         { "value2", "value3" };
131         Object[] lstValues2 = new Object[]
132         { "value4", "value5", "value6" };
133         config.addProperty("test", lstValues1);
134         config.addProperty("test", Arrays.asList(lstValues2));
135         List<Object> lst = config.getList("test");
136         assertEquals("Wrong number of list elements", 6, lst.size());
137         for (int i = 0; i < lst.size(); i++)
138         {
139             assertEquals("Wrong list element at " + i, "value" + (i + 1), lst
140                     .get(i));
141         }
142     }
143 
144     /**
145      * Tests the copy() method.
146      */
147     @Test
148     public void testCopy()
149     {
150         AbstractConfiguration config = setUpDestConfig();
151         Configuration srcConfig = setUpSourceConfig();
152         config.copy(srcConfig);
153         for (int i = 0; i < PROP_COUNT; i++)
154         {
155             String key = KEY_PREFIX + i;
156             if (srcConfig.containsKey(key))
157             {
158                 assertEquals("Value not replaced: " + key, srcConfig
159                         .getProperty(key), config.getProperty(key));
160             }
161             else
162             {
163                 assertEquals("Value modified: " + key, "value" + i, config
164                         .getProperty(key));
165             }
166         }
167     }
168 
169     /**
170      * Tests the copy() method when properties with multiple values and escaped
171      * list delimiters are involved.
172      */
173     @Test
174     public void testCopyWithLists()
175     {
176         Configuration srcConfig = setUpSourceConfig();
177         AbstractConfiguration config = setUpDestConfig();
178         config.copy(srcConfig);
179         checkListProperties(config);
180     }
181 
182     /**
183      * Tests the events generated by a copy() operation.
184      */
185     @Test
186     public void testCopyEvents()
187     {
188         AbstractConfiguration config = setUpDestConfig();
189         Configuration srcConfig = setUpSourceConfig();
190         CollectingConfigurationListener l = new CollectingConfigurationListener();
191         config.addConfigurationListener(l);
192         config.copy(srcConfig);
193         checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_SET_PROPERTY);
194     }
195 
196     /**
197      * Tests copying a null configuration. This should be a noop.
198      */
199     @Test
200     public void testCopyNull()
201     {
202         AbstractConfiguration config = setUpDestConfig();
203         config.copy(null);
204         ConfigurationAssert.assertEquals(setUpDestConfig(), config);
205     }
206 
207     /**
208      * Tests the append() method.
209      */
210     @Test
211     public void testAppend()
212     {
213         AbstractConfiguration config = setUpDestConfig();
214         Configuration srcConfig = setUpSourceConfig();
215         config.append(srcConfig);
216         for (int i = 0; i < PROP_COUNT; i++)
217         {
218             String key = KEY_PREFIX + i;
219             if (srcConfig.containsKey(key))
220             {
221                 List<Object> values = config.getList(key);
222                 assertEquals("Value not added: " + key, 2, values.size());
223                 assertEquals("Wrong value 1 for " + key, "value" + i, values
224                         .get(0));
225                 assertEquals("Wrong value 2 for " + key, "src" + i, values
226                         .get(1));
227             }
228             else
229             {
230                 assertEquals("Value modified: " + key, "value" + i, config
231                         .getProperty(key));
232             }
233         }
234     }
235 
236     /**
237      * Tests the append() method when properties with multiple values and
238      * escaped list delimiters are involved.
239      */
240     @Test
241     public void testAppendWithLists()
242     {
243         AbstractConfiguration config = setUpDestConfig();
244         config.append(setUpSourceConfig());
245         checkListProperties(config);
246     }
247 
248     /**
249      * Tests the events generated by an append() operation.
250      */
251     @Test
252     public void testAppendEvents()
253     {
254         AbstractConfiguration config = setUpDestConfig();
255         Configuration srcConfig = setUpSourceConfig();
256         CollectingConfigurationListener l = new CollectingConfigurationListener();
257         config.addConfigurationListener(l);
258         config.append(srcConfig);
259         checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_ADD_PROPERTY);
260     }
261 
262     /**
263      * Tests appending a null configuration. This should be a noop.
264      */
265     @Test
266     public void testAppendNull()
267     {
268         AbstractConfiguration config = setUpDestConfig();
269         config.append(null);
270         ConfigurationAssert.assertEquals(setUpDestConfig(), config);
271     }
272 
273     /**
274      * Tests whether environment variables can be interpolated.
275      */
276     @Test
277     public void testInterpolateEnvironmentVariables()
278     {
279         AbstractConfiguration config = new TestConfigurationImpl(
280                 new PropertiesConfiguration());
281         EnvironmentConfiguration envConfig = new EnvironmentConfiguration();
282         Map<String, Object> env = new HashMap<String, Object>();
283         for (Iterator<String> it = envConfig.getKeys(); it.hasNext();)
284         {
285             String key = it.next();
286             String propKey = "envtest." + key;
287             env.put(propKey, envConfig.getString(key));
288             config.addProperty(propKey, "${env:" + key + "}");
289         }
290         assertFalse("No environment properties", env.isEmpty());
291         for (Map.Entry<String, Object> e : env.entrySet())
292         {
293             assertEquals("Wrong value for " + e.getKey(), e.getValue(), config
294                     .getString(e.getKey()));
295         }
296     }
297 
298     /**
299      * Tests getList() for single non-string values.
300      */
301     @Test
302     public void testGetListNonString()
303     {
304         checkGetListScalar(Integer.valueOf(42));
305         checkGetListScalar(Long.valueOf(42));
306         checkGetListScalar(Short.valueOf((short) 42));
307         checkGetListScalar(Byte.valueOf((byte) 42));
308         checkGetListScalar(Float.valueOf(42));
309         checkGetListScalar(Double.valueOf(42));
310         checkGetListScalar(Boolean.TRUE);
311 }
312 
313     /**
314      * Tests getStringArray() for single son-string values.
315      */
316     @Test
317     public void testGetStringArrayNonString()
318     {
319         checkGetStringArrayScalar(Integer.valueOf(42));
320         checkGetStringArrayScalar(Long.valueOf(42));
321         checkGetStringArrayScalar(Short.valueOf((short) 42));
322         checkGetStringArrayScalar(Byte.valueOf((byte) 42));
323         checkGetStringArrayScalar(Float.valueOf(42));
324         checkGetStringArrayScalar(Double.valueOf(42));
325         checkGetStringArrayScalar(Boolean.TRUE);
326     }
327 
328     /**
329      * Helper method for checking getList() if the property value is a scalar.
330      * @param value the value of the property
331      */
332     private void checkGetListScalar(Object value)
333     {
334         BaseConfiguration config = new BaseConfiguration();
335         config.addProperty(KEY_PREFIX, value);
336         List<Object> lst = config.getList(KEY_PREFIX);
337         assertEquals("Wrong number of values", 1, lst.size());
338         assertEquals("Wrong value", value.toString(), lst.get(0));
339     }
340 
341     /**
342      * Helper method for checking getStringArray() if the property value is a
343      * scalar.
344      *
345      * @param value the value of the property
346      */
347     private void checkGetStringArrayScalar(Object value)
348     {
349         BaseConfiguration config = new BaseConfiguration();
350         config.addProperty(KEY_PREFIX, value);
351         String[] array = config.getStringArray(KEY_PREFIX);
352         assertEquals("Weong number of elements", 1, array.length);
353         assertEquals("Wrong value", value.toString(), array[0]);
354     }
355 
356     /**
357      * Tests whether interpolation works in variable names.
358      */
359     @Test
360     public void testNestedVariableInterpolation()
361     {
362         BaseConfiguration config = new BaseConfiguration();
363         config.getSubstitutor().setEnableSubstitutionInVariables(true);
364         config.addProperty("java.version", "1.4");
365         config.addProperty("jre-1.4", "C:\\java\\1.4");
366         config.addProperty("jre.path", "${jre-${java.version}}");
367         assertEquals("Wrong path", "C:\\java\\1.4",
368                 config.getString("jre.path"));
369     }
370 
371     /**
372      * Creates the source configuration for testing the copy() and append()
373      * methods. This configuration contains keys with an odd index and values
374      * starting with the prefix "src". There are also some list properties.
375      *
376      * @return the source configuration for copy operations
377      */
378     private Configuration setUpSourceConfig()
379     {
380         BaseConfiguration config = new BaseConfiguration();
381         for (int i = 1; i < PROP_COUNT; i += 2)
382         {
383             config.addProperty(KEY_PREFIX + i, "src" + i);
384         }
385         config.addProperty("list1", "1,2,3");
386         config.addProperty("list2", "3\\,1415,9\\,81");
387         return config;
388     }
389 
390     /**
391      * Creates the destination configuration for testing the copy() and append()
392      * methods. This configuration contains keys with a running index and
393      * corresponding values starting with the prefix "value".
394      *
395      * @return the destination configuration for copy operations
396      */
397     private AbstractConfiguration setUpDestConfig()
398     {
399         AbstractConfiguration config = new TestConfigurationImpl(
400                 new PropertiesConfiguration());
401         for (int i = 0; i < PROP_COUNT; i++)
402         {
403             config.addProperty(KEY_PREFIX + i, "value" + i);
404         }
405         return config;
406     }
407 
408     /**
409      * Tests the values of list properties after a copy operation.
410      *
411      * @param config the configuration to test
412      */
413     private void checkListProperties(Configuration config)
414     {
415         List<Object> values = config.getList("list1");
416         assertEquals("Wrong number of elements in list 1", 3, values.size());
417         values = config.getList("list2");
418         assertEquals("Wrong number of elements in list 2", 2, values.size());
419         assertEquals("Wrong value 1", "3,1415", values.get(0));
420         assertEquals("Wrong value 2", "9,81", values.get(1));
421     }
422 
423     /**
424      * Tests whether the correct events are received for a copy operation.
425      *
426      * @param l the event listener
427      * @param src the configuration that was copied
428      * @param eventType the expected event type
429      */
430     private void checkCopyEvents(CollectingConfigurationListener l,
431             Configuration src, int eventType)
432     {
433         Map<String, ConfigurationEvent> events = new HashMap<String, ConfigurationEvent>();
434         for (ConfigurationEvent e : l.events)
435         {
436             assertEquals("Wrong event type", eventType, e.getType());
437             assertTrue("Unknown property: " + e.getPropertyName(), src
438                     .containsKey(e.getPropertyName()));
439             assertEquals("Wrong property value for " + e.getPropertyName(), e
440                     .getPropertyValue(), src.getProperty(e.getPropertyName()));
441             if (!e.isBeforeUpdate())
442             {
443                 assertTrue("After event without before event", events
444                         .containsKey(e.getPropertyName()));
445             }
446             else
447             {
448                 events.put(e.getPropertyName(), e);
449             }
450         }
451 
452         for (Iterator<String> it = src.getKeys(); it.hasNext();)
453         {
454             String key = it.next();
455             assertTrue("No event received for key " + key, events
456                     .containsKey(key));
457         }
458     }
459 
460     /**
461      * A test configuration implementation. This implementation inherits
462      * directly from AbstractConfiguration. For implementing the required
463      * functionality another implementation of AbstractConfiguration is used;
464      * all methods that need to be implemented delegate to this wrapped
465      * configuration.
466      */
467     static class TestConfigurationImpl extends AbstractConfiguration
468     {
469         /** Stores the underlying configuration. */
470         private AbstractConfiguration config;
471 
472         public AbstractConfiguration getUnderlyingConfiguration()
473         {
474             return config;
475         }
476 
477         public TestConfigurationImpl(AbstractConfiguration wrappedConfig)
478         {
479             config = wrappedConfig;
480         }
481 
482         @Override
483         protected void addPropertyDirect(String key, Object value)
484         {
485             config.addPropertyDirect(key, value);
486         }
487 
488         public boolean containsKey(String key)
489         {
490             return config.containsKey(key);
491         }
492 
493         public Iterator<String> getKeys()
494         {
495             return config.getKeys();
496         }
497 
498         public Object getProperty(String key)
499         {
500             return config.getProperty(key);
501         }
502 
503         public boolean isEmpty()
504         {
505             return config.isEmpty();
506         }
507 
508         @Override
509         protected void clearPropertyDirect(String key)
510         {
511             config.clearPropertyDirect(key);
512         }
513     }
514 
515     /**
516      * An event listener implementation that simply collects all received
517      * configuration events.
518      */
519     static class CollectingConfigurationListener implements
520             ConfigurationListener
521     {
522         List<ConfigurationEvent> events = new ArrayList<ConfigurationEvent>();
523 
524         public void configurationChanged(ConfigurationEvent event)
525         {
526             events.add(event);
527         }
528     }
529 }