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