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 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 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
106
107 @Test
108 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
123
124 @Test
125 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
137
138 @Test
139 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
150
151 @Test
152 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 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 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 void testContainsValue() {
183 assertFalse(config.containsValue(null));
184 }
185
186 @Test
187 void testGetBigDecimal() {
188 config.setProperty("numberBigD", "123.456");
189 final BigDecimal number = new BigDecimal("123.456");
190 final BigDecimal defaultValue = new BigDecimal("654.321");
191
192 assertEquals(number, config.getBigDecimal("numberBigD"));
193 assertEquals(number, config.getBigDecimal("numberBigD", defaultValue));
194 assertEquals(defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue));
195 }
196
197 @Test
198 void testGetBigDecimalIncompatibleType() {
199 config.setProperty("test.empty", "");
200 assertThrows(ConversionException.class, () -> config.getBigDecimal("test.empty"));
201 }
202
203 @Test
204 void testGetBigDecimalUnknown() {
205 assertThrows(NoSuchElementException.class, () -> config.getBigDecimal("numberNotInConfig"));
206 }
207
208 @Test
209 void testGetBigInteger() {
210 config.setProperty("numberBigI", "1234567890");
211 final BigInteger number = new BigInteger("1234567890");
212 final BigInteger defaultValue = new BigInteger("654321");
213
214 assertEquals(number, config.getBigInteger("numberBigI"));
215 assertEquals(number, config.getBigInteger("numberBigI", defaultValue));
216 assertEquals(defaultValue, config.getBigInteger("numberNotInConfig", defaultValue));
217 }
218
219 @Test
220 void testGetBigIntegerIncompatibleType() {
221 config.setProperty("test.empty", "");
222 assertThrows(ConversionException.class, () -> config.getBigInteger("test.empty"));
223 }
224
225 @Test
226 void testGetBigIntegerUnknown() {
227 assertThrows(NoSuchElementException.class, () -> config.getBigInteger("numberNotInConfig"));
228 }
229
230 @Test
231 void testGetBinaryValue() {
232 config.setProperty("number", "0b11111111");
233 assertEquals((byte) 0xFF, config.getByte("number"));
234
235 config.setProperty("number", "0b1111111111111111");
236 assertEquals((short) 0xFFFF, config.getShort("number"));
237
238 config.setProperty("number", "0b11111111111111111111111111111111");
239 assertEquals(0xFFFFFFFF, config.getInt("number"));
240
241 config.setProperty("number", "0b1111111111111111111111111111111111111111111111111111111111111111");
242 assertEquals(0xFFFFFFFFFFFFFFFFL, config.getLong("number"));
243
244 assertEquals(0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue());
245 }
246
247 @Test
248 void testGetBoolean() {
249 config.setProperty("boolA", Boolean.TRUE);
250 final boolean boolT = true;
251 final boolean boolF = false;
252 assertEquals(boolT, config.getBoolean("boolA"));
253 assertEquals(boolT, config.getBoolean("boolA", boolF));
254 assertEquals(boolF, config.getBoolean("boolNotInConfig", boolF));
255 assertEquals(Boolean.valueOf(boolT), config.getBoolean("boolA", Boolean.valueOf(boolF)));
256 }
257
258 @Test
259 void testGetBooleanIncompatibleType() {
260 config.setProperty("test.empty", "");
261 assertThrows(ConversionException.class, () -> config.getBoolean("test.empty"));
262 }
263
264 @Test
265 void testGetBooleanUnknown() {
266 assertThrows(NoSuchElementException.class, () -> config.getBoolean("numberNotInConfig"));
267 }
268
269 @Test
270 void testGetByte() {
271 config.setProperty("number", "1");
272 final byte oneB = 1;
273 final byte twoB = 2;
274 assertEquals(oneB, config.getByte("number"));
275 assertEquals(oneB, config.getByte("number", twoB));
276 assertEquals(twoB, config.getByte("numberNotInConfig", twoB));
277 assertEquals(Byte.valueOf(oneB), config.getByte("number", Byte.valueOf("2")));
278 }
279
280 @Test
281 void testGetByteIncompatibleType() {
282 config.setProperty("test.empty", "");
283 assertThrows(ConversionException.class, () -> config.getByte("test.empty"));
284 }
285
286 @Test
287 void testGetByteUnknown() {
288 assertThrows(NoSuchElementException.class, () -> config.getByte("numberNotInConfig"));
289 }
290
291 @Test
292 void testGetDouble() {
293 config.setProperty("numberD", "1.0");
294 final double oneD = 1;
295 final double twoD = 2;
296 assertEquals(oneD, config.getDouble("numberD"), 0);
297 assertEquals(oneD, config.getDouble("numberD", twoD), 0);
298 assertEquals(twoD, config.getDouble("numberNotInConfig", twoD), 0);
299 assertEquals(Double.valueOf(oneD), config.getDouble("numberD", Double.valueOf("2")));
300 }
301
302 @Test
303 void testGetDoubleIncompatibleType() {
304 config.setProperty("test.empty", "");
305 assertThrows(ConversionException.class, () -> config.getDouble("test.empty"));
306 }
307
308 @Test
309 void testGetDoubleUnknown() {
310 assertThrows(NoSuchElementException.class, () -> config.getDouble("numberNotInConfig"));
311 }
312
313 @Test
314 void testGetDuration() {
315 final Duration d = Duration.ofSeconds(1);
316 config.setProperty("durationD", d.toString());
317 final Duration oneD = Duration.ofSeconds(1);
318 final Duration twoD = Duration.ofSeconds(2);
319 assertEquals(oneD, config.getDuration("durationD"));
320 assertEquals(oneD, config.getDuration("durationD", twoD));
321 assertEquals(twoD, config.getDuration("numberNotInConfig", twoD));
322 assertEquals(oneD, config.getDuration("durationD", twoD));
323 }
324
325 @Test
326 void testGetDurationIncompatibleType() {
327 config.setProperty("test.empty", "");
328 assertThrows(ConversionException.class, () -> config.getDuration("test.empty"));
329 }
330
331 @Test
332 void testGetDurationUnknown() {
333 assertThrows(NoSuchElementException.class, () -> config.getDuration("numberNotInConfig"));
334 }
335
336 @Test
337 void testGetEnum() {
338 config.setProperty("testEnum", EnumFixture.SMALLTALK.name());
339 config.setProperty("testBadEnum", "This is not an enum value.");
340 final EnumFixture enum1 = EnumFixture.SMALLTALK;
341 final EnumFixture defaultValue = EnumFixture.JAVA;
342
343 assertEquals(enum1, config.getEnum("testEnum", EnumFixture.class));
344 assertEquals(enum1, config.getEnum("testEnum", EnumFixture.class, defaultValue));
345 assertEquals(defaultValue, config.getEnum("stringNotInConfig", EnumFixture.class, defaultValue));
346
347 assertThrows(ConversionException.class, () -> config.getEnum("testBadEnum", EnumFixture.class));
348
349 assertThrows(ConversionException.class, () -> config.getEnum("testBadEnum", EnumFixture.class, defaultValue));
350 }
351
352 @Test
353 void testGetFloat() {
354 config.setProperty("numberF", "1.0");
355 final float oneF = 1;
356 final float twoF = 2;
357 assertEquals(oneF, config.getFloat("numberF"), 0);
358 assertEquals(oneF, config.getFloat("numberF", twoF), 0);
359 assertEquals(twoF, config.getFloat("numberNotInConfig", twoF), 0);
360 assertEquals(Float.valueOf(oneF), config.getFloat("numberF", Float.valueOf("2")));
361 }
362
363 @Test
364 void testGetFloatIncompatibleType() {
365 config.setProperty("test.empty", "");
366 assertThrows(ConversionException.class, () -> config.getFloat("test.empty"));
367 }
368
369 @Test
370 void testGetFloatUnknown() {
371 assertThrows(NoSuchElementException.class, () -> config.getFloat("numberNotInConfig"));
372 }
373
374 @Test
375 void testGetHexadecimalValue() {
376 config.setProperty("number", "0xFF");
377 assertEquals((byte) 0xFF, config.getByte("number"));
378
379 config.setProperty("number", "0xFFFF");
380 assertEquals((short) 0xFFFF, config.getShort("number"));
381
382 config.setProperty("number", "0xFFFFFFFF");
383 assertEquals(0xFFFFFFFF, config.getInt("number"));
384
385 config.setProperty("number", "0xFFFFFFFFFFFFFFFF");
386 assertEquals(0xFFFFFFFFFFFFFFFFL, config.getLong("number"));
387
388 assertEquals(0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue());
389 }
390
391 @Test
392 void testGetInterpolatedList() {
393 config.addProperty("number", "1");
394 config.addProperty("array", "${number}");
395 config.addProperty("array", "${number}");
396
397 final List<String> list = new ArrayList<>();
398 list.add("1");
399 list.add("1");
400
401 assertEquals(list, config.getList("array"));
402 }
403
404 @Test
405 void testGetInterpolatedPrimitives() {
406 config.addProperty("number", "1");
407 config.addProperty("value", "${number}");
408
409 config.addProperty("boolean", "true");
410 config.addProperty("booleanValue", "${boolean}");
411
412
413 assertTrue(config.getBoolean("booleanValue"));
414 assertEquals(1, config.getByte("value"));
415 assertEquals(1, config.getShort("value"));
416 assertEquals(1, config.getInt("value"));
417 assertEquals(1, config.getLong("value"));
418 assertEquals(1, config.getFloat("value"), 0);
419 assertEquals(1, config.getDouble("value"), 0);
420
421
422 assertEquals(Boolean.TRUE, config.getBoolean("booleanValue", null));
423 assertEquals(Byte.valueOf("1"), config.getByte("value", null));
424 assertEquals(Short.valueOf("1"), config.getShort("value", null));
425 assertEquals(Integer.valueOf("1"), config.getInteger("value", null));
426 assertEquals(Long.valueOf("1"), config.getLong("value", null));
427 assertEquals(Float.valueOf("1"), config.getFloat("value", null));
428 assertEquals(Double.valueOf("1"), config.getDouble("value", null));
429
430 assertEquals(new BigInteger("1"), config.getBigInteger("value", null));
431 assertEquals(new BigDecimal("1"), config.getBigDecimal("value", null));
432 }
433
434
435
436
437 @Test
438 void testGetInterpolator() {
439 InterpolationTestHelper.testGetInterpolator(config);
440 }
441
442 @Test
443 void testGetList() {
444 config.addProperty("number", "1");
445 config.addProperty("number", "2");
446 final List<Object> list = config.getList("number");
447 assertEquals(Arrays.asList("1", "2"), list);
448 }
449
450 @Test
451 void testGetLong() {
452 config.setProperty("numberL", "1");
453 final long oneL = 1;
454 final long twoL = 2;
455 assertEquals(oneL, config.getLong("numberL"));
456 assertEquals(oneL, config.getLong("numberL", twoL));
457 assertEquals(twoL, config.getLong("numberNotInConfig", twoL));
458 assertEquals(Long.valueOf(oneL), config.getLong("numberL", Long.valueOf("2")));
459 }
460
461 @Test
462 void testGetLongIncompatibleTypes() {
463 config.setProperty("test.empty", "");
464 assertThrows(ConversionException.class, () -> config.getLong("test.empty"));
465 }
466
467 @Test
468 void testGetLongUnknown() {
469 assertThrows(NoSuchElementException.class, () -> config.getLong("numberNotInConfig"));
470 }
471
472 @Test
473 void testGetProperty() {
474
475 assertNull(config.getProperty("foo"));
476
477
478 config.setProperty("number", "1");
479 assertEquals("1", config.getProperty("number"));
480 assertEquals("1", config.getString("number"));
481 }
482
483 @Test
484 void testGetShort() {
485 config.setProperty("numberS", "1");
486 final short oneS = 1;
487 final short twoS = 2;
488 assertEquals(oneS, config.getShort("numberS"));
489 assertEquals(oneS, config.getShort("numberS", twoS));
490 assertEquals(twoS, config.getShort("numberNotInConfig", twoS));
491 assertEquals(Short.valueOf(oneS), config.getShort("numberS", Short.valueOf("2")));
492 }
493
494 @Test
495 void testGetShortIncompatibleType() {
496 config.setProperty("test.empty", "");
497 assertThrows(ConversionException.class, () -> config.getShort("test.empty"));
498 }
499
500 @Test
501 void testGetShortUnknown() {
502 assertThrows(NoSuchElementException.class, () -> config.getShort("numberNotInConfig"));
503 }
504
505 @Test
506 void testGetString() {
507 config.setProperty("testString", "The quick brown fox");
508 final String string = "The quick brown fox";
509 final String defaultValue = "jumps over the lazy dog";
510
511 assertEquals(string, config.getString("testString"));
512 assertEquals(string, config.getString("testString", defaultValue));
513 assertEquals(defaultValue, config.getString("stringNotInConfig", defaultValue));
514 }
515
516
517
518
519 @Test
520 void testGetStringForListValue() {
521 config.addProperty("number", "1");
522 config.addProperty("number", "2");
523 assertEquals("1", config.getString("number"));
524 }
525
526 @Test
527 void testGetStringUnknown() {
528 assertThrows(NoSuchElementException.class, () -> config.getString("stringNotInConfig"));
529 }
530
531
532
533
534 @Test
535 void testInstallInterpolator() {
536 final Lookup prefixLookup = mock(Lookup.class);
537 final Lookup defLookup = mock(Lookup.class);
538 final Map<String, Lookup> prefixLookups = new HashMap<>();
539 prefixLookups.put("test", prefixLookup);
540 final List<Lookup> defLookups = new ArrayList<>();
541 defLookups.add(defLookup);
542 config.installInterpolator(prefixLookups, defLookups);
543 final ConfigurationInterpolator interpolator = config.getInterpolator();
544 assertEquals(prefixLookups, interpolator.getLookups());
545 final List<Lookup> defLookups2 = interpolator.getDefaultLookups();
546 assertEquals(2, defLookups2.size());
547 assertSame(defLookup, defLookups2.get(0));
548 final String var = "testVariable";
549 final Object value = 42;
550 config.addProperty(var, value);
551 assertEquals(value, defLookups2.get(1).lookup(var));
552 }
553
554
555
556
557 @Test
558 void testInterpolatedConfiguration() {
559 InterpolationTestHelper.testInterpolatedConfiguration(config);
560 }
561
562 @Test
563 void testInterpolation() {
564 InterpolationTestHelper.testInterpolation(config);
565 }
566
567
568
569
570 @Test
571 void testInterpolationConstants() {
572 InterpolationTestHelper.testInterpolationConstants(config);
573 }
574
575
576
577
578 @Test
579 void testInterpolationEnvironment() {
580 InterpolationTestHelper.testInterpolationEnvironment(config);
581 }
582
583
584
585
586 @Test
587 void testInterpolationEscaped() {
588 InterpolationTestHelper.testInterpolationEscaped(config);
589 }
590
591
592
593
594 @Test
595 void testInterpolationLocalhost() {
596 InterpolationTestHelper.testInterpolationLocalhost(config);
597 }
598
599 @Test
600 void testInterpolationLoop() {
601 InterpolationTestHelper.testInterpolationLoop(config);
602 }
603
604
605
606
607 @Test
608 void testInterpolationSubset() {
609 InterpolationTestHelper.testInterpolationSubset(config);
610 }
611
612
613
614
615 @Test
616 void testInterpolationSystemProperties() {
617 InterpolationTestHelper.testInterpolationSystemProperties(config);
618 }
619
620
621
622
623 @Test
624 void testInterpolationUnknownProperty() {
625 InterpolationTestHelper.testInterpolationUnknownProperty(config);
626 }
627
628 @Test
629 void testMultipleInterpolation() {
630 InterpolationTestHelper.testMultipleInterpolation(config);
631 }
632
633
634
635
636 @Test
637 void testNoInterpolator() {
638 config.setProperty("test", "${value}");
639 config.setInterpolator(null);
640 assertEquals("${value}", config.getString("test"));
641 }
642
643
644
645
646 @Test
647 void testNumberConversions() {
648 config.setProperty(KEY_NUMBER, Integer.valueOf(42));
649 assertEquals(42, config.getInt(KEY_NUMBER));
650 assertEquals(42L, config.getLong(KEY_NUMBER));
651 assertEquals((byte) 42, config.getByte(KEY_NUMBER));
652 assertEquals(42.0f, config.getFloat(KEY_NUMBER), 0.01f);
653 assertEquals(42.0, config.getDouble(KEY_NUMBER), 0.001);
654
655 assertEquals(Long.valueOf(42L), config.getLong(KEY_NUMBER, null));
656 assertEquals(new BigInteger("42"), config.getBigInteger(KEY_NUMBER));
657 assertEquals(new BigDecimal("42.0"), config.getBigDecimal(KEY_NUMBER));
658 }
659
660 @Test
661 void testPropertyAccess() {
662 config.clearProperty("prop.properties");
663 config.setProperty("prop.properties", "");
664 assertEquals(new Properties(), config.getProperties("prop.properties"));
665 config.clearProperty("prop.properties");
666 config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber");
667
668 final Properties p = new Properties();
669 p.setProperty("foo", "bar");
670 p.setProperty("baz", "moo");
671 p.setProperty("seal", "clubber");
672 assertEquals(p, config.getProperties("prop.properties"));
673 }
674
675
676
677
678 @Test
679 void testSetInterpolator() {
680 final ConfigurationInterpolator interpolator = mock(ConfigurationInterpolator.class);
681 config.setInterpolator(interpolator);
682 assertSame(interpolator, config.getInterpolator());
683 }
684
685
686
687
688 @Test
689 void testSize() {
690 final int count = 16;
691 for (int i = 0; i < count; i++) {
692 config.addProperty("key" + i, "value" + i);
693 }
694 assertEquals(count, config.size());
695 }
696
697 @Test
698 void testSubset() {
699
700
701
702
703 final String prop = "hey, that's a test";
704 final String prop2 = "hey\\, that's a test";
705 config.setProperty("prop.string", prop2);
706 config.setProperty("property.string", "hello");
707
708 Configuration subEprop = config.subset("prop");
709
710 assertEquals(prop, subEprop.getString("string"));
711 assertEquals(1, subEprop.getList("string").size());
712
713 Iterator<String> it = subEprop.getKeys();
714 it.next();
715 assertFalse(it.hasNext());
716
717 subEprop = config.subset("prop.");
718 it = subEprop.getKeys();
719 assertFalse(it.hasNext());
720 }
721
722 @Test
723 void testThrowExceptionOnMissing() {
724 assertTrue(config.isThrowExceptionOnMissing());
725 }
726 }