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.assertTrue;
24  
25  import java.math.BigDecimal;
26  import java.math.BigInteger;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.LinkedHashSet;
31  import java.util.List;
32  import java.util.NoSuchElementException;
33  import java.util.Properties;
34  import java.util.Set;
35  import java.util.StringTokenizer;
36  
37  import junitx.framework.ListAssert;
38  
39  import org.apache.commons.configuration.event.ConfigurationEvent;
40  import org.apache.commons.configuration.event.ConfigurationListener;
41  import org.junit.Before;
42  import org.junit.Test;
43  
44  /**
45   * Tests some basic functions of the BaseConfiguration class. Missing keys will
46   * throw Exceptions
47   *
48   * @version $Id: TestBaseConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $
49   */
50  public class TestBaseConfiguration
51  {
52      /** Constant for the number key.*/
53      static final String KEY_NUMBER = "number";
54  
55      protected BaseConfiguration config = null;
56  
57      protected static Class<?> missingElementException = NoSuchElementException.class;
58      protected static Class<?> incompatibleElementException = ConversionException.class;
59  
60      @Before
61      public void setUp() throws Exception
62      {
63          config = new BaseConfiguration();
64          config.setThrowExceptionOnMissing(true);
65      }
66  
67      @Test
68      public void testThrowExceptionOnMissing()
69      {
70          assertTrue("Throw Exception Property is not set!", config.isThrowExceptionOnMissing());
71      }
72  
73      @Test
74      public void testGetProperty()
75      {
76          /* should be empty and return null */
77          assertEquals("This returns null", config.getProperty("foo"), null);
78  
79          /* add a real value, and get it two different ways */
80          config.setProperty("number", "1");
81          assertEquals("This returns '1'", config.getProperty("number"), "1");
82          assertEquals("This returns '1'", config.getString("number"), "1");
83      }
84  
85      @Test
86      public void testGetByte()
87      {
88          config.setProperty("number", "1");
89          byte oneB = 1;
90          byte twoB = 2;
91          assertEquals("This returns 1(byte)", oneB, config.getByte("number"));
92          assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB));
93          assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB));
94          assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2")));
95      }
96  
97      @Test(expected = NoSuchElementException.class)
98      public void testGetByteUnknown()
99      {
100         config.getByte("numberNotInConfig");
101     }
102 
103     @Test(expected = ConversionException.class)
104     public void testGetByteIncompatibleType()
105     {
106         config.setProperty("test.empty", "");
107         config.getByte("test.empty");
108     }
109 
110     @Test
111     public void testGetShort()
112     {
113         config.setProperty("numberS", "1");
114         short oneS = 1;
115         short twoS = 2;
116         assertEquals("This returns 1(short)", oneS, config.getShort("numberS"));
117         assertEquals("This returns 1(short)", oneS, config.getShort("numberS", twoS));
118         assertEquals("This returns 2(default short)", twoS, config.getShort("numberNotInConfig", twoS));
119         assertEquals("This returns 1(Short)", new Short(oneS), config.getShort("numberS", new Short("2")));
120     }
121 
122     @Test(expected = NoSuchElementException.class)
123     public void testGetShortUnknown()
124     {
125         config.getShort("numberNotInConfig");
126     }
127 
128     @Test(expected = ConversionException.class)
129     public void testGetShortIncompatibleType()
130     {
131         config.setProperty("test.empty", "");
132         config.getShort("test.empty");
133     }
134 
135     @Test
136     public void testGetLong()
137     {
138         config.setProperty("numberL", "1");
139         long oneL = 1;
140         long twoL = 2;
141         assertEquals("This returns 1(long)", oneL, config.getLong("numberL"));
142         assertEquals("This returns 1(long)", oneL, config.getLong("numberL", twoL));
143         assertEquals("This returns 2(default long)", twoL, config.getLong("numberNotInConfig", twoL));
144         assertEquals("This returns 1(Long)", new Long(oneL), config.getLong("numberL", new Long("2")));
145     }
146 
147     @Test(expected = NoSuchElementException.class)
148     public void testGetLongUnknown()
149     {
150         config.getLong("numberNotInConfig");
151     }
152 
153     @Test(expected = ConversionException.class)
154     public void testGetLongIncompatibleTypes()
155     {
156         config.setProperty("test.empty", "");
157         config.getLong("test.empty");
158     }
159 
160     @Test
161     public void testGetFloat()
162     {
163         config.setProperty("numberF", "1.0");
164         float oneF = 1;
165         float twoF = 2;
166         assertEquals("This returns 1(float)", oneF, config.getFloat("numberF"), 0);
167         assertEquals("This returns 1(float)", oneF, config.getFloat("numberF", twoF), 0);
168         assertEquals("This returns 2(default float)", twoF, config.getFloat("numberNotInConfig", twoF), 0);
169         assertEquals("This returns 1(Float)", new Float(oneF), config.getFloat("numberF", new Float("2")));
170     }
171 
172     @Test(expected = NoSuchElementException.class)
173     public void testGetFloatUnknown()
174     {
175         config.getFloat("numberNotInConfig");
176     }
177 
178     @Test(expected = ConversionException.class)
179     public void testGetFloatIncompatibleType()
180     {
181         config.setProperty("test.empty", "");
182         config.getFloat("test.empty");
183     }
184 
185     @Test
186     public void testGetDouble()
187     {
188         config.setProperty("numberD", "1.0");
189         double oneD = 1;
190         double twoD = 2;
191         assertEquals("This returns 1(double)", oneD, config.getDouble("numberD"), 0);
192         assertEquals("This returns 1(double)", oneD, config.getDouble("numberD", twoD), 0);
193         assertEquals("This returns 2(default double)", twoD, config.getDouble("numberNotInConfig", twoD), 0);
194         assertEquals("This returns 1(Double)", new Double(oneD), config.getDouble("numberD", new Double("2")));
195     }
196 
197     @Test(expected = NoSuchElementException.class)
198     public void testGetDoubleUnknown()
199     {
200         config.getDouble("numberNotInConfig");
201     }
202 
203     @Test(expected = ConversionException.class)
204     public void testGetDoubleIncompatibleType()
205     {
206         config.setProperty("test.empty", "");
207         config.getDouble("test.empty");
208     }
209 
210     @Test
211     public void testGetBigDecimal()
212     {
213         config.setProperty("numberBigD", "123.456");
214         BigDecimal number = new BigDecimal("123.456");
215         BigDecimal defaultValue = new BigDecimal("654.321");
216 
217         assertEquals("Existing key", number, config.getBigDecimal("numberBigD"));
218         assertEquals("Existing key with default value", number, config.getBigDecimal("numberBigD", defaultValue));
219         assertEquals("Missing key with default value", defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue));
220     }
221 
222     @Test(expected = NoSuchElementException.class)
223     public void testGetBigDecimalUnknown()
224     {
225         config.getBigDecimal("numberNotInConfig");
226     }
227 
228     @Test(expected = ConversionException.class)
229     public void testGetBigDecimalIncompatibleType()
230     {
231         config.setProperty("test.empty", "");
232         config.getBigDecimal("test.empty");
233     }
234 
235     @Test
236     public void testGetBigInteger()
237     {
238         config.setProperty("numberBigI", "1234567890");
239         BigInteger number = new BigInteger("1234567890");
240         BigInteger defaultValue = new BigInteger("654321");
241 
242         assertEquals("Existing key", number, config.getBigInteger("numberBigI"));
243         assertEquals("Existing key with default value", number, config.getBigInteger("numberBigI", defaultValue));
244         assertEquals("Missing key with default value", defaultValue, config.getBigInteger("numberNotInConfig", defaultValue));
245     }
246 
247     @Test(expected = NoSuchElementException.class)
248     public void testGetBigIntegerUnknown()
249     {
250         config.getBigInteger("numberNotInConfig");
251     }
252 
253     @Test(expected = ConversionException.class)
254     public void testGetBigIntegerIncompatibleType()
255     {
256         config.setProperty("test.empty", "");
257         config.getBigInteger("test.empty");
258     }
259 
260     @Test
261     public void testGetString()
262     {
263         config.setProperty("testString", "The quick brown fox");
264         String string = "The quick brown fox";
265         String defaultValue = "jumps over the lazy dog";
266 
267         assertEquals("Existing key", string, config.getString("testString"));
268         assertEquals("Existing key with default value", string, config.getString("testString", defaultValue));
269         assertEquals("Missing key with default value", defaultValue, config.getString("stringNotInConfig", defaultValue));
270     }
271 
272     @Test(expected = NoSuchElementException.class)
273     public void testGetStringUnknown()
274     {
275         config.getString("stringNotInConfig");
276     }
277 
278     @Test
279     public void testGetBoolean()
280     {
281         config.setProperty("boolA", Boolean.TRUE);
282         boolean boolT = true, boolF = false;
283         assertEquals("This returns true", boolT, config.getBoolean("boolA"));
284         assertEquals("This returns true, not the default", boolT, config.getBoolean("boolA", boolF));
285         assertEquals("This returns false(default)", boolF, config.getBoolean("boolNotInConfig", boolF));
286         assertEquals("This returns true(Boolean)", new Boolean(boolT), config.getBoolean("boolA", new Boolean(boolF)));
287     }
288 
289     @Test(expected = NoSuchElementException.class)
290     public void testGetBooleanUnknown()
291     {
292         config.getBoolean("numberNotInConfig");
293     }
294 
295     @Test(expected = ConversionException.class)
296     public void testGetBooleanIncompatibleType()
297     {
298         config.setProperty("test.empty", "");
299         config.getBoolean("test.empty");
300     }
301 
302     @Test
303     public void testGetList()
304     {
305         config.addProperty("number", "1");
306         config.addProperty("number", "2");
307         List<Object> list = config.getList("number");
308         assertNotNull("The list is null", list);
309         assertEquals("List size", 2, list.size());
310         assertTrue("The number 1 is missing from the list", list.contains("1"));
311         assertTrue("The number 2 is missing from the list", list.contains("2"));
312     }
313 
314     /**
315      * Tests that the first scalar of a list is returned.
316      */
317     @Test
318     public void testGetStringForListValue()
319     {
320         config.addProperty("number", "1");
321         config.addProperty("number", "2");
322         assertEquals("Wrong result", "1", config.getString("number"));
323     }
324 
325     @Test
326     public void testGetInterpolatedList()
327     {
328         config.addProperty("number", "1");
329         config.addProperty("array", "${number}");
330         config.addProperty("array", "${number}");
331 
332         List<String> list = new ArrayList<String>();
333         list.add("1");
334         list.add("1");
335 
336         ListAssert.assertEquals("'array' property", list, config.getList("array"));
337     }
338 
339     @Test
340     public void testGetInterpolatedPrimitives()
341     {
342         config.addProperty("number", "1");
343         config.addProperty("value", "${number}");
344 
345         config.addProperty("boolean", "true");
346         config.addProperty("booleanValue", "${boolean}");
347 
348         // primitive types
349         assertEquals("boolean interpolation", true, config.getBoolean("booleanValue"));
350         assertEquals("byte interpolation", 1, config.getByte("value"));
351         assertEquals("short interpolation", 1, config.getShort("value"));
352         assertEquals("int interpolation", 1, config.getInt("value"));
353         assertEquals("long interpolation", 1, config.getLong("value"));
354         assertEquals("float interpolation", 1, config.getFloat("value"), 0);
355         assertEquals("double interpolation", 1, config.getDouble("value"), 0);
356 
357         // primitive wrappers
358         assertEquals("Boolean interpolation", Boolean.TRUE, config.getBoolean("booleanValue", null));
359         assertEquals("Byte interpolation", new Byte("1"), config.getByte("value", null));
360         assertEquals("Short interpolation", new Short("1"), config.getShort("value", null));
361         assertEquals("Integer interpolation", new Integer("1"), config.getInteger("value", null));
362         assertEquals("Long interpolation", new Long("1"), config.getLong("value", null));
363         assertEquals("Float interpolation", new Float("1"), config.getFloat("value", null));
364         assertEquals("Double interpolation", new Double("1"), config.getDouble("value", null));
365 
366         assertEquals("BigInteger interpolation", new BigInteger("1"), config.getBigInteger("value", null));
367         assertEquals("BigDecimal interpolation", new BigDecimal("1"), config.getBigDecimal("value", null));
368     }
369 
370     @Test
371     public void testCommaSeparatedString()
372     {
373         String prop = "hey, that's a test";
374         config.setProperty("prop.string", prop);
375         List<Object> list = config.getList("prop.string");
376         assertEquals("Wrong number of list elements", 2, list.size());
377         assertEquals("Wrong element 1", "hey", list.get(0));
378     }
379 
380     @Test
381     public void testCommaSeparatedStringEscaped()
382     {
383         String prop2 = "hey\\, that's a test";
384         config.setProperty("prop.string", prop2);
385         assertEquals("Wrong value", "hey, that's a test", config.getString("prop.string"));
386     }
387 
388     @Test
389     public void testAddProperty() throws Exception
390     {
391         Collection<Object> props = new ArrayList<Object>();
392         props.add("one");
393         props.add("two,three,four");
394         props.add(new String[] { "5.1", "5.2", "5.3,5.4", "5.5" });
395         props.add("six");
396         config.addProperty("complex.property", props);
397 
398         Object val = config.getProperty("complex.property");
399         assertTrue(val instanceof Collection);
400         Collection<?> col = (Collection<?>) val;
401         assertEquals(10, col.size());
402 
403         props = new ArrayList<Object>();
404         props.add("quick");
405         props.add("brown");
406         props.add("fox,jumps");
407         Object[] data = new Object[] {
408                 "The", props, "over,the", "lazy", "dog."
409         };
410         config.setProperty("complex.property", data);
411         val = config.getProperty("complex.property");
412         assertTrue(val instanceof Collection);
413         col = (Collection<?>) val;
414         Iterator<?> it = col.iterator();
415         StringTokenizer tok = new StringTokenizer("The quick brown fox jumps over the lazy dog.", " ");
416         while(tok.hasMoreTokens())
417         {
418             assertTrue(it.hasNext());
419             assertEquals(tok.nextToken(), it.next());
420         }
421         assertFalse(it.hasNext());
422 
423         config.setProperty("complex.property", null);
424         assertFalse(config.containsKey("complex.property"));
425     }
426 
427     @Test
428     public void testPropertyAccess()
429     {
430         config.clearProperty("prop.properties");
431         config.setProperty("prop.properties", "");
432         assertEquals(
433                 "This returns an empty Properties object",
434                 config.getProperties("prop.properties"),
435                 new Properties());
436         config.clearProperty("prop.properties");
437         config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber");
438 
439         Properties p = new Properties();
440         p.setProperty("foo", "bar");
441         p.setProperty("baz", "moo");
442         p.setProperty("seal", "clubber");
443         assertEquals(
444                 "This returns a filled in Properties object",
445                 config.getProperties("prop.properties"),
446                 p);
447     }
448 
449     @Test
450     public void testSubset()
451     {
452         /*
453          * test subset : assure we don't reprocess the data elements
454          * when generating the subset
455          */
456 
457         String prop = "hey, that's a test";
458         String prop2 = "hey\\, that's a test";
459         config.setProperty("prop.string", prop2);
460         config.setProperty("property.string", "hello");
461 
462         Configuration subEprop = config.subset("prop");
463 
464         assertEquals(
465                 "Returns the full string",
466                 prop,
467                 subEprop.getString("string"));
468         assertEquals("Wrong list size", 1, subEprop.getList("string").size());
469 
470         Iterator<String> it = subEprop.getKeys();
471         it.next();
472         assertFalse(it.hasNext());
473 
474         subEprop = config.subset("prop.");
475         it = subEprop.getKeys();
476         assertFalse(it.hasNext());
477     }
478 
479     @Test
480     public void testInterpolation()
481     {
482         InterpolationTestHelper.testInterpolation(config);
483     }
484 
485     @Test
486     public void testMultipleInterpolation()
487     {
488         InterpolationTestHelper.testMultipleInterpolation(config);
489     }
490 
491     @Test
492     public void testInterpolationLoop()
493     {
494         InterpolationTestHelper.testInterpolationLoop(config);
495     }
496 
497     /**
498      * Tests interpolation when a subset configuration is involved.
499      */
500     @Test
501     public void testInterpolationSubset()
502     {
503         InterpolationTestHelper.testInterpolationSubset(config);
504     }
505 
506     /**
507      * Tests interpolation when the referred property is not found.
508      */
509     @Test
510     public void testInterpolationUnknownProperty()
511     {
512         InterpolationTestHelper.testInterpolationUnknownProperty(config);
513     }
514 
515     /**
516      * Tests interpolation of system properties.
517      */
518     @Test
519     public void testInterpolationSystemProperties()
520     {
521         InterpolationTestHelper.testInterpolationSystemProperties(config);
522     }
523 
524     /**
525      * Tests interpolation of constant values.
526      */
527     @Test
528     public void testInterpolationConstants()
529     {
530         InterpolationTestHelper.testInterpolationConstants(config);
531     }
532 
533     /**
534      * Tests whether a variable can be escaped, so that it won't be
535      * interpolated.
536      */
537     @Test
538     public void testInterpolationEscaped()
539     {
540         InterpolationTestHelper.testInterpolationEscaped(config);
541     }
542 
543     /**
544      * Tests accessing and manipulating the interpolator object.
545      */
546     @Test
547     public void testGetInterpolator()
548     {
549         InterpolationTestHelper.testGetInterpolator(config);
550     }
551 
552     /**
553      * Tests obtaining a configuration with all variables replaced by their
554      * actual values.
555      */
556     @Test
557     public void testInterpolatedConfiguration()
558     {
559         InterpolationTestHelper.testInterpolatedConfiguration(config);
560     }
561 
562     @Test
563     public void testGetHexadecimalValue()
564     {
565         config.setProperty("number", "0xFF");
566         assertEquals("byte value", (byte) 0xFF, config.getByte("number"));
567 
568         config.setProperty("number", "0xFFFF");
569         assertEquals("short value", (short) 0xFFFF, config.getShort("number"));
570 
571         config.setProperty("number", "0xFFFFFFFF");
572         assertEquals("int value", 0xFFFFFFFF, config.getInt("number"));
573 
574         config.setProperty("number", "0xFFFFFFFFFFFFFFFF");
575         assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getLong("number"));
576 
577         assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue());
578     }
579 
580     @Test
581     public void testGetBinaryValue()
582     {
583         config.setProperty("number", "0b11111111");
584         assertEquals("byte value", (byte) 0xFF, config.getByte("number"));
585 
586         config.setProperty("number", "0b1111111111111111");
587         assertEquals("short value", (short) 0xFFFF, config.getShort("number"));
588 
589         config.setProperty("number", "0b11111111111111111111111111111111");
590         assertEquals("int value", 0xFFFFFFFF, config.getInt("number"));
591 
592         config.setProperty("number", "0b1111111111111111111111111111111111111111111111111111111111111111");
593         assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getLong("number"));
594 
595         assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue());
596     }
597 
598     @Test
599     public void testResolveContainerStore()
600     {
601         AbstractConfiguration config = new BaseConfiguration();
602 
603         // array of objects
604         config.addPropertyDirect("array", new String[] { "foo", "bar" });
605 
606         assertEquals("first element of the 'array' property", "foo", config.resolveContainerStore("array"));
607 
608         // list of objects
609         List<Object> list = new ArrayList<Object>();
610         list.add("foo");
611         list.add("bar");
612         config.addPropertyDirect("list", list);
613 
614         assertEquals("first element of the 'list' property", "foo", config.resolveContainerStore("list"));
615 
616         // set of objects
617         Set<Object> set = new LinkedHashSet<Object>();
618         set.add("foo");
619         set.add("bar");
620         config.addPropertyDirect("set", set);
621 
622         assertEquals("first element of the 'set' property", "foo", config.resolveContainerStore("set"));
623 
624         // arrays of primitives
625         config.addPropertyDirect("array.boolean", new boolean[] { true, false });
626         assertEquals("first element of the 'array.boolean' property", true, config.getBoolean("array.boolean"));
627 
628         config.addPropertyDirect("array.byte", new byte[] { 1, 2 });
629         assertEquals("first element of the 'array.byte' property", 1, config.getByte("array.byte"));
630 
631         config.addPropertyDirect("array.short", new short[] { 1, 2 });
632         assertEquals("first element of the 'array.short' property", 1, config.getShort("array.short"));
633 
634         config.addPropertyDirect("array.int", new int[] { 1, 2 });
635         assertEquals("first element of the 'array.int' property", 1, config.getInt("array.int"));
636 
637         config.addPropertyDirect("array.long", new long[] { 1, 2 });
638         assertEquals("first element of the 'array.long' property", 1, config.getLong("array.long"));
639 
640         config.addPropertyDirect("array.float", new float[] { 1, 2 });
641         assertEquals("first element of the 'array.float' property", 1, config.getFloat("array.float"), 0);
642 
643         config.addPropertyDirect("array.double", new double[] { 1, 2 });
644         assertEquals("first element of the 'array.double' property", 1, config.getDouble("array.double"), 0);
645     }
646 
647     /**
648      * Tests if conversion between number types is possible.
649      */
650     @Test
651     public void testNumberConversions()
652     {
653         config.setProperty(KEY_NUMBER, new Integer(42));
654         assertEquals("Wrong int returned", 42, config.getInt(KEY_NUMBER));
655         assertEquals("Wrong long returned", 42L, config.getLong(KEY_NUMBER));
656         assertEquals("Wrong byte returned", (byte) 42, config
657                 .getByte(KEY_NUMBER));
658         assertEquals("Wrong float returned", 42.0f,
659                 config.getFloat(KEY_NUMBER), 0.01f);
660         assertEquals("Wrong double returned", 42.0, config
661                 .getDouble(KEY_NUMBER), 0.001);
662 
663         assertEquals("Wrong Long returned", new Long(42L), config.getLong(
664                 KEY_NUMBER, null));
665         assertEquals("Wrong BigInt returned", new BigInteger("42"), config
666                 .getBigInteger(KEY_NUMBER));
667         assertEquals("Wrong DigDecimal returned", new BigDecimal("42"), config
668                 .getBigDecimal(KEY_NUMBER));
669     }
670 
671     /**
672      * Tests cloning a BaseConfiguration.
673      */
674     @Test
675     public void testClone()
676     {
677         for (int i = 0; i < 10; i++)
678         {
679             config.addProperty("key" + i, new Integer(i));
680         }
681         BaseConfiguration config2 = (BaseConfiguration) config.clone();
682 
683         for (Iterator<String> it = config.getKeys(); it.hasNext();)
684         {
685             String key = it.next();
686             assertTrue("Key not found: " + key, config2.containsKey(key));
687             assertEquals("Wrong value for key " + key, config.getProperty(key),
688                     config2.getProperty(key));
689         }
690     }
691 
692     /**
693      * Tests whether a cloned configuration is decoupled from its original.
694      */
695     @Test
696     public void testCloneModify()
697     {
698         ConfigurationListener l = new ConfigurationListener()
699         {
700             public void configurationChanged(ConfigurationEvent event)
701             {
702                 // just a dummy
703             }
704         };
705         config.addConfigurationListener(l);
706         config.addProperty("original", Boolean.TRUE);
707         BaseConfiguration config2 = (BaseConfiguration) config.clone();
708 
709         config2.addProperty("clone", Boolean.TRUE);
710         assertFalse("New key appears in original", config.containsKey("clone"));
711         config2.setProperty("original", Boolean.FALSE);
712         assertTrue("Wrong value of original property", config
713                 .getBoolean("original"));
714 
715         assertEquals("Event listener was copied", 0, config2
716                 .getConfigurationListeners().size());
717     }
718 
719     /**
720      * Tests the clone() method if a list property is involved.
721      */
722     @Test
723     public void testCloneListProperty()
724     {
725         final String key = "list";
726         config.addProperty(key, "value1");
727         config.addProperty(key, "value2");
728         BaseConfiguration config2 = (BaseConfiguration) config.clone();
729         config2.addProperty(key, "value3");
730         assertEquals("Wrong number of original properties", 2, config.getList(
731                 key).size());
732     }
733 }