    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.util.HashSet;
    20  import java.util.List;
    21  import java.util.NoSuchElementException;
    22  import java.util.Set;
    23
    24  import org.apache.commons.collections.CollectionUtils;
    25  import org.apache.commons.configuration.tree.ConfigurationNode;
    26  import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
    27
    28  import junit.framework.TestCase;
    29
    30  /***
    31   * Test case for SubnodeConfiguration.
    32   *
    33   * @author Oliver Heger
    34   * @version $Id: TestSubnodeConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
    35   */
    36  public class TestSubnodeConfiguration extends TestCase
    37  {
    38      /*** An array with names of tables (test data). */
    39      private static final String[] TABLE_NAMES =
    40      { "documents", "users" };
    41
    42      /*** An array with the fields of the test tables (test data). */
    43      private static final String[][] TABLE_FIELDS =
    44      {
    45      { "docid", "docname", "author", "dateOfCreation", "version", "size" },
    46      { "userid", "uname", "firstName", "lastName" } };
    47
    48      /*** The parent configuration. */
    49      HierarchicalConfiguration parent;
    50
    51      /*** The subnode configuration to be tested. */
    52      SubnodeConfiguration config;
    53
    54      /*** Stores the root node of the subnode config. */
    55      ConfigurationNode subnode;
    56
    57      /*** Stores a counter for the created nodes. */
    58      int nodeCounter;
    59
    60      protected void setUp() throws Exception
    61      {
    62          super.setUp();
    63          parent = setUpParentConfig();
    64          nodeCounter = 0;
    65      }
    66
    67      /***
    68       * Tests creation of a subnode config.
    69       */
    70      public void testInitSubNodeConfig()
    71      {
    72          setUpSubnodeConfig();
    73          assertSame("Wrong root node in subnode", getSubnodeRoot(parent), config
    74                  .getRoot());
    75          assertSame("Wrong parent config", parent, config.getParent());
    76      }
    77
    78      /***
    79       * Tests constructing a subnode configuration with a null parent. This
    80       * should cause an exception.
    81       */
    82      public void testInitSubNodeConfigWithNullParent()
    83      {
    84          try
    85          {
    86              config = new SubnodeConfiguration(null, getSubnodeRoot(parent));
    87              fail("Could set a null parent config!");
    88          }
    89          catch (IllegalArgumentException iex)
    90          {
    91              // ok
    92          }
    93      }
    94
    95      /***
    96       * Tests constructing a subnode configuration with a null root node. This
    97       * should cause an exception.
    98       */
    99      public void testInitSubNodeConfigWithNullNode()
    100     {
    101         try
    102         {
    103             config = new SubnodeConfiguration(parent, null);
    104             fail("Could set a null root node!");
    105         }
    106         catch (IllegalArgumentException iex)
    107         {
    108             // ok
    109         }
    110     }
    111
    112     /***
    113      * Tests if properties of the sub node can be accessed.
    114      */
    115     public void testGetProperties()
    116     {
    117         setUpSubnodeConfig();
    118         assertEquals("Wrong table name", TABLE_NAMES[0], config
    119                 .getString("name"));
    120         List fields = config.getList("fields.field.name");
    121         assertEquals("Wrong number of fields", TABLE_FIELDS[0].length, fields
    122                 .size());
    123         for (int i = 0; i < TABLE_FIELDS[0].length; i++)
    124         {
    125             assertEquals("Wrong field at position " + i, TABLE_FIELDS[0][i],
    126                     fields.get(i));
    127         }
    128     }
    129
    130     /***
    131      * Tests setting of properties in both the parent and the subnode
    132      * configuration and whether the changes are visible to each other.
    133      */
    134     public void testSetProperty()
    135     {
    136         setUpSubnodeConfig();
    137         config.setProperty(null, "testTable");
    138         config.setProperty("name", TABLE_NAMES[0] + "_tested");
    139         assertEquals("Root value was not set", "testTable", parent
    140                 .getString("tables.table(0)"));
    141         assertEquals("Table name was not changed", TABLE_NAMES[0] + "_tested",
    142                 parent.getString("tables.table(0).name"));
    143
    144         parent.setProperty("tables.table(0).fields.field(1).name", "testField");
    145         assertEquals("Field name was not changed", "testField", config
    146                 .getString("fields.field(1).name"));
    147     }
    148
    149     /***
    150      * Tests adding of properties.
    151      */
    152     public void testAddProperty()
    153     {
    154         setUpSubnodeConfig();
    155         config.addProperty("[@table-type]", "test");
    156         assertEquals("parent.createNode() was not called", 1, nodeCounter);
    157         assertEquals("Attribute not set", "test", parent
    158                 .getString("tables.table(0)[@table-type]"));
    159
    160         parent.addProperty("tables.table(0).fields.field(-1).name", "newField");
    161         List fields = config.getList("fields.field.name");
    162         assertEquals("New field was not added", TABLE_FIELDS[0].length + 1,
    163                 fields.size());
    164         assertEquals("Wrong last field", "newField", fields
    165                 .get(fields.size() - 1));
    166     }
    167
    168     /***
    169      * Tests listing the defined keys.
    170      */
    171     public void testGetKeys()
    172     {
    173         setUpSubnodeConfig();
    174         Set keys = new HashSet();
    175         CollectionUtils.addAll(keys, config.getKeys());
    176         assertEquals("Incorrect number of keys", 2, keys.size());
    177         assertTrue("Key 1 not contained", keys.contains("name"));
    178         assertTrue("Key 2 not contained", keys.contains("fields.field.name"));
    179     }
    180
    181     /***
    182      * Tests setting the exception on missing flag. The subnode config obtains
    183      * this flag from its parent.
    184      */
    185     public void testSetThrowExceptionOnMissing()
    186     {
    187         parent.setThrowExceptionOnMissing(true);
    188         setUpSubnodeConfig();
    189         assertTrue("Exception flag not fetchted from parent", config
    190                 .isThrowExceptionOnMissing());
    191         try
    192         {
    193             config.getString("non existing key");
    194             fail("Could fetch non existing key!");
    195         }
    196         catch (NoSuchElementException nex)
    197         {
    198             // ok
    199         }
    200
    201         config.setThrowExceptionOnMissing(false);
    202         assertTrue("Exception flag reset on parent", parent
    203                 .isThrowExceptionOnMissing());
    204     }
    205
    206     /***
    207      * Tests handling of the delimiter parsing disabled flag. This is shared
    208      * with the parent, too.
    209      */
    210     public void testSetDelimiterParsingDisabled()
    211     {
    212         parent.setDelimiterParsingDisabled(true);
    213         setUpSubnodeConfig();
    214         parent.setDelimiterParsingDisabled(false);
    215         assertTrue("Delimiter parsing flag was not received from parent",
    216                 config.isDelimiterParsingDisabled());
    217         config.addProperty("newProp", "test1,test2,test3");
    218         assertEquals("New property was splitted", "test1,test2,test3", parent
    219                 .getString("tables.table(0).newProp"));
    220         parent.setDelimiterParsingDisabled(true);
    221         config.setDelimiterParsingDisabled(false);
    222         assertTrue("Delimiter parsing flag was reset on parent", parent
    223                 .isDelimiterParsingDisabled());
    224     }
    225
    226     /***
    227      * Tests manipulating the list delimiter. This piece of data is derived from
    228      * the parent.
    229      */
    230     public void testSetListDelimiter()
    231     {
    232         parent.setListDelimiter('/');
    233         setUpSubnodeConfig();
    234         parent.setListDelimiter(';');
    235         assertEquals("List delimiter not obtained from parent", '/', config
    236                 .getListDelimiter());
    237         config.addProperty("newProp", "test1,test2/test3");
    238         assertEquals("List was incorrectly splitted", "test1,test2", parent
    239                 .getString("tables.table(0).newProp"));
    240         config.setListDelimiter(',');
    241         assertEquals("List delimiter changed on parent", ';', parent
    242                 .getListDelimiter());
    243     }
    244
    245     /***
    246      * Tests changing the expression engine.
    247      */
    248     public void testSetExpressionEngine()
    249     {
    250         parent.setExpressionEngine(new XPathExpressionEngine());
    251         setUpSubnodeConfig();
    252         assertEquals("Wrong field name", TABLE_FIELDS[0][1], config
    253                 .getString("fields/field[2]/name"));
    254         Set keys = new HashSet();
    255         CollectionUtils.addAll(keys, config.getKeys());
    256         assertEquals("Wrong number of keys", 2, keys.size());
    257         assertTrue("Key 1 not contained", keys.contains("name"));
    258         assertTrue("Key 2 not contained", keys.contains("fields/field/name"));
    259         config.setExpressionEngine(null);
    260         assertTrue("Expression engine reset on parent", parent
    261                 .getExpressionEngine() instanceof XPathExpressionEngine);
    262     }
    263
    264     /***
    265      * Tests the configurationAt() method.
    266      */
    267     public void testConfiguarationAt()
    268     {
    269         setUpSubnodeConfig();
    270         SubnodeConfiguration sub2 = (SubnodeConfiguration) config
    271                 .configurationAt("fields.field(1)");
    272         assertEquals("Wrong value of property", TABLE_FIELDS[0][1], sub2
    273                 .getString("name"));
    274         assertEquals("Wrong parent", config.getParent(), sub2.getParent());
    275     }
    276
    277     /***
    278      * Tests interpolation features. The subnode config should use its parent
    279      * for interpolation.
    280      */
    281     public void testInterpolation()
    282     {
    283         parent.addProperty("tablespaces.tablespace.name", "default");
    284         parent.addProperty("tablespaces.tablespace(-1).name", "test");
    285         parent.addProperty("tables.table(0).tablespace",
    286                 "${tablespaces.tablespace(0).name}");
    287         assertEquals("Wrong interpolated tablespace", "default", parent
    288                 .getString("tables.table(0).tablespace"));
    289
    290         setUpSubnodeConfig();
    291         assertEquals("Wrong interpolated tablespace in subnode", "default",
    292                 config.getString("tablespace"));
    293     }
    294
    295     /***
    296      * Initializes the parent configuration. This method creates the typical
    297      * structure of tables and fields nodes.
    298      *
    299      * @return the parent configuration
    300      */
    301     protected HierarchicalConfiguration setUpParentConfig()
    302     {
    303         HierarchicalConfiguration conf = new HierarchicalConfiguration()
    304         {
    305             // Provide a special implementation of createNode() to check
    306             // if it is called by the subnode config
    307             protected Node createNode(String name)
    308             {
    309                 nodeCounter++;
    310                 return super.createNode(name);
    311             }
    312         };
    313         for (int i = 0; i < TABLE_NAMES.length; i++)
    314         {
    315             conf.addProperty("tables.table(-1).name", TABLE_NAMES[i]);
    316             for (int j = 0; j < TABLE_FIELDS[i].length; j++)
    317             {
    318                 conf.addProperty("tables.table.fields.field(-1).name",
    319                         TABLE_FIELDS[i][j]);
    320             }
    321         }
    322         return conf;
    323     }
    324
    325     /***
    326      * Returns the root node for the subnode config. This method returns the
    327      * first table node.
    328      *
    329      * @param conf the parent config
    330      * @return the root node for the subnode config
    331      */
    332     protected ConfigurationNode getSubnodeRoot(HierarchicalConfiguration conf)
    333     {
    334         ConfigurationNode root = conf.getRoot();
    335         return root.getChild(0).getChild(0);
    336     }
    337
    338     /***
    339      * Performs a standard initialization of the subnode config to test.
    340      */
    341     protected void setUpSubnodeConfig()
    342     {
    343         config = new SubnodeConfiguration(parent, getSubnodeRoot(parent));
    344     }
    345 }