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