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