001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.configuration; 018 019 import static org.junit.Assert.assertEquals; 020 import static org.junit.Assert.assertFalse; 021 import static org.junit.Assert.assertNotNull; 022 import static org.junit.Assert.assertNull; 023 import static org.junit.Assert.assertSame; 024 import static org.junit.Assert.assertTrue; 025 import static org.junit.Assert.fail; 026 027 import java.io.Reader; 028 import java.io.StringReader; 029 import java.io.StringWriter; 030 import java.util.Iterator; 031 032 import org.apache.commons.configuration.event.ConfigurationEvent; 033 import org.apache.commons.configuration.event.ConfigurationListener; 034 import org.junit.Before; 035 import org.junit.Test; 036 037 /** 038 * Test class for PropertiesConfigurationLayout. 039 * 040 * @author <a 041 * href="http://commons.apache.org/configuration/team-list.html">Commons 042 * Configuration team</a> 043 * @version $Id: TestPropertiesConfigurationLayout.java 1301996 2012-03-17 20:30:39Z sebb $ 044 */ 045 public class TestPropertiesConfigurationLayout 046 { 047 /** Constant for the line break character. */ 048 private static final String CR = System.getProperty("line.separator"); 049 050 /** Constant for the normalized line break character. */ 051 private static final String CRNORM = "\n"; 052 053 /** Constant for a test property key. */ 054 static final String TEST_KEY = "myProperty"; 055 056 /** Constant for a test comment. */ 057 static final String TEST_COMMENT = "A comment for my test property"; 058 059 /** Constant for a test property value. */ 060 static final String TEST_VALUE = "myPropertyValue"; 061 062 /** The layout object under test. */ 063 PropertiesConfigurationLayout layout; 064 065 /** The associated configuration object. */ 066 LayoutTestConfiguration config; 067 068 /** A properties builder that can be used for testing. */ 069 PropertiesBuilder builder; 070 071 @Before 072 public void setUp() throws Exception 073 { 074 config = new LayoutTestConfiguration(); 075 layout = new PropertiesConfigurationLayout(config); 076 config.setLayout(layout); 077 builder = new PropertiesBuilder(); 078 } 079 080 /** 081 * Tests a newly created instance. 082 */ 083 @Test 084 public void testInit() 085 { 086 assertTrue("Object contains keys", layout.getKeys().isEmpty()); 087 assertNull("Header comment not null", layout.getHeaderComment()); 088 Iterator<ConfigurationListener> it = config.getConfigurationListeners().iterator(); 089 assertTrue("No event listener registered", it.hasNext()); 090 assertSame("Layout not registered as event listener", layout, it.next()); 091 assertFalse("Multiple event listeners registered", it.hasNext()); 092 assertSame("Configuration not stored", config, layout 093 .getConfiguration()); 094 assertFalse("Force single line flag set", layout.isForceSingleLine()); 095 assertNull("Got a global separator", layout.getGlobalSeparator()); 096 } 097 098 /** 099 * Tests creating a layout object with a null configuration. This should 100 * cause an exception. 101 */ 102 @Test(expected = IllegalArgumentException.class) 103 public void testInitNull() 104 { 105 new PropertiesConfigurationLayout(null); 106 } 107 108 /** 109 * Tests reading a simple properties file. 110 */ 111 @Test 112 public void testReadSimple() throws ConfigurationException 113 { 114 builder.addComment(TEST_COMMENT); 115 builder.addProperty(TEST_KEY, TEST_VALUE); 116 layout.load(builder.getReader()); 117 assertNull("A header comment was found", layout.getHeaderComment()); 118 assertEquals("Wrong number of properties", 1, layout.getKeys().size()); 119 assertTrue("Property not found", layout.getKeys().contains(TEST_KEY)); 120 assertEquals("Comment not found", TEST_COMMENT, layout 121 .getCanonicalComment(TEST_KEY, false)); 122 assertEquals("Wrong number of blanc lines", 0, layout 123 .getBlancLinesBefore(TEST_KEY)); 124 assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY)); 125 assertEquals("Property not stored in config", TEST_VALUE, config 126 .getString(TEST_KEY)); 127 } 128 129 /** 130 * Tests whether blanc lines before a property are correctly detected. 131 */ 132 @Test 133 public void testBlancLines() throws ConfigurationException 134 { 135 builder.addProperty("prop", "value"); 136 builder.addComment(null); 137 builder.addComment(null); 138 builder.addComment(TEST_COMMENT); 139 builder.addComment(null); 140 builder.addProperty(TEST_KEY, TEST_VALUE); 141 layout.load(builder.getReader()); 142 assertEquals("Wrong number of blanc lines", 2, layout 143 .getBlancLinesBefore(TEST_KEY)); 144 assertEquals("Wrong comment", TEST_COMMENT + CRNORM, layout 145 .getCanonicalComment(TEST_KEY, false)); 146 assertEquals("Wrong property value", TEST_VALUE, config 147 .getString(TEST_KEY)); 148 } 149 150 /** 151 * Tests the single line flag for a simple property definition. 152 */ 153 @Test 154 public void testIsSingleLine() throws ConfigurationException 155 { 156 builder.addProperty(TEST_KEY, TEST_VALUE + "," + TEST_VALUE + "2"); 157 layout.load(builder.getReader()); 158 assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY)); 159 assertEquals("Wrong number of values", 2, config.getList(TEST_KEY) 160 .size()); 161 } 162 163 /** 164 * Tests the single line flag if there are multiple property definitions. 165 */ 166 @Test 167 public void testIsSingleLineMulti() throws ConfigurationException 168 { 169 builder.addProperty(TEST_KEY, TEST_VALUE); 170 builder.addProperty("anotherProp", "a value"); 171 builder.addProperty(TEST_KEY, TEST_VALUE + "2"); 172 layout.load(builder.getReader()); 173 assertFalse("Wrong single line flag", layout.isSingleLine(TEST_KEY)); 174 assertEquals("Wrong number of values", 2, config.getList(TEST_KEY) 175 .size()); 176 } 177 178 /** 179 * Tests whether comments are combined for multiple occurrences. 180 */ 181 @Test 182 public void testCombineComments() throws ConfigurationException 183 { 184 builder.addComment(TEST_COMMENT); 185 builder.addProperty(TEST_KEY, TEST_VALUE); 186 builder.addComment(null); 187 builder.addComment(TEST_COMMENT); 188 builder.addProperty(TEST_KEY, TEST_VALUE + "2"); 189 layout.load(builder.getReader()); 190 assertEquals("Wrong combined comment", 191 TEST_COMMENT + CRNORM + TEST_COMMENT, layout.getCanonicalComment( 192 TEST_KEY, false)); 193 assertEquals("Wrong combined blanc numbers", 0, layout 194 .getBlancLinesBefore(TEST_KEY)); 195 } 196 197 /** 198 * Tests if a header comment is detected. 199 */ 200 @Test 201 public void testHeaderComment() throws ConfigurationException 202 { 203 builder.addComment(TEST_COMMENT); 204 builder.addComment(null); 205 builder.addProperty(TEST_KEY, TEST_VALUE); 206 layout.load(builder.getReader()); 207 assertEquals("Wrong header comment", TEST_COMMENT, layout 208 .getCanonicalHeaderComment(false)); 209 assertNull("Wrong comment for property", layout.getCanonicalComment( 210 TEST_KEY, false)); 211 } 212 213 /** 214 * Tests if a header comment containing blanc lines is correctly detected. 215 */ 216 @Test 217 public void testHeaderCommentWithBlancs() throws ConfigurationException 218 { 219 builder.addComment(TEST_COMMENT); 220 builder.addComment(null); 221 builder.addComment(TEST_COMMENT); 222 builder.addComment(null); 223 builder.addProperty(TEST_KEY, TEST_VALUE); 224 layout.load(builder.getReader()); 225 assertEquals("Wrong header comment", TEST_COMMENT + CRNORM + CRNORM 226 + TEST_COMMENT, layout.getCanonicalHeaderComment(false)); 227 assertNull("Wrong comment for property", layout.getComment(TEST_KEY)); 228 } 229 230 /** 231 * Tests if a header comment is correctly detected when it contains blanc 232 * lines and the first property has a comment, too. 233 */ 234 @Test 235 public void testHeaderCommentWithBlancsAndPropComment() 236 throws ConfigurationException 237 { 238 builder.addComment(TEST_COMMENT); 239 builder.addComment(null); 240 builder.addComment(TEST_COMMENT); 241 builder.addComment(null); 242 builder.addComment(TEST_COMMENT); 243 builder.addProperty(TEST_KEY, TEST_VALUE); 244 layout.load(builder.getReader()); 245 assertEquals("Wrong header comment", TEST_COMMENT + CRNORM + CRNORM 246 + TEST_COMMENT, layout.getCanonicalHeaderComment(false)); 247 assertEquals("Wrong comment for property", TEST_COMMENT, layout 248 .getCanonicalComment(TEST_KEY, false)); 249 } 250 251 /** 252 * Tests fetching a canonical header comment when no comment is set. 253 */ 254 @Test 255 public void testHeaderCommentNull() 256 { 257 assertNull("No null comment with comment chars", layout 258 .getCanonicalHeaderComment(true)); 259 assertNull("No null comment without comment chars", layout 260 .getCanonicalHeaderComment(false)); 261 } 262 263 /** 264 * Tests if a property add event is correctly processed. 265 */ 266 @Test 267 public void testEventAdd() 268 { 269 ConfigurationEvent event = new ConfigurationEvent(this, 270 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, 271 false); 272 layout.configurationChanged(event); 273 assertTrue("Property not stored", layout.getKeys().contains(TEST_KEY)); 274 assertEquals("Blanc lines before new property", 0, layout 275 .getBlancLinesBefore(TEST_KEY)); 276 assertTrue("No single line property", layout.isSingleLine(TEST_KEY)); 277 assertEquals("Wrong separator", " = ", layout.getSeparator(TEST_KEY)); 278 } 279 280 /** 281 * Tests adding a property multiple time through an event. The property 282 * should then be a multi-line property. 283 */ 284 @Test 285 public void testEventAddMultiple() 286 { 287 ConfigurationEvent event = new ConfigurationEvent(this, 288 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, 289 false); 290 layout.configurationChanged(event); 291 layout.configurationChanged(event); 292 assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY)); 293 } 294 295 /** 296 * Tests if an add event is correctly processed if the affected property is 297 * already stored in the layout object. 298 */ 299 @Test 300 public void testEventAddExisting() throws ConfigurationException 301 { 302 builder.addComment(TEST_COMMENT); 303 builder.addProperty(TEST_KEY, TEST_VALUE); 304 layout.load(builder.getReader()); 305 ConfigurationEvent event = new ConfigurationEvent(this, 306 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, 307 false); 308 layout.configurationChanged(event); 309 assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY)); 310 assertEquals("Comment was modified", TEST_COMMENT, layout 311 .getCanonicalComment(TEST_KEY, false)); 312 } 313 314 /** 315 * Tests if a set property event for a non existing property is correctly 316 * handled. 317 */ 318 @Test 319 public void testEventSetNonExisting() 320 { 321 ConfigurationEvent event = new ConfigurationEvent(this, 322 AbstractConfiguration.EVENT_SET_PROPERTY, TEST_KEY, TEST_VALUE, 323 false); 324 layout.configurationChanged(event); 325 assertTrue("New property was not found", layout.getKeys().contains( 326 TEST_KEY)); 327 } 328 329 /** 330 * Tests if a property delete event is correctly processed. 331 */ 332 @Test 333 public void testEventDelete() 334 { 335 ConfigurationEvent event = new ConfigurationEvent(this, 336 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, 337 false); 338 layout.configurationChanged(event); 339 event = new ConfigurationEvent(this, 340 AbstractConfiguration.EVENT_CLEAR_PROPERTY, TEST_KEY, null, 341 false); 342 layout.configurationChanged(event); 343 assertFalse("Property still existing", layout.getKeys().contains( 344 TEST_KEY)); 345 } 346 347 /** 348 * Tests if a clear event is correctly processed. 349 */ 350 @Test 351 public void testEventClearConfig() throws Exception 352 { 353 fillLayout(); 354 ConfigurationEvent event = new ConfigurationEvent(this, 355 AbstractConfiguration.EVENT_CLEAR, null, null, false); 356 layout.configurationChanged(event); 357 assertTrue("Keys not empty", layout.getKeys().isEmpty()); 358 assertNull("Header comment was not reset", layout.getHeaderComment()); 359 } 360 361 /** 362 * Tests if a before update event is correctly ignored. 363 */ 364 @Test 365 public void testEventAddBefore() 366 { 367 ConfigurationEvent event = new ConfigurationEvent(this, 368 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, 369 true); 370 layout.configurationChanged(event); 371 assertFalse("Property already stored", layout.getKeys().contains( 372 TEST_KEY)); 373 } 374 375 /** 376 * Tests if a reload update is correctly processed. 377 */ 378 @Test 379 public void testEventReload() 380 { 381 fillLayout(); 382 ConfigurationEvent event = new ConfigurationEvent(this, 383 AbstractFileConfiguration.EVENT_RELOAD, null, null, true); 384 layout.configurationChanged(event); 385 assertTrue("Keys not empty", layout.getKeys().isEmpty()); 386 assertNull("Header comment was not reset", layout.getHeaderComment()); 387 } 388 389 /** 390 * Tests the event after a reload has been performed. This should be 391 * ignored. 392 */ 393 @Test 394 public void testEventReloadAfter() 395 { 396 fillLayout(); 397 ConfigurationEvent event = new ConfigurationEvent(this, 398 AbstractFileConfiguration.EVENT_RELOAD, null, null, false); 399 layout.configurationChanged(event); 400 assertFalse("Keys are empty", layout.getKeys().isEmpty()); 401 assertNotNull("Header comment was reset", layout.getHeaderComment()); 402 } 403 404 /** 405 * Tests a recursive load call. 406 */ 407 @Test 408 public void testRecursiveLoadCall() throws ConfigurationException 409 { 410 PropertiesBuilder b = new PropertiesBuilder(); 411 b.addComment("A nested header comment."); 412 b.addComment("With multiple lines"); 413 b.addComment(null); 414 b.addComment("Second comment"); 415 b.addProperty(TEST_KEY, TEST_VALUE); 416 b.addProperty(TEST_KEY + "2", TEST_VALUE + "2"); 417 config.builder = b; 418 419 builder.addComment("Header comment"); 420 builder.addComment(null); 421 builder.addComment(TEST_COMMENT); 422 builder.addProperty(TEST_KEY, TEST_VALUE); 423 builder.addComment("Include file"); 424 builder.addProperty(PropertiesConfiguration.getInclude(), "test"); 425 426 layout.load(builder.getReader()); 427 428 assertEquals("Wrong header comment", "Header comment", layout 429 .getCanonicalHeaderComment(false)); 430 assertFalse("Include property was stored", layout.getKeys().contains( 431 PropertiesConfiguration.getInclude())); 432 assertEquals("Wrong comment for property", TEST_COMMENT + CRNORM 433 + "A nested header comment." + CRNORM + "With multiple lines" + CRNORM 434 + CRNORM + "Second comment", layout.getCanonicalComment(TEST_KEY, 435 false)); 436 } 437 438 /** 439 * Tests whether the output of the layout object is identical to the source 440 * file (at least for simple properties files). 441 */ 442 @Test 443 public void testReadAndWrite() throws ConfigurationException 444 { 445 builder.addComment("This is my test properties file,"); 446 builder.addComment("which contains a header comment."); 447 builder.addComment(null); 448 builder.addComment(TEST_COMMENT); 449 builder.addProperty(TEST_KEY, TEST_COMMENT); 450 builder.addComment(null); 451 builder.addComment(null); 452 builder.addComment("Another comment"); 453 builder.addProperty("property", "and a value"); 454 layout.load(builder.getReader()); 455 checkLayoutString(builder.toString()); 456 } 457 458 /** 459 * Tests if the content of the layout object is correctly written. 460 */ 461 @Test 462 public void testSave() throws ConfigurationException 463 { 464 config.addProperty(TEST_KEY, TEST_VALUE); 465 layout.setComment(TEST_KEY, TEST_COMMENT); 466 config.addProperty(TEST_KEY, TEST_VALUE + "2"); 467 config.addProperty("AnotherProperty", "AnotherValue"); 468 config.addProperty("AnotherProperty", "3rdValue"); 469 layout.setComment("AnotherProperty", "AnotherComment"); 470 layout.setBlancLinesBefore("AnotherProperty", 2); 471 layout.setSingleLine("AnotherProperty", true); 472 layout.setHeaderComment("A header comment" + CRNORM + "for my properties"); 473 checkLayoutString("# A header comment" + CR + "# for my properties" 474 + CR + CR + "# " + TEST_COMMENT + CR + TEST_KEY + " = " 475 + TEST_VALUE + CR + TEST_KEY + " = " + TEST_VALUE + "2" + CR 476 + CR + CR + "# AnotherComment" + CR 477 + "AnotherProperty = AnotherValue,3rdValue" + CR); 478 } 479 480 /** 481 * Tests the force single line flag. 482 */ 483 @Test 484 public void testSaveForceSingleLine() throws ConfigurationException 485 { 486 config.setListDelimiter(';'); 487 config.addProperty(TEST_KEY, TEST_VALUE); 488 config.addProperty(TEST_KEY, TEST_VALUE + "2"); 489 config.addProperty("AnotherProperty", "value1;value2;value3"); 490 layout.setComment(TEST_KEY, TEST_COMMENT); 491 layout.setForceSingleLine(true); 492 checkLayoutString("# " + TEST_COMMENT + CR + TEST_KEY + " = " 493 + TEST_VALUE + ';' + TEST_VALUE + "2" + CR 494 + "AnotherProperty = value1;value2;value3" + CR); 495 } 496 497 /** 498 * Tests the trimComment method. 499 */ 500 @Test 501 public void testTrimComment() 502 { 503 assertEquals("Wrong trimmed comment", "This is a comment" + CR 504 + "that spans multiple" + CR + "lines in a" + CR 505 + " complex way.", PropertiesConfigurationLayout.trimComment( 506 " # This is a comment" + CR + "that spans multiple" + CR 507 + "!lines in a" + CR + " complex way.", false)); 508 } 509 510 /** 511 * Tests trimming a comment with trailing CRs. 512 */ 513 @Test 514 public void testTrimCommentTrainlingCR() 515 { 516 assertEquals("Wrong trimmed comment", "Comment with" + CR 517 + "trailing CR" + CR, PropertiesConfigurationLayout 518 .trimComment("Comment with" + CR + "! trailing CR" + CR, false)); 519 } 520 521 /** 522 * Tests enforcing comment characters in a comment. 523 */ 524 @Test 525 public void testTrimCommentFalse() 526 { 527 assertEquals("Wrong trimmed comment", "# Comment with" + CR 528 + " ! some mixed " + CR + "#comment" + CR + "# lines", 529 PropertiesConfigurationLayout.trimComment("Comment with" + CR 530 + " ! some mixed " + CR + "#comment" + CR + "lines", 531 true)); 532 } 533 534 /** 535 * Tests accessing data for a property, which is not stored. 536 */ 537 @Test 538 public void testGetNonExistingLayouData() 539 { 540 assertNull("A comment was found", layout.getComment("unknown")); 541 assertTrue("A multi-line property", layout.isSingleLine("unknown")); 542 assertEquals("Leading blanc lines", 0, layout 543 .getBlancLinesBefore("unknown")); 544 } 545 546 /** 547 * Tests accessing a property with a null key. This should throw an 548 * exception. 549 */ 550 @Test(expected = IllegalArgumentException.class) 551 public void testGetNullLayouttData() 552 { 553 layout.setComment(null, TEST_COMMENT); 554 } 555 556 /** 557 * Tests resetting a comment. 558 */ 559 @Test 560 public void testSetNullComment() 561 { 562 fillLayout(); 563 layout.setComment(TEST_KEY, null); 564 assertNull("Comment was not reset", layout.getComment(TEST_KEY)); 565 } 566 567 /** 568 * Tests saving when a comment for a non existing property is contained in 569 * the layout object. This comment should be ignored. 570 */ 571 @Test 572 public void testSaveCommentForUnexistingProperty() 573 throws ConfigurationException 574 { 575 fillLayout(); 576 layout.setComment("NonExistingKey", "NonExistingComment"); 577 String output = getLayoutString(); 578 assertTrue("Non existing key was found", output 579 .indexOf("NonExistingKey") < 0); 580 assertTrue("Non existing comment was found", output 581 .indexOf("NonExistingComment") < 0); 582 } 583 584 /** 585 * Tests saving an empty layout object. 586 */ 587 @Test 588 public void testSaveEmptyLayout() throws ConfigurationException 589 { 590 checkLayoutString(""); 591 } 592 593 /** 594 * Tests the copy constructor. 595 */ 596 @Test 597 public void testInitCopy() 598 { 599 fillLayout(); 600 PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout( 601 config, layout); 602 assertEquals("Wrong number of keys", layout.getKeys().size(), l2 603 .getKeys().size()); 604 for (Iterator<String> it = layout.getKeys().iterator(); it.hasNext();) 605 { 606 Object key = it.next(); 607 assertTrue("Key was not found: " + key, l2.getKeys().contains(key)); 608 } 609 } 610 611 /** 612 * Tests if the copy and the original are independent from each other. 613 */ 614 @Test 615 public void testInitCopyModify() 616 { 617 fillLayout(); 618 PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout( 619 config, layout); 620 assertEquals("Comments are not equal", layout.getComment(TEST_KEY), l2 621 .getComment(TEST_KEY)); 622 layout.setComment(TEST_KEY, "A new comment"); 623 assertEquals("Comment was changed", TEST_COMMENT, l2 624 .getCanonicalComment(TEST_KEY, false)); 625 l2.setBlancLinesBefore(TEST_KEY, l2.getBlancLinesBefore(TEST_KEY) + 1); 626 assertFalse("Blanc lines do not differ", layout 627 .getBlancLinesBefore(TEST_KEY) == l2 628 .getBlancLinesBefore(TEST_KEY)); 629 } 630 631 /** 632 * Tests changing the separator for a property. 633 */ 634 @Test 635 public void testSetSeparator() throws ConfigurationException 636 { 637 config.addProperty(TEST_KEY, TEST_VALUE); 638 layout.setSeparator(TEST_KEY, ":"); 639 checkLayoutString(TEST_KEY + ":" + TEST_VALUE + CR); 640 } 641 642 /** 643 * Tests setting the global separator. This separator should override the 644 * separators for all properties. 645 */ 646 @Test 647 public void testSetGlobalSeparator() throws ConfigurationException 648 { 649 final String sep = "="; 650 config.addProperty(TEST_KEY, TEST_VALUE); 651 config.addProperty("key2", "value2"); 652 layout.setSeparator(TEST_KEY, " : "); 653 layout.setGlobalSeparator(sep); 654 checkLayoutString(TEST_KEY + sep + TEST_VALUE + CR + "key2" + sep 655 + "value2" + CR); 656 } 657 658 /** 659 * Tests setting the line separator. 660 */ 661 @Test 662 public void testSetLineSeparator() throws ConfigurationException 663 { 664 final String lf = CR + CR; 665 config.addProperty(TEST_KEY, TEST_VALUE); 666 layout.setBlancLinesBefore(TEST_KEY, 2); 667 layout.setComment(TEST_KEY, TEST_COMMENT); 668 layout.setHeaderComment("Header comment"); 669 layout.setLineSeparator(lf); 670 checkLayoutString("# Header comment" + lf + lf + lf + lf + "# " 671 + TEST_COMMENT + lf + TEST_KEY + " = " + TEST_VALUE + lf); 672 } 673 674 /** 675 * Tests whether the line separator is also taken into account within 676 * comments. 677 */ 678 @Test 679 public void testSetLineSeparatorInComments() throws ConfigurationException 680 { 681 final String lf = "<-\n"; 682 config.addProperty(TEST_KEY, TEST_VALUE); 683 layout.setComment(TEST_KEY, TEST_COMMENT + "\nMore comment"); 684 layout.setHeaderComment("Header\ncomment"); 685 layout.setLineSeparator(lf); 686 checkLayoutString("# Header" + lf + "# comment" + lf + lf + "# " 687 + TEST_COMMENT + lf + "# More comment" + lf + TEST_KEY + " = " 688 + TEST_VALUE + lf); 689 } 690 691 /** 692 * Helper method for filling the layout object with some properties. 693 */ 694 private void fillLayout() 695 { 696 builder.addComment("A header comment"); 697 builder.addComment(null); 698 builder.addProperty("prop", "value"); 699 builder.addComment(TEST_COMMENT); 700 builder.addProperty(TEST_KEY, TEST_VALUE); 701 builder.addProperty("anotherProp", "anotherValue"); 702 try 703 { 704 layout.load(builder.getReader()); 705 } 706 catch (ConfigurationException cex) 707 { 708 // should not happen 709 fail("Exception was thrown: " + cex); 710 } 711 } 712 713 /** 714 * Writes the layout's data into a string. 715 * 716 * @return the layout file's content as string 717 * @throws ConfigurationException if an error occurs 718 */ 719 private String getLayoutString() throws ConfigurationException 720 { 721 StringWriter out = new StringWriter(); 722 layout.save(out); 723 return out.toString(); 724 } 725 726 /** 727 * Checks if the layout's output is correct. 728 * 729 * @param expected the expected result 730 * @throws ConfigurationException if an error occurs 731 */ 732 private void checkLayoutString(String expected) 733 throws ConfigurationException 734 { 735 assertEquals("Wrong layout file content", expected, getLayoutString()); 736 } 737 738 /** 739 * A helper class used for constructing test properties files. 740 */ 741 static class PropertiesBuilder 742 { 743 /** A buffer for storing the data. */ 744 private StringBuilder buf = new StringBuilder(); 745 746 /** A counter for varying the comment character. */ 747 private int commentCounter; 748 749 /** 750 * Adds a property to the simulated file. 751 * 752 * @param key the property key 753 * @param value the value 754 */ 755 public void addProperty(String key, String value) 756 { 757 buf.append(key).append(" = ").append(value).append(CR); 758 } 759 760 /** 761 * Adds a comment line. 762 * 763 * @param s the comment (can be <b>null</b>, then a blanc line is 764 * added) 765 */ 766 public void addComment(String s) 767 { 768 if (s != null) 769 { 770 if (commentCounter % 2 == 0) 771 { 772 buf.append("# "); 773 } 774 else 775 { 776 buf.append("! "); 777 } 778 buf.append(s); 779 commentCounter++; 780 } 781 buf.append(CR); 782 } 783 784 /** 785 * Returns a reader for the simulated properties. 786 * 787 * @return a reader 788 */ 789 public Reader getReader() 790 { 791 return new StringReader(buf.toString()); 792 } 793 794 /** 795 * Returns a string representation of the buffer's content. 796 * 797 * @return the buffer as string 798 */ 799 @Override 800 public String toString() 801 { 802 return buf.toString(); 803 } 804 } 805 806 /** 807 * A mock properties configuration implementation that is used to check 808 * whether some expected methods are called. 809 */ 810 static class LayoutTestConfiguration extends PropertiesConfiguration 811 { 812 /** Stores a builder object. */ 813 public PropertiesBuilder builder; 814 815 /** 816 * Simulates the propertyLoaded() callback. If a builder was set, a 817 * load() call on the layout is invoked. 818 */ 819 @Override 820 boolean propertyLoaded(String key, String value) 821 throws ConfigurationException 822 { 823 if (builder == null) 824 { 825 return super.propertyLoaded(key, value); 826 } 827 else 828 { 829 if (PropertiesConfiguration.getInclude().equals(key)) 830 { 831 getLayout().load(builder.getReader()); 832 return false; 833 } 834 else 835 { 836 return true; 837 } 838 } 839 } 840 } 841 }