001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.configuration;
019    
020    import static org.junit.Assert.assertEquals;
021    import static org.junit.Assert.assertFalse;
022    import static org.junit.Assert.assertNotNull;
023    import static org.junit.Assert.assertTrue;
024    
025    import java.math.BigDecimal;
026    import java.math.BigInteger;
027    import java.util.ArrayList;
028    import java.util.Collection;
029    import java.util.Iterator;
030    import java.util.LinkedHashSet;
031    import java.util.List;
032    import java.util.NoSuchElementException;
033    import java.util.Properties;
034    import java.util.Set;
035    import java.util.StringTokenizer;
036    
037    import junitx.framework.ListAssert;
038    
039    import org.apache.commons.configuration.event.ConfigurationEvent;
040    import org.apache.commons.configuration.event.ConfigurationListener;
041    import org.junit.Before;
042    import org.junit.Test;
043    
044    /**
045     * Tests some basic functions of the BaseConfiguration class. Missing keys will
046     * throw Exceptions
047     *
048     * @version $Id: TestBaseConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $
049     */
050    public class TestBaseConfiguration
051    {
052        /** Constant for the number key.*/
053        static final String KEY_NUMBER = "number";
054    
055        protected BaseConfiguration config = null;
056    
057        protected static Class<?> missingElementException = NoSuchElementException.class;
058        protected static Class<?> incompatibleElementException = ConversionException.class;
059    
060        @Before
061        public void setUp() throws Exception
062        {
063            config = new BaseConfiguration();
064            config.setThrowExceptionOnMissing(true);
065        }
066    
067        @Test
068        public void testThrowExceptionOnMissing()
069        {
070            assertTrue("Throw Exception Property is not set!", config.isThrowExceptionOnMissing());
071        }
072    
073        @Test
074        public void testGetProperty()
075        {
076            /* should be empty and return null */
077            assertEquals("This returns null", config.getProperty("foo"), null);
078    
079            /* add a real value, and get it two different ways */
080            config.setProperty("number", "1");
081            assertEquals("This returns '1'", config.getProperty("number"), "1");
082            assertEquals("This returns '1'", config.getString("number"), "1");
083        }
084    
085        @Test
086        public void testGetByte()
087        {
088            config.setProperty("number", "1");
089            byte oneB = 1;
090            byte twoB = 2;
091            assertEquals("This returns 1(byte)", oneB, config.getByte("number"));
092            assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB));
093            assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB));
094            assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2")));
095        }
096    
097        @Test(expected = NoSuchElementException.class)
098        public void testGetByteUnknown()
099        {
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    }