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.assertDoesNotThrow;
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.assertNotEquals;
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
28 import java.io.Reader;
29 import java.io.StringReader;
30 import java.io.StringWriter;
31 import java.net.URL;
32 import java.util.Deque;
33 import java.util.Iterator;
34
35 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
36 import org.apache.commons.configuration2.convert.LegacyListDelimiterHandler;
37 import org.apache.commons.configuration2.event.ConfigurationEvent;
38 import org.apache.commons.configuration2.event.EventListener;
39 import org.apache.commons.configuration2.ex.ConfigurationException;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42
43
44
45
46 public class TestPropertiesConfigurationLayout {
47
48
49
50
51 static class LayoutTestConfiguration extends PropertiesConfiguration {
52
53
54 private PropertiesBuilder builder;
55
56
57
58
59 @Override
60 boolean propertyLoaded(final String key, final String value, final Deque<URL> seenStack) throws ConfigurationException {
61 if (builder == null) {
62 return super.propertyLoaded(key, value, seenStack);
63 }
64 if (PropertiesConfiguration.getInclude().equals(key)) {
65 getLayout().load(this, builder.getReader());
66 return false;
67 }
68 return true;
69 }
70 }
71
72
73
74
75 static class PropertiesBuilder {
76
77 private final StringBuilder buf = new StringBuilder();
78
79
80 private int commentCounter;
81
82
83
84
85
86
87 public void addComment(final String s) {
88 if (s != null) {
89 if (commentCounter % 2 == 0) {
90 buf.append("# ");
91 } else {
92 buf.append("! ");
93 }
94 buf.append(s);
95 commentCounter++;
96 }
97 buf.append(CR);
98 }
99
100
101
102
103
104
105 public void addLine(final String s) {
106 buf.append(s).append(CR);
107 }
108
109
110
111
112
113
114
115 public void addProperty(final String key, final String value) {
116 buf.append(key).append(" = ").append(value).append(CR);
117 }
118
119
120
121
122
123
124 public Reader getReader() {
125 return new StringReader(buf.toString());
126 }
127
128
129
130
131
132
133 @Override
134 public String toString() {
135 return buf.toString();
136 }
137 }
138
139
140 private static final String CR = System.lineSeparator();
141
142
143 private static final String CRNORM = "\n";
144
145
146 private static final String TEST_KEY = "myProperty";
147
148
149 private static final String TEST_COMMENT = "A comment for my test property";
150
151
152 private static final String TEST_VALUE = "myPropertyValue";
153
154
155 private PropertiesConfigurationLayout layout;
156
157
158 private LayoutTestConfiguration config;
159
160
161 private PropertiesBuilder builder;
162
163
164
165
166
167
168
169 private void checkLayoutString(final String expected) throws ConfigurationException {
170 assertEquals(expected, getLayoutString());
171 }
172
173
174
175
176 private void fillLayout() {
177 builder.addComment("A header comment");
178 builder.addComment(null);
179 builder.addProperty("prop", "value");
180 builder.addComment(TEST_COMMENT);
181 builder.addProperty(TEST_KEY, TEST_VALUE);
182 builder.addProperty("anotherProp", "anotherValue");
183 builder.addComment("A footer comment");
184 assertDoesNotThrow(() -> layout.load(config, builder.getReader()));
185 }
186
187
188
189
190
191
192
193 private String getLayoutString() throws ConfigurationException {
194 final StringWriter out = new StringWriter();
195 layout.save(config, out);
196 return out.toString();
197 }
198
199 @BeforeEach
200 public void setUp() throws Exception {
201 config = new LayoutTestConfiguration();
202 config.setListDelimiterHandler(new LegacyListDelimiterHandler(','));
203 layout = new PropertiesConfigurationLayout();
204 config.setLayout(layout);
205 builder = new PropertiesBuilder();
206 }
207
208
209
210
211 @Test
212 public void testBlankLines() throws ConfigurationException {
213 builder.addProperty("prop", "value");
214 builder.addComment(null);
215 builder.addComment(null);
216 builder.addComment(TEST_COMMENT);
217 builder.addComment(null);
218 builder.addProperty(TEST_KEY, TEST_VALUE);
219 layout.load(config, builder.getReader());
220 assertEquals(2, layout.getBlankLinesBefore(TEST_KEY));
221 assertEquals(TEST_COMMENT + CRNORM, layout.getCanonicalComment(TEST_KEY, false));
222 assertEquals(TEST_VALUE, config.getString(TEST_KEY));
223 }
224
225
226
227
228 @Test
229 public void testBlankLinesWithHeaderComment() throws ConfigurationException {
230 builder.addComment(TEST_COMMENT);
231 builder.addComment(null);
232 builder.addComment(null);
233 builder.addComment(TEST_COMMENT);
234 builder.addProperty(TEST_KEY, TEST_VALUE);
235 layout.load(config, builder.getReader());
236 assertEquals(2, layout.getBlankLinesBefore(TEST_KEY));
237 assertEquals(TEST_COMMENT, layout.getCanonicalComment(TEST_KEY, false));
238 assertEquals(TEST_VALUE, config.getString(TEST_KEY));
239 }
240
241
242
243
244 @Test
245 public void testCombineComments() throws ConfigurationException {
246 builder.addComment(TEST_COMMENT);
247 builder.addProperty(TEST_KEY, TEST_VALUE);
248 builder.addComment(null);
249 builder.addComment(TEST_COMMENT);
250 builder.addProperty(TEST_KEY, TEST_VALUE + "2");
251 layout.load(config, builder.getReader());
252 assertEquals(TEST_COMMENT + CRNORM + TEST_COMMENT, layout.getCanonicalComment(TEST_KEY, false));
253 assertEquals(0, layout.getBlankLinesBefore(TEST_KEY));
254 }
255
256
257
258
259 @Test
260 public void testEventAdd() {
261 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.ADD_PROPERTY, TEST_KEY, TEST_VALUE, false);
262 layout.onEvent(event);
263 assertTrue(layout.getKeys().contains(TEST_KEY));
264 assertEquals(0, layout.getBlankLinesBefore(TEST_KEY));
265 assertTrue(layout.isSingleLine(TEST_KEY));
266 assertEquals(" = ", layout.getSeparator(TEST_KEY));
267 }
268
269
270
271
272 @Test
273 public void testEventAddBefore() {
274 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.ADD_PROPERTY, TEST_KEY, TEST_VALUE, true);
275 layout.onEvent(event);
276 assertFalse(layout.getKeys().contains(TEST_KEY));
277 }
278
279
280
281
282 @Test
283 public void testEventAddExisting() throws ConfigurationException {
284 builder.addComment(TEST_COMMENT);
285 builder.addProperty(TEST_KEY, TEST_VALUE);
286 layout.load(config, builder.getReader());
287 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.ADD_PROPERTY, TEST_KEY, TEST_VALUE, false);
288 layout.onEvent(event);
289 assertFalse(layout.isSingleLine(TEST_KEY));
290 assertEquals(TEST_COMMENT, layout.getCanonicalComment(TEST_KEY, false));
291 }
292
293
294
295
296 @Test
297 public void testEventAddMultiple() {
298 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.ADD_PROPERTY, TEST_KEY, TEST_VALUE, false);
299 layout.onEvent(event);
300 layout.onEvent(event);
301 assertFalse(layout.isSingleLine(TEST_KEY));
302 }
303
304
305
306
307 @Test
308 public void testEventClearConfig() throws Exception {
309 fillLayout();
310 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.CLEAR, null, null, false);
311 layout.onEvent(event);
312 assertTrue(layout.getKeys().isEmpty());
313 assertNull(layout.getHeaderComment());
314 }
315
316
317
318
319 @Test
320 public void testEventDelete() {
321 ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.ADD_PROPERTY, TEST_KEY, TEST_VALUE, false);
322 layout.onEvent(event);
323 event = new ConfigurationEvent(this, ConfigurationEvent.CLEAR_PROPERTY, TEST_KEY, null, false);
324 layout.onEvent(event);
325 assertFalse(layout.getKeys().contains(TEST_KEY));
326 }
327
328
329
330
331 @Test
332 public void testEventSetNonExisting() {
333 final ConfigurationEvent event = new ConfigurationEvent(this, ConfigurationEvent.SET_PROPERTY, TEST_KEY, TEST_VALUE, false);
334 layout.onEvent(event);
335 assertTrue(layout.getKeys().contains(TEST_KEY));
336 }
337
338
339
340
341 @Test
342 public void testGetNonExistingLayouData() {
343 assertNull(layout.getComment("unknown"));
344 assertTrue(layout.isSingleLine("unknown"));
345 assertEquals(0, layout.getBlankLinesBefore("unknown"));
346 }
347
348
349
350
351 @Test
352 public void testGetNullLayouttData() {
353 assertThrows(IllegalArgumentException.class, () -> layout.setComment(null, TEST_COMMENT));
354 }
355
356
357
358
359 @Test
360 public void testHeaderComment() throws ConfigurationException {
361 builder.addComment(TEST_COMMENT);
362 builder.addComment(null);
363 builder.addProperty(TEST_KEY, TEST_VALUE);
364 layout.load(config, builder.getReader());
365 assertEquals(TEST_COMMENT, layout.getCanonicalHeaderComment(false));
366 assertNull(layout.getCanonicalComment(TEST_KEY, false));
367 }
368
369
370
371
372 @Test
373 public void testHeaderCommentNull() {
374 assertNull(layout.getCanonicalHeaderComment(true));
375 assertNull(layout.getCanonicalHeaderComment(false));
376 }
377
378
379
380
381 @Test
382 public void testHeaderCommentWithBlanks() throws ConfigurationException {
383 builder.addComment(TEST_COMMENT);
384 builder.addComment(null);
385 builder.addComment(TEST_COMMENT);
386 builder.addComment(null);
387 builder.addProperty(TEST_KEY, TEST_VALUE);
388 layout.load(config, builder.getReader());
389 assertEquals(TEST_COMMENT + CRNORM + CRNORM + TEST_COMMENT, layout.getCanonicalHeaderComment(false));
390 assertNull(layout.getComment(TEST_KEY));
391 }
392
393
394
395
396
397 @Test
398 public void testHeaderCommentWithBlanksAndPresetHeaderComment() throws ConfigurationException {
399 final String presetHeaderComment = "preset" + TEST_COMMENT + CRNORM + CRNORM + TEST_COMMENT;
400 builder.addComment(TEST_COMMENT);
401 builder.addComment(null);
402 builder.addComment(TEST_COMMENT);
403 builder.addComment(null);
404 builder.addProperty(TEST_KEY, TEST_VALUE);
405 layout.setHeaderComment(presetHeaderComment);
406 layout.load(config, builder.getReader());
407 assertEquals(presetHeaderComment, layout.getCanonicalHeaderComment(false));
408 assertNull(layout.getComment(TEST_KEY));
409 }
410
411
412
413
414
415 @Test
416 public void testHeaderCommentWithBlanksAndPropComment() throws ConfigurationException {
417 builder.addComment(TEST_COMMENT);
418 builder.addComment(null);
419 builder.addComment(TEST_COMMENT);
420 builder.addComment(null);
421 builder.addComment(TEST_COMMENT);
422 builder.addProperty(TEST_KEY, TEST_VALUE);
423 layout.load(config, builder.getReader());
424 assertEquals(TEST_COMMENT + CRNORM + CRNORM + TEST_COMMENT, layout.getCanonicalHeaderComment(false));
425 assertEquals(TEST_COMMENT, layout.getCanonicalComment(TEST_KEY, false));
426 }
427
428
429
430
431 @Test
432 public void testInit() {
433 assertTrue(layout.getKeys().isEmpty());
434 assertNull(layout.getHeaderComment());
435 final Iterator<EventListener<? super ConfigurationEvent>> it = config.getEventListeners(ConfigurationEvent.ANY).iterator();
436 assertTrue(it.hasNext());
437 assertSame(layout, it.next());
438 assertFalse(it.hasNext());
439 assertFalse(layout.isForceSingleLine());
440 assertNull(layout.getGlobalSeparator());
441 }
442
443
444
445
446 @Test
447 public void testInitCopy() {
448 fillLayout();
449 final PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout(layout);
450 assertEquals(l2.getKeys(), layout.getKeys());
451 assertEquals(layout.getHeaderComment(), l2.getHeaderComment());
452 assertEquals(layout.getFooterComment(), l2.getFooterComment());
453 }
454
455
456
457
458 @Test
459 public void testInitCopyModify() {
460 fillLayout();
461 final PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout(layout);
462 assertEquals(layout.getComment(TEST_KEY), l2.getComment(TEST_KEY));
463 layout.setComment(TEST_KEY, "A new comment");
464 assertEquals(TEST_COMMENT, l2.getCanonicalComment(TEST_KEY, false));
465 l2.setBlankLinesBefore(TEST_KEY, l2.getBlankLinesBefore(TEST_KEY) + 1);
466 assertNotEquals(layout.getBlankLinesBefore(TEST_KEY), l2.getBlankLinesBefore(TEST_KEY));
467 }
468
469
470
471
472 @Test
473 public void testInitNull() {
474 layout = new PropertiesConfigurationLayout(null);
475 assertTrue(layout.getKeys().isEmpty());
476 }
477
478
479
480
481 @Test
482 public void testIsSingleLine() throws ConfigurationException {
483 builder.addProperty(TEST_KEY, TEST_VALUE + "," + TEST_VALUE + "2");
484 layout.load(config, builder.getReader());
485 assertTrue(layout.isSingleLine(TEST_KEY));
486 assertEquals(2, config.getList(TEST_KEY).size());
487 }
488
489
490
491
492 @Test
493 public void testIsSingleLineMulti() throws ConfigurationException {
494 builder.addProperty(TEST_KEY, TEST_VALUE);
495 builder.addProperty("anotherProp", "a value");
496 builder.addProperty(TEST_KEY, TEST_VALUE + "2");
497 layout.load(config, builder.getReader());
498 assertFalse(layout.isSingleLine(TEST_KEY));
499 assertEquals(2, config.getList(TEST_KEY).size());
500 }
501
502
503
504
505 @Test
506 public void testLineWithBlank() throws ConfigurationException {
507 builder.addComment(TEST_COMMENT);
508 builder.addLine(" ");
509 builder.addProperty(TEST_KEY, TEST_VALUE);
510 layout.load(config, builder.getReader());
511 assertEquals(TEST_COMMENT + CRNORM + " ", layout.getCanonicalComment(TEST_KEY, false));
512 }
513
514
515
516
517 @Test
518 public void testReadAndWrite() throws ConfigurationException {
519 builder.addComment("This is my test properties file,");
520 builder.addComment("which contains a header comment.");
521 builder.addComment(null);
522 builder.addComment(null);
523 builder.addComment(TEST_COMMENT);
524 builder.addProperty(TEST_KEY, TEST_COMMENT);
525 builder.addComment(null);
526 builder.addComment(null);
527 builder.addComment("Another comment");
528 builder.addProperty("property", "and a value");
529 layout.load(config, builder.getReader());
530 checkLayoutString(builder.toString());
531 }
532
533
534
535
536 @Test
537 public void testReadSimple() throws ConfigurationException {
538 builder.addComment(TEST_COMMENT);
539 builder.addProperty(TEST_KEY, TEST_VALUE);
540 layout.load(config, builder.getReader());
541 assertNull(layout.getHeaderComment());
542 assertEquals(1, layout.getKeys().size());
543 assertTrue(layout.getKeys().contains(TEST_KEY));
544 assertEquals(TEST_COMMENT, layout.getCanonicalComment(TEST_KEY, false));
545 assertEquals(0, layout.getBlankLinesBefore(TEST_KEY));
546 assertTrue(layout.isSingleLine(TEST_KEY));
547 assertEquals(TEST_VALUE, config.getString(TEST_KEY));
548 }
549
550
551
552
553 @Test
554 public void testRecursiveLoadCall() throws ConfigurationException {
555 final PropertiesBuilder b = new PropertiesBuilder();
556 b.addComment("A nested header comment.");
557 b.addComment("With multiple lines");
558 b.addComment(null);
559 b.addComment("Second comment");
560 b.addProperty(TEST_KEY, TEST_VALUE);
561 b.addProperty(TEST_KEY + "2", TEST_VALUE + "2");
562 config.builder = b;
563
564 builder.addComment("Header comment");
565 builder.addComment(null);
566 builder.addComment(TEST_COMMENT);
567 builder.addProperty(TEST_KEY, TEST_VALUE);
568 builder.addComment("Include file");
569 builder.addProperty(PropertiesConfiguration.getInclude(), "test");
570
571 layout.load(config, builder.getReader());
572
573 assertEquals("Header comment", layout.getCanonicalHeaderComment(false));
574 assertFalse(layout.getKeys().contains(PropertiesConfiguration.getInclude()));
575 assertEquals(TEST_COMMENT + CRNORM + "A nested header comment." + CRNORM + "With multiple lines" + CRNORM + CRNORM + "Second comment",
576 layout.getCanonicalComment(TEST_KEY, false));
577 }
578
579
580
581
582 @Test
583 public void testSave() throws ConfigurationException {
584 config.addProperty(TEST_KEY, TEST_VALUE);
585 layout.setComment(TEST_KEY, TEST_COMMENT);
586 config.addProperty(TEST_KEY, TEST_VALUE + "2");
587 config.addProperty("AnotherProperty", "AnotherValue");
588 config.addProperty("AnotherProperty", "3rdValue");
589 layout.setComment("AnotherProperty", "AnotherComment");
590 layout.setBlankLinesBefore("AnotherProperty", 2);
591 layout.setSingleLine("AnotherProperty", true);
592 layout.setHeaderComment("A header comment" + CRNORM + "for my properties");
593 checkLayoutString("# A header comment" + CR + "# for my properties" + CR + CR + "# " + TEST_COMMENT + CR + TEST_KEY + " = " + TEST_VALUE + CR + TEST_KEY
594 + " = " + TEST_VALUE + "2" + CR + CR + CR + "# AnotherComment" + CR + "AnotherProperty = AnotherValue,3rdValue" + CR);
595 }
596
597
598
599
600
601 @Test
602 public void testSaveCommentForUnexistingProperty() throws ConfigurationException {
603 fillLayout();
604 layout.setComment("NonExistingKey", "NonExistingComment");
605 final String output = getLayoutString();
606 assertFalse(output.contains("NonExistingKey"));
607 assertFalse(output.contains("NonExistingComment"));
608 }
609
610
611
612
613 @Test
614 public void testSaveEmptyLayout() throws ConfigurationException {
615 checkLayoutString("");
616 }
617
618
619
620
621 @Test
622 public void testSaveForceSingleLine() throws ConfigurationException {
623 config.setListDelimiterHandler(new DefaultListDelimiterHandler(';'));
624 config.addProperty(TEST_KEY, TEST_VALUE);
625 config.addProperty(TEST_KEY, TEST_VALUE + "2");
626 config.addProperty("AnotherProperty", "value1;value2;value3");
627 layout.setComment(TEST_KEY, TEST_COMMENT);
628 layout.setForceSingleLine(true);
629 checkLayoutString(
630 "# " + TEST_COMMENT + CR + TEST_KEY + " = " + TEST_VALUE + ';' + TEST_VALUE + "2" + CR + "AnotherProperty = value1;value2;value3" + CR);
631 }
632
633
634
635
636 @Test
637 public void testSetGlobalSeparator() throws ConfigurationException {
638 final String sep = "=";
639 config.addProperty(TEST_KEY, TEST_VALUE);
640 config.addProperty("key2", "value2");
641 layout.setSeparator(TEST_KEY, " : ");
642 layout.setGlobalSeparator(sep);
643 checkLayoutString(TEST_KEY + sep + TEST_VALUE + CR + "key2" + sep + "value2" + CR);
644 }
645
646
647
648
649 @Test
650 public void testSetLineSeparator() throws ConfigurationException {
651 final String lf = CR + CR;
652 config.addProperty(TEST_KEY, TEST_VALUE);
653 layout.setBlankLinesBefore(TEST_KEY, 2);
654 layout.setComment(TEST_KEY, TEST_COMMENT);
655 layout.setHeaderComment("Header comment");
656 layout.setLineSeparator(lf);
657 checkLayoutString("# Header comment" + lf + lf + lf + "# " + TEST_COMMENT + lf + TEST_KEY + " = " + TEST_VALUE + lf);
658 }
659
660
661
662
663 @Test
664 public void testSetLineSeparatorInComments() throws ConfigurationException {
665 final String lf = "<-\n";
666 config.addProperty(TEST_KEY, TEST_VALUE);
667 layout.setComment(TEST_KEY, TEST_COMMENT + "\nMore comment");
668 layout.setHeaderComment("Header\ncomment");
669 layout.setLineSeparator(lf);
670 checkLayoutString("# Header" + lf + "# comment" + lf + lf + "# " + TEST_COMMENT + lf + "# More comment" + lf + TEST_KEY + " = " + TEST_VALUE + lf);
671 }
672
673
674
675
676 @Test
677 public void testSetNullComment() {
678 fillLayout();
679 layout.setComment(TEST_KEY, null);
680 assertNull(layout.getComment(TEST_KEY));
681 }
682
683
684
685
686 @Test
687 public void testSetSeparator() throws ConfigurationException {
688 config.addProperty(TEST_KEY, TEST_VALUE);
689 layout.setSeparator(TEST_KEY, ":");
690 checkLayoutString(TEST_KEY + ":" + TEST_VALUE + CR);
691 }
692
693
694
695
696 @Test
697 public void testTrimComment() {
698 assertEquals("This is a comment" + CR + "that spans multiple" + CR + "lines in a" + CR + " complex way.",
699 PropertiesConfigurationLayout.trimComment(
700 " # This is a comment" + CR + "that spans multiple" + CR + "!lines in a" + CR + " complex way.",
701 false
702 ));
703 }
704
705
706
707
708 @Test
709 public void testTrimCommentFalse() {
710 assertEquals("# Comment with" + CR + " ! some mixed " + CR + "#comment" + CR + "# lines",
711 PropertiesConfigurationLayout.trimComment("Comment with" + CR + " ! some mixed " + CR + "#comment" + CR + "lines", true));
712 }
713
714
715
716
717 @Test
718 public void testTrimCommentTrainlingCR() {
719 assertEquals("Comment with" + CR + "trailing CR" + CR,
720 PropertiesConfigurationLayout.trimComment("Comment with" + CR + "! trailing CR" + CR, false));
721 }
722 }