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