1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
22 import static org.junit.jupiter.api.Assertions.assertNotEquals;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertNotSame;
25 import static org.junit.jupiter.api.Assertions.assertNull;
26 import static org.junit.jupiter.api.Assertions.assertSame;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29
30 import java.io.StringReader;
31 import java.io.StringWriter;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Set;
38 import java.util.concurrent.CountDownLatch;
39 import java.util.concurrent.atomic.AtomicInteger;
40
41 import org.apache.commons.configuration2.SynchronizerTestImpl.Methods;
42 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
43 import org.apache.commons.configuration2.event.ConfigurationEvent;
44 import org.apache.commons.configuration2.event.EventListener;
45 import org.apache.commons.configuration2.ex.ConfigurationException;
46 import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
47 import org.apache.commons.configuration2.io.FileHandler;
48 import org.apache.commons.configuration2.sync.LockMode;
49 import org.apache.commons.configuration2.sync.ReadWriteSynchronizer;
50 import org.apache.commons.configuration2.sync.Synchronizer;
51 import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
52 import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;
53 import org.apache.commons.configuration2.tree.ImmutableNode;
54 import org.apache.commons.configuration2.tree.NodeCombiner;
55 import org.apache.commons.configuration2.tree.NodeModel;
56 import org.apache.commons.configuration2.tree.OverrideCombiner;
57 import org.apache.commons.configuration2.tree.UnionCombiner;
58 import org.junit.jupiter.api.BeforeEach;
59 import org.junit.jupiter.api.Test;
60
61
62
63
64 public class TestCombinedConfiguration {
65
66
67
68 private static final class CombinedListener implements EventListener<ConfigurationEvent> {
69
70 private int invalidateEvents;
71
72 private int otherEvents;
73
74
75
76
77
78
79
80 public void checkEvent(final int expectedInvalidate, final int expectedOthers) {
81 assertEquals(expectedInvalidate, invalidateEvents);
82 assertEquals(expectedOthers, otherEvents);
83 }
84
85 @Override
86 public void onEvent(final ConfigurationEvent event) {
87 if (event.getEventType() == CombinedConfiguration.COMBINED_INVALIDATE) {
88 invalidateEvents++;
89 } else {
90 otherEvents++;
91 }
92 }
93 }
94
95
96
97
98
99 private static final class ReadThread extends Thread {
100
101
102 private final Configuration config;
103
104
105 private final CountDownLatch startLatch;
106
107
108 private final AtomicInteger errorCount;
109
110
111 private final int numberOfReads;
112
113
114
115
116
117
118
119
120
121 public ReadThread(final Configuration readConfig, final CountDownLatch latch, final AtomicInteger errCnt, final int readCount) {
122 config = readConfig;
123 startLatch = latch;
124 errorCount = errCnt;
125 numberOfReads = readCount;
126 }
127
128
129
130
131 private void readConfiguration() {
132 final List<Object> values = config.getList(KEY_CONCURRENT);
133 if (values.size() < 1 || values.size() > 2) {
134 errorCount.incrementAndGet();
135 } else {
136 boolean ok = true;
137 for (final Object value : values) {
138 if (!TEST_NAME.equals(value)) {
139 ok = false;
140 }
141 }
142 if (!ok) {
143 errorCount.incrementAndGet();
144 }
145 }
146 }
147
148
149
150
151 @Override
152 public void run() {
153 try {
154 startLatch.await();
155 for (int i = 0; i < numberOfReads; i++) {
156 readConfiguration();
157 }
158 } catch (final Exception e) {
159 errorCount.incrementAndGet();
160 }
161 }
162 }
163
164
165
166
167
168
169
170 private static final class WriteThread extends Thread {
171
172 private final List<Configuration> testConfigs;
173
174
175 private final CountDownLatch startLatch;
176
177
178 private final AtomicInteger errorCount;
179
180
181 private final int numberOfWrites;
182
183
184 private int currentChildConfigIdx;
185
186
187
188
189
190
191
192
193
194 public WriteThread(final CombinedConfiguration cc, final CountDownLatch latch, final AtomicInteger errCnt, final int writeCount) {
195 testConfigs = cc.getConfigurations();
196 startLatch = latch;
197 errorCount = errCnt;
198 numberOfWrites = writeCount;
199 }
200
201 @Override
202 public void run() {
203 try {
204 startLatch.await();
205 for (int i = 0; i < numberOfWrites; i++) {
206 updateConfigurations();
207 }
208 } catch (final InterruptedException e) {
209 errorCount.incrementAndGet();
210 }
211 }
212
213
214
215
216 private void updateConfigurations() {
217 final int newIdx = (currentChildConfigIdx + 1) % testConfigs.size();
218 testConfigs.get(newIdx).addProperty(KEY_CONCURRENT, TEST_NAME);
219 testConfigs.get(currentChildConfigIdx).clearProperty(KEY_CONCURRENT);
220 currentChildConfigIdx = newIdx;
221 }
222 }
223
224
225 private static final String TEST_NAME = "SUBCONFIG";
226
227
228 private static final String TEST_KEY = "test.value";
229
230
231 private static final String KEY_CONCURRENT = "concurrent.access.test";
232
233
234 private static final String CHILD1 = TEST_NAME + "1";
235
236
237 private static final String CHILD2 = TEST_NAME + "2";
238
239
240 private static final String SUB_KEY = "test.sub.config";
241
242
243
244
245
246
247 private static AbstractConfiguration setUpTestConfiguration() {
248 final BaseHierarchicalConfiguration config = new BaseHierarchicalConfiguration();
249 config.addProperty(TEST_KEY, Boolean.TRUE);
250 config.addProperty("test.comment", "This is a test");
251 return config;
252 }
253
254
255 private CombinedConfiguration config;
256
257
258 private CombinedListener listener;
259
260
261
262
263
264
265 private void checkAddConfig(final AbstractConfiguration c) {
266 final Collection<EventListener<? super ConfigurationEvent>> listeners = c.getEventListeners(ConfigurationEvent.ANY);
267 assertEquals(1, listeners.size());
268 assertTrue(listeners.contains(config));
269 }
270
271
272
273
274 private void checkCombinedRootNotConstructed() {
275 assertTrue(config.getModel().getNodeHandler().getRootNode().getChildren().isEmpty());
276 }
277
278
279
280
281
282
283 private void checkConfigurationsAt(final boolean withUpdates) {
284 setUpSubConfigTest();
285 final List<HierarchicalConfiguration<ImmutableNode>> subs = config.configurationsAt(SUB_KEY, withUpdates);
286 assertEquals(1, subs.size());
287 assertTrue(subs.get(0).getBoolean(TEST_KEY));
288 }
289
290
291
292
293
294
295 private void checkRemoveConfig(final AbstractConfiguration c) {
296 assertTrue(c.getEventListeners(ConfigurationEvent.ANY).isEmpty());
297 assertEquals(0, config.getNumberOfConfigurations());
298 assertTrue(config.getConfigurationNames().isEmpty());
299 listener.checkEvent(2, 0);
300 }
301
302 @BeforeEach
303 public void setUp() throws Exception {
304 config = new CombinedConfiguration();
305 listener = new CombinedListener();
306 config.addEventListener(ConfigurationEvent.ANY, listener);
307 }
308
309
310
311
312 private void setUpSourceTest() {
313 final BaseHierarchicalConfiguration c1 = new BaseHierarchicalConfiguration();
314 final PropertiesConfiguration c2 = new PropertiesConfiguration();
315 c1.addProperty(TEST_KEY, TEST_NAME);
316 c2.addProperty("another.key", "test");
317 config.addConfiguration(c1, CHILD1);
318 config.addConfiguration(c2, CHILD2);
319 }
320
321
322
323
324
325
326 private AbstractConfiguration setUpSubConfigTest() {
327 final AbstractConfiguration srcConfig = setUpTestConfiguration();
328 config.addConfiguration(srcConfig, "source", SUB_KEY);
329 config.addConfiguration(setUpTestConfiguration());
330 config.addConfiguration(setUpTestConfiguration(), "otherTest", "other.prefix");
331 return srcConfig;
332 }
333
334
335
336
337
338
339 private SynchronizerTestImpl setUpSynchronizerTest() {
340 setUpSourceTest();
341 final SynchronizerTestImpl sync = new SynchronizerTestImpl();
342 config.setSynchronizer(sync);
343 return sync;
344 }
345
346
347
348
349 @Test
350 void testAccessPropertyEmpty() {
351 assertFalse(config.containsKey(TEST_KEY));
352 assertNull(config.getString("test.comment"));
353 assertTrue(config.isEmpty());
354 }
355
356
357
358
359 @Test
360 void testAccessPropertyMulti() {
361 config.addConfiguration(setUpTestConfiguration());
362 config.addConfiguration(setUpTestConfiguration(), null, "prefix1");
363 config.addConfiguration(setUpTestConfiguration(), null, "prefix2");
364 assertTrue(config.getBoolean(TEST_KEY));
365 assertTrue(config.getBoolean("prefix1." + TEST_KEY));
366 assertTrue(config.getBoolean("prefix2." + TEST_KEY));
367 assertFalse(config.isEmpty());
368 listener.checkEvent(3, 0);
369 }
370
371
372
373
374 @Test
375 void testAddConfiguration() {
376 final AbstractConfiguration c = setUpTestConfiguration();
377 config.addConfiguration(c);
378 checkAddConfig(c);
379 assertEquals(1, config.getNumberOfConfigurations());
380 assertTrue(config.getConfigurationNames().isEmpty());
381 assertSame(c, config.getConfiguration(0));
382 assertTrue(config.getBoolean(TEST_KEY));
383 listener.checkEvent(1, 0);
384 }
385
386
387
388
389 @Test
390 void testAddConfigurationAt() {
391 final AbstractConfiguration c = setUpTestConfiguration();
392 config.addConfiguration(c, null, "my");
393 checkAddConfig(c);
394 assertTrue(config.getBoolean("my." + TEST_KEY));
395 }
396
397
398
399
400 @Test
401 void testAddConfigurationComplexAt() {
402 final AbstractConfiguration c = setUpTestConfiguration();
403 config.addConfiguration(c, null, "This..is.a.complex");
404 checkAddConfig(c);
405 assertTrue(config.getBoolean("This..is.a.complex." + TEST_KEY));
406 }
407
408
409
410
411 @Test
412 void testAddConfigurationSynchronized() {
413 final SynchronizerTestImpl sync = setUpSynchronizerTest();
414 config.addConfiguration(new BaseHierarchicalConfiguration());
415 sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
416 checkCombinedRootNotConstructed();
417 }
418
419
420
421
422 @Test
423 void testAddConfigurationWithName() {
424 final AbstractConfiguration c = setUpTestConfiguration();
425 config.addConfiguration(c, TEST_NAME);
426 checkAddConfig(c);
427 assertEquals(1, config.getNumberOfConfigurations());
428 assertSame(c, config.getConfiguration(0));
429 assertSame(c, config.getConfiguration(TEST_NAME));
430 final Set<String> names = config.getConfigurationNames();
431 assertEquals(1, names.size());
432 assertTrue(names.contains(TEST_NAME));
433 assertTrue(config.getBoolean(TEST_KEY));
434 listener.checkEvent(1, 0);
435 }
436
437
438
439
440 @Test
441 void testAddConfigurationWithNameTwice() {
442 config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
443 final Configuration configuration = setUpTestConfiguration();
444 assertThrows(ConfigurationRuntimeException.class, () -> config.addConfiguration(configuration, TEST_NAME, "prefix"));
445 }
446
447
448
449
450 @Test
451 void testAddNullConfiguration() {
452 assertThrows(IllegalArgumentException.class, () -> config.addConfiguration(null));
453 }
454
455
456
457
458 @Test
459 void testClear() {
460 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "test");
461 config.addConfiguration(setUpTestConfiguration());
462
463 config.clear();
464 assertEquals(0, config.getNumberOfConfigurations());
465 assertTrue(config.getConfigurationNames().isEmpty());
466 assertTrue(config.isEmpty());
467
468 listener.checkEvent(3, 2);
469 }
470
471
472
473
474
475 @Test
476 void testClearRemoveChildListener() {
477 final AbstractConfiguration child = setUpTestConfiguration();
478 config.addConfiguration(child);
479
480 config.clear();
481 for (final EventListener<?> listener : child.getEventListeners(ConfigurationEvent.ANY)) {
482 assertNotEquals(config, listener);
483 }
484 }
485
486
487
488
489 @Test
490 void testClone() {
491 config.addConfiguration(setUpTestConfiguration());
492 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2");
493 config.addConfiguration(new PropertiesConfiguration(), "props");
494
495 final CombinedConfiguration cc2 = (CombinedConfiguration) config.clone();
496 assertNotNull(cc2.getModel().getNodeHandler().getRootNode());
497 assertEquals(config.getNumberOfConfigurations(), cc2.getNumberOfConfigurations());
498 assertSame(config.getNodeCombiner(), cc2.getNodeCombiner());
499 assertEquals(config.getConfigurationNames().size(), cc2.getConfigurationNames().size());
500 assertTrue(Collections.disjoint(cc2.getEventListeners(ConfigurationEvent.ANY), config.getEventListeners(ConfigurationEvent.ANY)));
501
502 final StrictConfigurationComparator comp = new StrictConfigurationComparator();
503 for (int i = 0; i < config.getNumberOfConfigurations(); i++) {
504 assertNotSame(config.getConfiguration(i), cc2.getConfiguration(i), "Configuration at " + i + " was not cloned");
505 assertEquals(config.getConfiguration(i).getClass(), cc2.getConfiguration(i).getClass(), "Wrong config class at " + i);
506 assertTrue(comp.compare(config.getConfiguration(i), cc2.getConfiguration(i)), "Configs not equal at " + i);
507 }
508
509 assertTrue(comp.compare(config, cc2));
510 }
511
512
513
514
515 @Test
516 void testCloneModify() {
517 config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
518 final CombinedConfiguration cc2 = (CombinedConfiguration) config.clone();
519 assertTrue(cc2.getConfigurationNames().contains(TEST_NAME));
520 cc2.removeConfiguration(TEST_NAME);
521 assertFalse(config.getConfigurationNames().isEmpty());
522 }
523
524
525
526
527 @Test
528 void testCloneSynchronized() {
529 setUpSourceTest();
530 config.lock(LockMode.READ);
531 config.unlock(LockMode.READ);
532 final SynchronizerTestImpl sync = new SynchronizerTestImpl();
533 config.setSynchronizer(sync);
534 config.clone();
535
536 sync.verifyStart(Methods.BEGIN_READ, Methods.BEGIN_READ);
537 sync.verifyEnd(Methods.END_READ, Methods.END_READ);
538 }
539
540
541
542
543
544 @Test
545 void testCombinedCopyToXML() throws ConfigurationException {
546 final XMLConfiguration x1 = new XMLConfiguration();
547 x1.addProperty("key1", "value1");
548 x1.addProperty("key1[@override]", "USER1");
549 x1.addProperty("key2", "value2");
550 x1.addProperty("key2[@override]", "USER2");
551 final XMLConfiguration x2 = new XMLConfiguration();
552 x2.addProperty("key2", "value2.2");
553 x2.addProperty("key2[@override]", "USER2");
554 config.setNodeCombiner(new OverrideCombiner());
555 config.addConfiguration(x2);
556 config.addConfiguration(x1);
557 XMLConfiguration x3 = new XMLConfiguration(config);
558 assertEquals("value2.2", x3.getString("key2"));
559 assertEquals("USER2", x3.getString("key2[@override]"));
560 final StringWriter w = new StringWriter();
561 new FileHandler(x3).save(w);
562 final String s = w.toString();
563 x3 = new XMLConfiguration();
564 new FileHandler(x3).load(new StringReader(s));
565 assertEquals("value2.2", x3.getString("key2"));
566 assertEquals("USER2", x3.getString("key2[@override]"));
567 }
568
569
570
571
572
573 @Test
574 void testConcurrentAccess() throws ConfigurationException, InterruptedException {
575
576 setUpSourceTest();
577 final XMLConfiguration xmlConf = new XMLConfiguration();
578 new FileHandler(xmlConf).load(ConfigurationAssert.getTestFile("test.xml"));
579 config.addConfiguration(xmlConf);
580 final PropertiesConfiguration propConf = new PropertiesConfiguration();
581 new FileHandler(propConf).load(ConfigurationAssert.getTestFile("test.properties"));
582 for (int i = 0; i < 8; i++) {
583 config.addConfiguration(new BaseHierarchicalConfiguration());
584 }
585 config.getConfiguration(0).addProperty(KEY_CONCURRENT, TEST_NAME);
586
587
588 final Synchronizer sync = new ReadWriteSynchronizer();
589 config.setSynchronizer(sync);
590 for (final Configuration c : config.getConfigurations()) {
591 c.setSynchronizer(sync);
592 }
593
594
595 final int numberOfReaders = 3;
596 final int readCount = 5000;
597 final int writeCount = 3000;
598 final CountDownLatch latch = new CountDownLatch(1);
599 final AtomicInteger errorCount = new AtomicInteger();
600 final Collection<Thread> threads = new ArrayList<>(numberOfReaders + 1);
601 final Thread writeThread = new WriteThread(config, latch, errorCount, writeCount);
602 writeThread.start();
603 threads.add(writeThread);
604 for (int i = 0; i < numberOfReaders; i++) {
605 final Thread readThread = new ReadThread(config, latch, errorCount, readCount);
606 readThread.start();
607 threads.add(readThread);
608 }
609
610
611 latch.countDown();
612 for (final Thread t : threads) {
613 t.join();
614 }
615 assertEquals(0, errorCount.get());
616 }
617
618
619
620
621 @Test
622 void testConfigurationsAt() {
623 checkConfigurationsAt(false);
624 }
625
626
627
628
629 @Test
630 void testConfigurationsAtWithUpdates() {
631 checkConfigurationsAt(true);
632 }
633
634
635
636
637
638 @Test
639 void testConversionExpressionEngine() {
640 final PropertiesConfiguration child = new PropertiesConfiguration();
641 child.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
642 child.addProperty("test(a)", "1,2,3");
643 config.addConfiguration(child);
644 final DefaultExpressionEngine engineQuery = new DefaultExpressionEngine(
645 new DefaultExpressionEngineSymbols.Builder(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS).setIndexStart("<").setIndexEnd(">").create());
646 config.setExpressionEngine(engineQuery);
647 final DefaultExpressionEngine engineConvert = new DefaultExpressionEngine(
648 new DefaultExpressionEngineSymbols.Builder(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS).setIndexStart("[").setIndexEnd("]").create());
649 config.setConversionExpressionEngine(engineConvert);
650 assertEquals("1", config.getString("test(a)<0>"));
651 assertEquals("2", config.getString("test(a)<1>"));
652 assertEquals("3", config.getString("test(a)<2>"));
653 }
654
655
656
657
658 @Test
659 void testEscapeListDelimiters() {
660 final PropertiesConfiguration sub = new PropertiesConfiguration();
661 sub.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
662 sub.addProperty("test.pi", "3\\,1415");
663 config.addConfiguration(sub);
664 assertEquals("3,1415", config.getString("test.pi"));
665 }
666
667
668
669
670 @Test
671 void testGetConfigurationByIdxSynchronized() {
672 final SynchronizerTestImpl sync = setUpSynchronizerTest();
673 assertNotNull(config.getConfiguration(0));
674 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
675 checkCombinedRootNotConstructed();
676 }
677
678
679
680
681 @Test
682 void testGetConfigurationByNameSynchronized() {
683 final SynchronizerTestImpl sync = setUpSynchronizerTest();
684 assertNotNull(config.getConfiguration(CHILD1));
685 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
686 checkCombinedRootNotConstructed();
687 }
688
689 @Test
690 void testGetConfigurationNameList() throws Exception {
691 config.addConfiguration(setUpTestConfiguration());
692 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2");
693 final AbstractConfiguration pc = new PropertiesConfiguration();
694 config.addConfiguration(pc, "props");
695 final List<String> list = config.getConfigurationNameList();
696 assertNotNull(list);
697 assertEquals(3, list.size());
698 final String name = list.get(1);
699 assertNotNull(name);
700 assertEquals(TEST_NAME, name);
701 }
702
703
704
705
706 @Test
707 void testGetConfigurationNameListSynchronized() {
708 final SynchronizerTestImpl sync = setUpSynchronizerTest();
709 assertFalse(config.getConfigurationNameList().isEmpty());
710 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
711 checkCombinedRootNotConstructed();
712 }
713
714
715
716
717 @Test
718 void testGetConfigurationNamesSynchronized() {
719 final SynchronizerTestImpl sync = setUpSynchronizerTest();
720 assertFalse(config.getConfigurationNames().isEmpty());
721 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
722 checkCombinedRootNotConstructed();
723 }
724
725 @Test
726 void testGetConfigurations() throws Exception {
727 config.addConfiguration(setUpTestConfiguration());
728 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2");
729 final AbstractConfiguration pc = new PropertiesConfiguration();
730 config.addConfiguration(pc, "props");
731 final List<Configuration> list = config.getConfigurations();
732 assertNotNull(list);
733 assertEquals(3, list.size());
734 final Configuration c = list.get(2);
735 assertSame(pc, c);
736 }
737
738
739
740
741 @Test
742 void testGetConfigurationsSynchronized() {
743 final SynchronizerTestImpl sync = setUpSynchronizerTest();
744 assertFalse(config.getConfigurations().isEmpty());
745 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
746 checkCombinedRootNotConstructed();
747 }
748
749
750
751
752 @Test
753 void testGetConversionExpressionEngineSynchronized() {
754 final SynchronizerTestImpl sync = setUpSynchronizerTest();
755 assertNull(config.getConversionExpressionEngine());
756 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
757 checkCombinedRootNotConstructed();
758 }
759
760
761
762
763 @Test
764 void testGetKeys() {
765
766 final BaseConfiguration conf1 = new BaseConfiguration();
767 final String key = "x1";
768 conf1.addProperty(key, 1);
769 assertEquals(1, conf1.getProperty(key));
770
771 final CombinedConfiguration conf2 = new CombinedConfiguration();
772 conf2.addConfiguration(conf1, null, "");
773 assertEquals(conf1, conf2.getConfiguration(0));
774
775
776 final Iterator<String> keys = conf2.getKeys();
777 assertEquals(key, keys.next());
778 assertFalse(keys.hasNext());
779 }
780
781
782
783
784 @Test
785 void testGetNodeCombinerSynchronized() {
786 final SynchronizerTestImpl sync = setUpSynchronizerTest();
787 assertNotNull(config.getNodeCombiner());
788 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
789 checkCombinedRootNotConstructed();
790 }
791
792
793
794
795 @Test
796 void testGetNumberOfConfigurationsSynchronized() {
797 final SynchronizerTestImpl sync = setUpSynchronizerTest();
798 assertEquals(2, config.getNumberOfConfigurations());
799 sync.verify(Methods.BEGIN_READ, Methods.END_READ);
800 checkCombinedRootNotConstructed();
801 }
802
803
804
805
806 @Test
807 void testGetSourceCombined() {
808 setUpSourceTest();
809 final String key = "yet.another.key";
810 config.addProperty(key, Boolean.TRUE);
811 assertEquals(config, config.getSource(key));
812 }
813
814
815
816
817 @Test
818 void testGetSourceHierarchical() {
819 setUpSourceTest();
820 assertEquals(config.getConfiguration(CHILD1), config.getSource(TEST_KEY));
821 }
822
823
824
825
826
827 @Test
828 void testGetSourceMulti() {
829 setUpSourceTest();
830 final String key = "list.key";
831 config.getConfiguration(CHILD1).addProperty(key, "1,2,3");
832 assertEquals(config.getConfiguration(CHILD1), config.getSource(key));
833 }
834
835
836
837
838
839 @Test
840 void testGetSourceMultiSources() {
841 setUpSourceTest();
842 final String key = "list.key";
843 config.getConfiguration(CHILD1).addProperty(key, "1,2,3");
844 config.getConfiguration(CHILD2).addProperty(key, "a,b,c");
845 assertThrows(IllegalArgumentException.class, () -> config.getSource(key));
846 }
847
848
849
850
851 @Test
852 void testGetSourceNonHierarchical() {
853 setUpSourceTest();
854 assertEquals(config.getConfiguration(CHILD2), config.getSource("another.key"));
855 }
856
857
858
859
860 @Test
861 void testGetSourceNull() {
862 assertThrows(IllegalArgumentException.class, () -> config.getSource(null));
863 }
864
865
866
867
868 @Test
869 void testGetSourcesMultiSources() {
870 setUpSourceTest();
871 final String key = "list.key";
872 config.getConfiguration(CHILD1).addProperty(key, "1,2,3");
873 config.getConfiguration(CHILD2).addProperty(key, "a,b,c");
874 final Set<Configuration> sources = config.getSources(key);
875 assertEquals(2, sources.size());
876 assertTrue(sources.contains(config.getConfiguration(CHILD1)));
877 assertTrue(sources.contains(config.getConfiguration(CHILD2)));
878 }
879
880
881
882
883 @Test
884 void testGetSourcesUnknownKey() {
885 setUpSourceTest();
886 assertTrue(config.getSources("non.existing,key").isEmpty());
887 }
888
889
890
891
892 @Test
893 void testGetSourceSynchronized() {
894 final SynchronizerTestImpl sync = setUpSynchronizerTest();
895 assertNotNull(config.getSource(TEST_KEY));
896 sync.verifyStart(Methods.BEGIN_READ);
897 sync.verifyEnd(Methods.END_READ);
898 }
899
900
901
902
903 @Test
904 void testGetSourceUnknown() {
905 setUpSourceTest();
906 assertNull(config.getSource("an.unknown.key"));
907 }
908
909
910
911
912 @Test
913 void testGetSourceWithCombinedChildConfiguration() {
914 setUpSourceTest();
915 final CombinedConfiguration cc = new CombinedConfiguration();
916 cc.addConfiguration(config);
917 assertEquals(config, cc.getSource(TEST_KEY));
918 }
919
920
921
922
923 @Test
924 void testInit() {
925 assertEquals(0, config.getNumberOfConfigurations());
926 assertTrue(config.getConfigurationNames().isEmpty());
927 assertInstanceOf(UnionCombiner.class, config.getNodeCombiner());
928 assertNull(config.getConfiguration(TEST_NAME));
929 }
930
931
932
933
934 @Test
935 void testInvalidateEventBeforeAndAfterChange() {
936 ConfigurationEvent event = new ConfigurationEvent(config, ConfigurationEvent.ANY, null, null, true);
937 config.onEvent(event);
938 assertEquals(1, listener.invalidateEvents);
939 event = new ConfigurationEvent(config, ConfigurationEvent.ANY, null, null, false);
940 config.onEvent(event);
941 assertEquals(1, listener.invalidateEvents);
942 }
943
944
945
946
947 @Test
948 void testInvalidateSynchronized() {
949 final SynchronizerTestImpl sync = setUpSynchronizerTest();
950 config.invalidate();
951 sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
952 }
953
954
955
956
957 @Test
958 void testLockHandlingWithExceptionWhenConstructingRootNode() {
959 final SynchronizerTestImpl sync = setUpSynchronizerTest();
960 final RuntimeException testEx = new ConfigurationRuntimeException("Test exception");
961 final BaseHierarchicalConfiguration childEx = new BaseHierarchicalConfiguration() {
962 @Override
963 public NodeModel<ImmutableNode> getModel() {
964 throw testEx;
965 }
966 };
967 config.addConfiguration(childEx);
968 final Exception ex = assertThrows(Exception.class, () -> config.lock(LockMode.READ));
969 assertEquals(testEx, ex);
970
971 sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE, Methods.BEGIN_READ, Methods.END_READ, Methods.BEGIN_WRITE, Methods.END_WRITE);
972 }
973
974
975
976
977 @Test
978 void testRemoveConfiguration() {
979 final AbstractConfiguration c = setUpTestConfiguration();
980 config.addConfiguration(c);
981 checkAddConfig(c);
982 assertTrue(config.removeConfiguration(c));
983 checkRemoveConfig(c);
984 }
985
986
987
988
989 @Test
990 void testRemoveConfigurationAt() {
991 final AbstractConfiguration c = setUpTestConfiguration();
992 config.addConfiguration(c);
993 assertSame(c, config.removeConfigurationAt(0));
994 checkRemoveConfig(c);
995 }
996
997
998
999
1000 @Test
1001 void testRemoveConfigurationByName() {
1002 final AbstractConfiguration c = setUpTestConfiguration();
1003 config.addConfiguration(c, TEST_NAME);
1004 assertSame(c, config.removeConfiguration(TEST_NAME));
1005 checkRemoveConfig(c);
1006 }
1007
1008
1009
1010
1011 @Test
1012 void testRemoveConfigurationByUnknownName() {
1013 assertNull(config.removeConfiguration("unknownName"));
1014 listener.checkEvent(0, 0);
1015 }
1016
1017
1018
1019
1020 @Test
1021 void testRemoveNamedConfiguration() {
1022 final AbstractConfiguration c = setUpTestConfiguration();
1023 config.addConfiguration(c, TEST_NAME);
1024 config.removeConfiguration(c);
1025 checkRemoveConfig(c);
1026 }
1027
1028
1029
1030
1031 @Test
1032 void testRemoveNamedConfigurationAt() {
1033 final AbstractConfiguration c = setUpTestConfiguration();
1034 config.addConfiguration(c, TEST_NAME);
1035 assertSame(c, config.removeConfigurationAt(0));
1036 checkRemoveConfig(c);
1037 }
1038
1039
1040
1041
1042 @Test
1043 void testRemoveNonContainedConfiguration() {
1044 assertFalse(config.removeConfiguration(setUpTestConfiguration()));
1045 listener.checkEvent(0, 0);
1046 }
1047
1048
1049
1050
1051 @Test
1052 void testSetConversionExpressionEngineSynchronized() {
1053 final SynchronizerTestImpl sync = setUpSynchronizerTest();
1054 config.setConversionExpressionEngine(new DefaultExpressionEngine(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS));
1055 sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
1056 checkCombinedRootNotConstructed();
1057 }
1058
1059
1060
1061
1062 @Test
1063 void testSetNodeCombiner() {
1064 final NodeCombiner combiner = new UnionCombiner();
1065 config.setNodeCombiner(combiner);
1066 assertSame(combiner, config.getNodeCombiner());
1067 listener.checkEvent(1, 0);
1068 }
1069
1070
1071
1072
1073 @Test
1074 void testSetNodeCombinerSynchronized() {
1075 final SynchronizerTestImpl sync = setUpSynchronizerTest();
1076 config.setNodeCombiner(new UnionCombiner());
1077 sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
1078 checkCombinedRootNotConstructed();
1079 }
1080
1081
1082
1083
1084 @Test
1085 void testSetNullNodeCombiner() {
1086 assertThrows(IllegalArgumentException.class, () -> config.setNodeCombiner(null));
1087 }
1088
1089
1090
1091
1092 @Test
1093 void testSubConfigurationWithUpdates() {
1094 final AbstractConfiguration srcConfig = setUpSubConfigTest();
1095 final HierarchicalConfiguration<ImmutableNode> sub = config.configurationAt(SUB_KEY, true);
1096 assertTrue(sub.getBoolean(TEST_KEY));
1097 srcConfig.setProperty(TEST_KEY, Boolean.FALSE);
1098 assertFalse(sub.getBoolean(TEST_KEY));
1099 assertFalse(config.getBoolean(SUB_KEY + '.' + TEST_KEY));
1100 }
1101
1102
1103
1104
1105 @Test
1106 void testUpdateContainedConfiguration() {
1107 final AbstractConfiguration c = setUpTestConfiguration();
1108 config.addConfiguration(c);
1109 c.addProperty("test.otherTest", "yes");
1110 assertEquals("yes", config.getString("test.otherTest"));
1111 listener.checkEvent(2, 0);
1112 }
1113 }