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