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