1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
55
56 public class TestBaseConfiguration {
57
58
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
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
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
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
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
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
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
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
476 assertNull(config.getProperty("foo"));
477
478
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
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
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
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
570
571 @Test
572 void testInterpolationConstants() {
573 InterpolationTestHelper.testInterpolationConstants(config);
574 }
575
576
577
578
579 @Test
580 void testInterpolationEnvironment() {
581 InterpolationTestHelper.testInterpolationEnvironment(config);
582 }
583
584
585
586
587 @Test
588 void testInterpolationEscaped() {
589 InterpolationTestHelper.testInterpolationEscaped(config);
590 }
591
592
593
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
607
608 @Test
609 void testInterpolationSubset() {
610 InterpolationTestHelper.testInterpolationSubset(config);
611 }
612
613
614
615
616 @Test
617 void testInterpolationSystemProperties() {
618 InterpolationTestHelper.testInterpolationSystemProperties(config);
619 }
620
621
622
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
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
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
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
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
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 }