    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.configuration;
    18
    19  import java.io.Reader;
    20  import java.io.StringReader;
    21  import java.io.StringWriter;
    22  import java.util.Iterator;
    23
    24  import org.apache.commons.configuration.event.ConfigurationEvent;
    25
    26  import junit.framework.TestCase;
    27
    28  /***
    29   * Test class for PropertiesConfigurationLayout.
    30   *
    31   * @author <a
    32   * href="http://commons.apache.org/configuration/team-list.html">Commons
    33   * Configuration team</a>
    34   * @version $Id: TestPropertiesConfigurationLayout.java 561230 2007-07-31 04:17:09Z rahul $
    35   */
    36  public class TestPropertiesConfigurationLayout extends TestCase
    37  {
    38      /*** Constant for the line break character. */
    39      static final String CR = System.getProperty("line.separator");
    40
    41      /*** Constant for a test property key. */
    42      static final String TEST_KEY = "myProperty";
    43
    44      /*** Constant for a test comment. */
    45      static final String TEST_COMMENT = "A comment for my test property";
    46
    47      /*** Constant for a test property value. */
    48      static final String TEST_VALUE = "myPropertyValue";
    49
    50      /*** The layout object under test. */
    51      PropertiesConfigurationLayout layout;
    52
    53      /*** The associated configuration object. */
    54      LayoutTestConfiguration config;
    55
    56      /*** A properties builder that can be used for testing. */
    57      PropertiesBuilder builder;
    58
    59      protected void setUp() throws Exception
    60      {
    61          super.setUp();
    62          config = new LayoutTestConfiguration();
    63          layout = new PropertiesConfigurationLayout(config);
    64          config.setLayout(layout);
    65          builder = new PropertiesBuilder();
    66      }
    67
    68      /***
    69       * Tests a newly created instance.
    70       */
    71      public void testInit()
    72      {
    73          assertTrue("Object contains keys", layout.getKeys().isEmpty());
    74          assertNull("Header comment not null", layout.getHeaderComment());
    75          Iterator it = config.getConfigurationListeners().iterator();
    76          assertTrue("No event listener registered", it.hasNext());
    77          assertSame("Layout not registered as event listener", layout, it.next());
    78          assertFalse("Multiple event listeners registered", it.hasNext());
    79          assertSame("Configuration not stored", config, layout
    80                  .getConfiguration());
    81          assertFalse("Force single line flag set", layout.isForceSingleLine());
    82      }
    83
    84      /***
    85       * Tests creating a layout object with a null configuration. This should
    86       * cause an exception.
    87       */
    88      public void testInitNull()
    89      {
    90          try
    91          {
    92              new PropertiesConfigurationLayout(null);
    93              fail("Could create instance with null config!");
    94          }
    95          catch (IllegalArgumentException iex)
    96          {
    97              // ok
    98          }
    99      }
    100
    101     /***
    102      * Tests reading a simple properties file.
    103      */
    104     public void testReadSimple() throws ConfigurationException
    105     {
    106         builder.addComment(TEST_COMMENT);
    107         builder.addProperty(TEST_KEY, TEST_VALUE);
    108         layout.load(builder.getReader());
    109         assertNull("A header comment was found", layout.getHeaderComment());
    110         assertEquals("Wrong number of properties", 1, layout.getKeys().size());
    111         assertTrue("Property not found", layout.getKeys().contains(TEST_KEY));
    112         assertEquals("Comment not found", TEST_COMMENT, layout
    113                 .getCanonicalComment(TEST_KEY, false));
    114         assertEquals("Wrong number of blanc lines", 0, layout
    115                 .getBlancLinesBefore(TEST_KEY));
    116         assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY));
    117         assertEquals("Property not stored in config", TEST_VALUE, config
    118                 .getString(TEST_KEY));
    119     }
    120
    121     /***
    122      * Tests whether blanc lines before a property are correctly detected.
    123      */
    124     public void testBlancLines() throws ConfigurationException
    125     {
    126         builder.addProperty("prop", "value");
    127         builder.addComment(null);
    128         builder.addComment(null);
    129         builder.addComment(TEST_COMMENT);
    130         builder.addComment(null);
    131         builder.addProperty(TEST_KEY, TEST_VALUE);
    132         layout.load(builder.getReader());
    133         assertEquals("Wrong number of blanc lines", 2, layout
    134                 .getBlancLinesBefore(TEST_KEY));
    135         assertEquals("Wrong comment", TEST_COMMENT + CR, layout
    136                 .getCanonicalComment(TEST_KEY, false));
    137         assertEquals("Wrong property value", TEST_VALUE, config
    138                 .getString(TEST_KEY));
    139     }
    140
    141     /***
    142      * Tests the single line flag for a simple property definition.
    143      */
    144     public void testIsSingleLine() throws ConfigurationException
    145     {
    146         builder.addProperty(TEST_KEY, TEST_VALUE + "," + TEST_VALUE + "2");
    147         layout.load(builder.getReader());
    148         assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY));
    149         assertEquals("Wrong number of values", 2, config.getList(TEST_KEY)
    150                 .size());
    151     }
    152
    153     /***
    154      * Tests the single line flag if there are multiple property definitions.
    155      */
    156     public void testIsSingleLineMulti() throws ConfigurationException
    157     {
    158         builder.addProperty(TEST_KEY, TEST_VALUE);
    159         builder.addProperty("anotherProp", "a value");
    160         builder.addProperty(TEST_KEY, TEST_VALUE + "2");
    161         layout.load(builder.getReader());
    162         assertFalse("Wrong single line flag", layout.isSingleLine(TEST_KEY));
    163         assertEquals("Wrong number of values", 2, config.getList(TEST_KEY)
    164                 .size());
    165     }
    166
    167     /***
    168      * Tests whether comments are combined for multiple occurrences.
    169      */
    170     public void testCombineComments() throws ConfigurationException
    171     {
    172         builder.addComment(TEST_COMMENT);
    173         builder.addProperty(TEST_KEY, TEST_VALUE);
    174         builder.addComment(null);
    175         builder.addComment(TEST_COMMENT);
    176         builder.addProperty(TEST_KEY, TEST_VALUE + "2");
    177         layout.load(builder.getReader());
    178         assertEquals("Wrong combined comment",
    179                 TEST_COMMENT + CR + TEST_COMMENT, layout.getCanonicalComment(
    180                         TEST_KEY, false));
    181         assertEquals("Wrong combined blanc numbers", 0, layout
    182                 .getBlancLinesBefore(TEST_KEY));
    183     }
    184
    185     /***
    186      * Tests if a header comment is detected.
    187      */
    188     public void testHeaderComment() throws ConfigurationException
    189     {
    190         builder.addComment(TEST_COMMENT);
    191         builder.addComment(null);
    192         builder.addProperty(TEST_KEY, TEST_VALUE);
    193         layout.load(builder.getReader());
    194         assertEquals("Wrong header comment", TEST_COMMENT, layout
    195                 .getCanonicalHeaderComment(false));
    196         assertNull("Wrong comment for property", layout.getCanonicalComment(
    197                 TEST_KEY, false));
    198     }
    199
    200     /***
    201      * Tests if a header comment containing blanc lines is correctly detected.
    202      */
    203     public void testHeaderCommentWithBlancs() throws ConfigurationException
    204     {
    205         builder.addComment(TEST_COMMENT);
    206         builder.addComment(null);
    207         builder.addComment(TEST_COMMENT);
    208         builder.addComment(null);
    209         builder.addProperty(TEST_KEY, TEST_VALUE);
    210         layout.load(builder.getReader());
    211         assertEquals("Wrong header comment", TEST_COMMENT + CR + CR
    212                 + TEST_COMMENT, layout.getCanonicalHeaderComment(false));
    213         assertNull("Wrong comment for property", layout.getComment(TEST_KEY));
    214     }
    215
    216     /***
    217      * Tests if a header comment is correctly detected when it contains blanc
    218      * lines and the first property has a comment, too.
    219      */
    220     public void testHeaderCommentWithBlancsAndPropComment()
    221             throws ConfigurationException
    222     {
    223         builder.addComment(TEST_COMMENT);
    224         builder.addComment(null);
    225         builder.addComment(TEST_COMMENT);
    226         builder.addComment(null);
    227         builder.addComment(TEST_COMMENT);
    228         builder.addProperty(TEST_KEY, TEST_VALUE);
    229         layout.load(builder.getReader());
    230         assertEquals("Wrong header comment", TEST_COMMENT + CR + CR
    231                 + TEST_COMMENT, layout.getCanonicalHeaderComment(false));
    232         assertEquals("Wrong comment for property", TEST_COMMENT, layout
    233                 .getCanonicalComment(TEST_KEY, false));
    234     }
    235
    236     /***
    237      * Tests fetching a canonical header comment when no comment is set.
    238      */
    239     public void testHeaderCommentNull()
    240     {
    241         assertNull("No null comment with comment chars", layout
    242                 .getCanonicalHeaderComment(true));
    243         assertNull("No null comment without comment chars", layout
    244                 .getCanonicalHeaderComment(false));
    245     }
    246
    247     /***
    248      * Tests if a property add event is correctly processed.
    249      */
    250     public void testEventAdd()
    251     {
    252         ConfigurationEvent event = new ConfigurationEvent(this,
    253                 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE,
    254                 false);
    255         layout.configurationChanged(event);
    256         assertTrue("Property not stored", layout.getKeys().contains(TEST_KEY));
    257         assertEquals("Blanc lines before new property", 0, layout
    258                 .getBlancLinesBefore(TEST_KEY));
    259         assertTrue("No single line property", layout.isSingleLine(TEST_KEY));
    260     }
    261
    262     /***
    263      * Tests adding a property multiple time through an event. The property
    264      * should then be a multi-line property.
    265      */
    266     public void testEventAddMultiple()
    267     {
    268         ConfigurationEvent event = new ConfigurationEvent(this,
    269                 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE,
    270                 false);
    271         layout.configurationChanged(event);
    272         layout.configurationChanged(event);
    273         assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY));
    274     }
    275
    276     /***
    277      * Tests if an add event is correctly processed if the affected property is
    278      * already stored in the layout object.
    279      */
    280     public void testEventAddExisting() throws ConfigurationException
    281     {
    282         builder.addComment(TEST_COMMENT);
    283         builder.addProperty(TEST_KEY, TEST_VALUE);
    284         layout.load(builder.getReader());
    285         ConfigurationEvent event = new ConfigurationEvent(this,
    286                 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE,
    287                 false);
    288         layout.configurationChanged(event);
    289         assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY));
    290         assertEquals("Comment was modified", TEST_COMMENT, layout
    291                 .getCanonicalComment(TEST_KEY, false));
    292     }
    293
    294     /***
    295      * Tests if a set property event for a non existing property is correctly
    296      * handled.
    297      */
    298     public void testEventSetNonExisting()
    299     {
    300         ConfigurationEvent event = new ConfigurationEvent(this,
    301                 AbstractConfiguration.EVENT_SET_PROPERTY, TEST_KEY, TEST_VALUE,
    302                 false);
    303         layout.configurationChanged(event);
    304         assertTrue("New property was not found", layout.getKeys().contains(
    305                 TEST_KEY));
    306     }
    307
    308     /***
    309      * Tests if a property delete event is correctly processed.
    310      */
    311     public void testEventDelete()
    312     {
    313         ConfigurationEvent event = new ConfigurationEvent(this,
    314                 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE,
    315                 false);
    316         layout.configurationChanged(event);
    317         event = new ConfigurationEvent(this,
    318                 AbstractConfiguration.EVENT_CLEAR_PROPERTY, TEST_KEY, null,
    319                 false);
    320         layout.configurationChanged(event);
    321         assertFalse("Property still existing", layout.getKeys().contains(
    322                 TEST_KEY));
    323     }
    324
    325     /***
    326      * Tests if a clear event is correctly processed.
    327      */
    328     public void testEventClearConfig() throws ConfigurationException
    329     {
    330         fillLayout();
    331         ConfigurationEvent event = new ConfigurationEvent(this,
    332                 AbstractConfiguration.EVENT_CLEAR, null, null, false);
    333         layout.configurationChanged(event);
    334         assertTrue("Keys not empty", layout.getKeys().isEmpty());
    335         assertNull("Header comment was not reset", layout.getHeaderComment());
    336     }
    337
    338     /***
    339      * Tests if a before update event is correctly ignored.
    340      */
    341     public void testEventAddBefore()
    342     {
    343         ConfigurationEvent event = new ConfigurationEvent(this,
    344                 AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE,
    345                 true);
    346         layout.configurationChanged(event);
    347         assertFalse("Property already stored", layout.getKeys().contains(
    348                 TEST_KEY));
    349     }
    350
    351     /***
    352      * Tests if a reload update is correctly processed.
    353      */
    354     public void testEventReload()
    355     {
    356         fillLayout();
    357         ConfigurationEvent event = new ConfigurationEvent(this,
    358                 AbstractFileConfiguration.EVENT_RELOAD, null, null, true);
    359         layout.configurationChanged(event);
    360         assertTrue("Keys not empty", layout.getKeys().isEmpty());
    361         assertNull("Header comment was not reset", layout.getHeaderComment());
    362     }
    363
    364     /***
    365      * Tests the event after a reload has been performed. This should be
    366      * ignored.
    367      */
    368     public void testEventReloadAfter()
    369     {
    370         fillLayout();
    371         ConfigurationEvent event = new ConfigurationEvent(this,
    372                 AbstractFileConfiguration.EVENT_RELOAD, null, null, false);
    373         layout.configurationChanged(event);
    374         assertFalse("Keys are empty", layout.getKeys().isEmpty());
    375         assertNotNull("Header comment was reset", layout.getHeaderComment());
    376     }
    377
    378     /***
    379      * Tests a recursive load call.
    380      */
    381     public void testRecursiveLoadCall() throws ConfigurationException
    382     {
    383         PropertiesBuilder b = new PropertiesBuilder();
    384         b.addComment("A nested header comment.");
    385         b.addComment("With multiple lines");
    386         b.addComment(null);
    387         b.addComment("Second comment");
    388         b.addProperty(TEST_KEY, TEST_VALUE);
    389         b.addProperty(TEST_KEY + "2", TEST_VALUE + "2");
    390         config.builder = b;
    391
    392         builder.addComment("Header comment");
    393         builder.addComment(null);
    394         builder.addComment(TEST_COMMENT);
    395         builder.addProperty(TEST_KEY, TEST_VALUE);
    396         builder.addComment("Include file");
    397         builder.addProperty(PropertiesConfiguration.getInclude(), "test");
    398
    399         layout.load(builder.getReader());
    400
    401         assertEquals("Wrong header comment", "Header comment", layout
    402                 .getCanonicalHeaderComment(false));
    403         assertFalse("Include property was stored", layout.getKeys().contains(
    404                 PropertiesConfiguration.getInclude()));
    405         assertEquals("Wrong comment for property", TEST_COMMENT + CR
    406                 + "A nested header comment." + CR + "With multiple lines" + CR
    407                 + CR + "Second comment", layout.getCanonicalComment(TEST_KEY,
    408                 false));
    409     }
    410
    411     /***
    412      * Tests whether the output of the layout object is identical to the source
    413      * file (at least for simple properties files).
    414      */
    415     public void testReadAndWrite() throws ConfigurationException
    416     {
    417         builder.addComment("This is my test properties file,");
    418         builder.addComment("which contains a header comment.");
    419         builder.addComment(null);
    420         builder.addComment(TEST_COMMENT);
    421         builder.addProperty(TEST_KEY, TEST_COMMENT);
    422         builder.addComment(null);
    423         builder.addComment(null);
    424         builder.addComment("Another comment");
    425         builder.addProperty("property", "and a value");
    426         layout.load(builder.getReader());
    427         checkLayoutString(builder.toString());
    428     }
    429
    430     /***
    431      * Tests if the content of the layout object is correctly written.
    432      */
    433     public void testSave() throws ConfigurationException
    434     {
    435         config.addProperty(TEST_KEY, TEST_VALUE);
    436         layout.setComment(TEST_KEY, TEST_COMMENT);
    437         config.addProperty(TEST_KEY, TEST_VALUE + "2");
    438         config.addProperty("AnotherProperty", "AnotherValue");
    439         config.addProperty("AnotherProperty", "3rdValue");
    440         layout.setComment("AnotherProperty", "AnotherComment");
    441         layout.setBlancLinesBefore("AnotherProperty", 2);
    442         layout.setSingleLine("AnotherProperty", true);
    443         layout.setHeaderComment("A header comment" + CR + "for my properties");
    444         checkLayoutString("# A header comment" + CR + "# for my properties"
    445                 + CR + CR + "# " + TEST_COMMENT + CR + TEST_KEY + " = "
    446                 + TEST_VALUE + CR + TEST_KEY + " = " + TEST_VALUE + "2" + CR
    447                 + CR + CR + "# AnotherComment" + CR
    448                 + "AnotherProperty = AnotherValue,3rdValue" + CR);
    449     }
    450
    451     /***
    452      * Tests the force single line flag.
    453      */
    454     public void testSaveForceSingleLine() throws ConfigurationException
    455     {
    456         config.setListDelimiter(';');
    457         config.addProperty(TEST_KEY, TEST_VALUE);
    458         config.addProperty(TEST_KEY, TEST_VALUE + "2");
    459         config.addProperty("AnotherProperty", "value1;value2;value3");
    460         layout.setComment(TEST_KEY, TEST_COMMENT);
    461         layout.setForceSingleLine(true);
    462         checkLayoutString("# " + TEST_COMMENT + CR + TEST_KEY + " = "
    463                 + TEST_VALUE + ';' + TEST_VALUE + "2" + CR
    464                 + "AnotherProperty = value1;value2;value3" + CR);
    465     }
    466
    467     /***
    468      * Tests the trimComment method.
    469      */
    470     public void testTrimComment()
    471     {
    472         assertEquals("Wrong trimmed comment", "This is a comment" + CR
    473                 + "that spans multiple" + CR + "lines in a" + CR
    474                 + " complex way.", PropertiesConfigurationLayout.trimComment(
    475                 "   # This is a comment" + CR + "that spans multiple" + CR
    476                         + "!lines in a" + CR + " complex way.", false));
    477     }
    478
    479     /***
    480      * Tests trimming a comment with trailing CRs.
    481      */
    482     public void testTrimCommentTrainlingCR()
    483     {
    484         assertEquals("Wrong trimmed comment", "Comment with" + CR
    485                 + "trailing CR" + CR, PropertiesConfigurationLayout
    486                 .trimComment("Comment with" + CR + "! trailing CR" + CR, false));
    487     }
    488
    489     /***
    490      * Tests enforcing comment characters in a comment.
    491      */
    492     public void testTrimCommentFalse()
    493     {
    494         assertEquals("Wrong trimmed comment", "# Comment with" + CR
    495                 + " ! some mixed " + CR + "#comment" + CR + "# lines",
    496                 PropertiesConfigurationLayout.trimComment("Comment with" + CR
    497                         + " ! some mixed " + CR + "#comment" + CR + "lines",
    498                         true));
    499     }
    500
    501     /***
    502      * Tests accessing data for a property, which is not stored.
    503      */
    504     public void testGetNonExistingLayouData()
    505     {
    506         assertNull("A comment was found", layout.getComment("unknown"));
    507         assertTrue("A multi-line property", layout.isSingleLine("unknown"));
    508         assertEquals("Leading blanc lines", 0, layout
    509                 .getBlancLinesBefore("unknown"));
    510     }
    511
    512     /***
    513      * Tests accessing a property with a null key. This should throw an
    514      * exception.
    515      */
    516     public void testGetNullLayouttData()
    517     {
    518         try
    519         {
    520             layout.setComment(null, TEST_COMMENT);
    521             fail("Could access null property key!");
    522         }
    523         catch (IllegalArgumentException iex)
    524         {
    525             // ok
    526         }
    527     }
    528
    529     /***
    530      * Tests resetting a comment.
    531      */
    532     public void testSetNullComment()
    533     {
    534         fillLayout();
    535         layout.setComment(TEST_KEY, null);
    536         assertNull("Comment was not reset", layout.getComment(TEST_KEY));
    537     }
    538
    539     /***
    540      * Tests saving when a comment for a non existing property is contained in
    541      * the layout object. This comment should be ignored.
    542      */
    543     public void testSaveCommentForUnexistingProperty()
    544             throws ConfigurationException
    545     {
    546         fillLayout();
    547         layout.setComment("NonExistingKey", "NonExistingComment");
    548         String output = getLayoutString();
    549         assertTrue("Non existing key was found", output
    550                 .indexOf("NonExistingKey") < 0);
    551         assertTrue("Non existing comment was found", output
    552                 .indexOf("NonExistingComment") < 0);
    553     }
    554
    555     /***
    556      * Tests saving an empty layout object.
    557      */
    558     public void testSaveEmptyLayout() throws ConfigurationException
    559     {
    560         checkLayoutString("");
    561     }
    562
    563     /***
    564      * Tests the copy constructor.
    565      */
    566     public void testInitCopy()
    567     {
    568         fillLayout();
    569         PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout(
    570                 config, layout);
    571         assertEquals("Wrong number of keys", layout.getKeys().size(), l2
    572                 .getKeys().size());
    573         for (Iterator it = layout.getKeys().iterator(); it.hasNext();)
    574         {
    575             Object key = it.next();
    576             assertTrue("Key was not found: " + key, l2.getKeys().contains(key));
    577         }
    578     }
    579
    580     /***
    581      * Tests if the copy and the original are independend from each other.
    582      */
    583     public void testInitCopyModify()
    584     {
    585         fillLayout();
    586         PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout(
    587                 config, layout);
    588         assertEquals("Comments are not equal", layout.getComment(TEST_KEY), l2
    589                 .getComment(TEST_KEY));
    590         layout.setComment(TEST_KEY, "A new comment");
    591         assertEquals("Comment was changed", TEST_COMMENT, l2
    592                 .getCanonicalComment(TEST_KEY, false));
    593         l2.setBlancLinesBefore(TEST_KEY, l2.getBlancLinesBefore(TEST_KEY) + 1);
    594         assertFalse("Blanc lines do not differ", layout
    595                 .getBlancLinesBefore(TEST_KEY) == l2
    596                 .getBlancLinesBefore(TEST_KEY));
    597     }
    598
    599     /***
    600      * Helper method for filling the layout object with some properties.
    601      */
    602     private void fillLayout()
    603     {
    604         builder.addComment("A header comment");
    605         builder.addComment(null);
    606         builder.addProperty("prop", "value");
    607         builder.addComment(TEST_COMMENT);
    608         builder.addProperty(TEST_KEY, TEST_VALUE);
    609         builder.addProperty("anotherProp", "anotherValue");
    610         try
    611         {
    612             layout.load(builder.getReader());
    613         }
    614         catch (ConfigurationException cex)
    615         {
    616             // should not happen
    617             fail("Exception was thrown: " + cex);
    618         }
    619     }
    620
    621     /***
    622      * Writes the layout's data into a string.
    623      *
    624      * @return the layout file's content as string
    625      * @throws ConfigurationException if an error occurs
    626      */
    627     private String getLayoutString() throws ConfigurationException
    628     {
    629         StringWriter out = new StringWriter();
    630         layout.save(out);
    631         return out.toString();
    632     }
    633
    634     /***
    635      * Checks if the layout's output is correct.
    636      *
    637      * @param expected the expected result
    638      * @throws ConfigurationException if an error occurs
    639      */
    640     private void checkLayoutString(String expected)
    641             throws ConfigurationException
    642     {
    643         assertEquals("Wrong layout file content", expected, getLayoutString());
    644     }
    645
    646     /***
    647      * A helper class used for constructing test properties files.
    648      */
    649     static class PropertiesBuilder
    650     {
    651         /*** A buffer for storing the data. */
    652         private StringBuffer buf = new StringBuffer();
    653
    654         /*** A counter for varying the comment character. */
    655         private int commentCounter;
    656
    657         /***
    658          * Adds a property to the simulated file.
    659          *
    660          * @param key the property key
    661          * @param value the value
    662          */
    663         public void addProperty(String key, String value)
    664         {
    665             buf.append(key).append(" = ").append(value).append(CR);
    666         }
    667
    668         /***
    669          * Adds a comment line.
    670          *
    671          * @param s the comment (can be <b>null</b>, then a blanc line is
    672          * added)
    673          */
    674         public void addComment(String s)
    675         {
    676             if (s != null)
    677             {
    678                 if (commentCounter % 2 == 0)
    679                 {
    680                     buf.append("# ");
    681                 }
    682                 else
    683                 {
    684                     buf.append("! ");
    685                 }
    686                 buf.append(s);
    687             }
    688             buf.append(CR);
    689         }
    690
    691         /***
    692          * Returns a reader for the simulated properties.
    693          *
    694          * @return a reader
    695          */
    696         public Reader getReader()
    697         {
    698             return new StringReader(buf.toString());
    699         }
    700
    701         /***
    702          * Returns a string representation of the buffer's content.
    703          *
    704          * @return the buffer as string
    705          */
    706         public String toString()
    707         {
    708             return buf.toString();
    709         }
    710     }
    711
    712     /***
    713      * A mock properties configuration implementation that is used to check
    714      * whether some expected methods are called.
    715      */
    716     static class LayoutTestConfiguration extends PropertiesConfiguration
    717     {
    718         /*** Stores a builder object. */
    719         public PropertiesBuilder builder;
    720
    721         /***
    722          * Simulates the propertyLoaded() callback. If a builder was set, a
    723          * load() call on the layout is invoked.
    724          */
    725         boolean propertyLoaded(String key, String value)
    726                 throws ConfigurationException
    727         {
    728             if (builder == null)
    729             {
    730                 return super.propertyLoaded(key, value);
    731             }
    732             else
    733             {
    734                 if (PropertiesConfiguration.getInclude().equals(key))
    735                 {
    736                     getLayout().load(builder.getReader());
    737                     return false;
    738                 }
    739                 else
    740                 {
    741                     return true;
    742                 }
    743             }
    744         }
    745     }
    746 }