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