    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.beanutils;
    18
    19  import java.util.Map;
    20
    21  import org.apache.commons.configuration.HierarchicalConfiguration;
    22  import org.apache.commons.configuration.SubnodeConfiguration;
    23  import org.apache.commons.configuration.tree.ConfigurationNode;
    24
    25  import junit.framework.TestCase;
    26
    27  /***
    28   * Test class for XMLBeanDeclaration.
    29   *
    30   * @since 1.3
    31   * @author Oliver Heger
    32   * @version $Id: TestXMLBeanDeclaration.java 670739 2008-06-23 20:36:37Z oheger $
    33   */
    34  public class TestXMLBeanDeclaration extends TestCase
    35  {
    36      /*** An array with some test properties. */
    37      static final String[] TEST_PROPS =
    38      { "firstName", "lastName", "department", "age", "hobby"};
    39
    40      /*** An array with the values for the test properties. */
    41      static final String[] TEST_VALUES =
    42      { "John", "Smith", "Engineering", "42", "TV"};
    43
    44      /*** An array with the names of nested (complex) properties. */
    45      static final String[] COMPLEX_PROPS =
    46      { "address", "car"};
    47
    48      /*** An array with the names of the classes of the complex properties. */
    49      static final String[] COMPLEX_CLASSES =
    50      { "org.apache.commons.configuration.test.AddressTest",
    51              "org.apache.commons.configuration.test.CarTest"};
    52
    53      /*** An array with the property names of the complex properties. */
    54      static final String[][] COMPLEX_ATTRIBUTES =
    55      {
    56      { "street", "zip", "city", "country"},
    57      { "brand", "color"}};
    58
    59      /*** An array with the values of the complex properties. */
    60      static final String[][] COMPLEX_VALUES =
    61      {
    62      { "Baker Street", "12354", "London", "UK"},
    63      { "Bentley", "silver"}};
    64
    65      /*** Constant for the key with the bean declaration. */
    66      static final String KEY = "myBean";
    67
    68      /*** Constant for the section with the variables.*/
    69      static final String VARS = "variables.";
    70
    71      /*** Stores the object to be tested. */
    72      XMLBeanDeclaration decl;
    73
    74      /***
    75       * Tests creating a declaration from a null node. This should cause an
    76       * exception.
    77       */
    78      public void testInitFromNullNode()
    79      {
    80          try
    81          {
    82              decl = new XMLBeanDeclaration(new HierarchicalConfiguration().configurationAt(null),
    83                      (ConfigurationNode) null);
    84              fail("Could init declaration with null node!");
    85          }
    86          catch (IllegalArgumentException iex)
    87          {
    88              // ok
    89          }
    90      }
    91
    92      /***
    93       * Tests creating a declaration from a null configuration. This should cause
    94       * an exception.
    95       */
    96      public void testInitFromNullConfiguration()
    97      {
    98          try
    99          {
    100             decl = new XMLBeanDeclaration((HierarchicalConfiguration) null);
    101             fail("Could init declaration with null configuration!");
    102         }
    103         catch (IllegalArgumentException iex)
    104         {
    105             // ok
    106         }
    107     }
    108
    109     /***
    110      * Tests creating a declaration from a null configuration with a key. This
    111      * should cause an exception.
    112      */
    113     public void testInitFromNullConfigurationAndKey()
    114     {
    115         try
    116         {
    117             decl = new XMLBeanDeclaration(null, KEY);
    118             fail("Could init declaration with null configuration and key!");
    119         }
    120         catch (IllegalArgumentException iex)
    121         {
    122             // ok
    123         }
    124     }
    125
    126     /***
    127      * Tests creating a declaration from a null configuration with a node. This
    128      * should cause an exception.
    129      */
    130     public void testInitFromNullConfigurationAndNode()
    131     {
    132         try
    133         {
    134             decl = new XMLBeanDeclaration(null, new HierarchicalConfiguration()
    135                     .getRoot());
    136             fail("Could init declaration with null configuration and node!");
    137         }
    138         catch (IllegalArgumentException iex)
    139         {
    140             // ok
    141         }
    142     }
    143
    144     /***
    145      * Tests fetching the bean's class name.
    146      */
    147     public void testGetBeanClassName()
    148     {
    149         HierarchicalConfiguration config = new HierarchicalConfiguration();
    150         config.addProperty(KEY + "[@config-class]", getClass().getName());
    151         decl = new XMLBeanDeclaration(config, KEY);
    152         assertEquals("Wrong class name", getClass().getName(), decl
    153                 .getBeanClassName());
    154     }
    155
    156     /***
    157      * Tests fetching the bean's class name if it is undefined.
    158      */
    159     public void testGetBeanClassNameUndefined()
    160     {
    161         decl = new XMLBeanDeclaration(new HierarchicalConfiguration());
    162         assertNull(decl.getBeanClassName());
    163     }
    164
    165     /***
    166      * Tests fetching the name of the bean factory.
    167      */
    168     public void testGetBeanFactoryName()
    169     {
    170         HierarchicalConfiguration config = new HierarchicalConfiguration();
    171         config.addProperty(KEY + "[@config-factory]", "myFactory");
    172         decl = new XMLBeanDeclaration(config, KEY);
    173         assertEquals("Wrong factory name", "myFactory", decl
    174                 .getBeanFactoryName());
    175     }
    176
    177     /***
    178      * Tests fetching the name of the bean factory if it is undefined.
    179      */
    180     public void testGetBeanFactoryNameUndefined()
    181     {
    182         decl = new XMLBeanDeclaration(new HierarchicalConfiguration());
    183         assertNull(decl.getBeanFactoryName());
    184     }
    185
    186     /***
    187      * Tests fetching the paramter for the bean factory.
    188      */
    189     public void testGetBeanFactoryParameter()
    190     {
    191         HierarchicalConfiguration config = new HierarchicalConfiguration();
    192         config
    193                 .addProperty(KEY + "[@config-factoryParam]",
    194                         "myFactoryParameter");
    195         decl = new XMLBeanDeclaration(config, KEY);
    196         assertEquals("Wrong factory parameter", "myFactoryParameter", decl
    197                 .getBeanFactoryParameter());
    198     }
    199
    200     /***
    201      * Tests fetching the paramter for the bean factory if it is undefined.
    202      */
    203     public void testGetBeanFactoryParameterUndefined()
    204     {
    205         decl = new XMLBeanDeclaration(new HierarchicalConfiguration());
    206         assertNull(decl.getBeanFactoryParameter());
    207     }
    208
    209     /***
    210      * Tests if the bean's properties are correctly extracted from the
    211      * configuration object.
    212      */
    213     public void testGetBeanProperties()
    214     {
    215         HierarchicalConfiguration config = new HierarchicalConfiguration();
    216         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    217         decl = new XMLBeanDeclaration(config, KEY);
    218         checkProperties(decl, TEST_PROPS, TEST_VALUES);
    219     }
    220
    221     /***
    222      * Tests obtaining the bean's properties when reserved attributes are
    223      * involved. These should be ignored.
    224      */
    225     public void testGetBeanPropertiesWithReservedAttributes()
    226     {
    227         HierarchicalConfiguration config = new HierarchicalConfiguration();
    228         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    229         config.addProperty(KEY + "[@config-testattr]", "yes");
    230         config.addProperty(KEY + "[@config-anothertest]", "this, too");
    231         decl = new XMLBeanDeclaration(config, KEY);
    232         checkProperties(decl, TEST_PROPS, TEST_VALUES);
    233     }
    234
    235     /***
    236      * Tests fetching properties if none are defined.
    237      */
    238     public void testGetBeanPropertiesEmpty()
    239     {
    240         decl = new XMLBeanDeclaration(new HierarchicalConfiguration());
    241         Map props = decl.getBeanProperties();
    242         assertTrue("Properties found", props == null || props.isEmpty());
    243     }
    244
    245     /***
    246      * Creates a configuration with data for testing nested bean declarations.
    247      * @return the initialized test configuration
    248      */
    249     private HierarchicalConfiguration prepareNestedBeanDeclarations()
    250     {
    251         HierarchicalConfiguration config = new HierarchicalConfiguration();
    252         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    253         for (int i = 0; i < COMPLEX_PROPS.length; i++)
    254         {
    255             setupBeanDeclaration(config, KEY + '.' + COMPLEX_PROPS[i],
    256                     COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]);
    257             config.addProperty(
    258                     KEY + '.' + COMPLEX_PROPS[i] + "[@config-class]",
    259                     COMPLEX_CLASSES[i]);
    260         }
    261         return config;
    262     }
    263
    264     /***
    265      * Tests fetching nested bean declarations.
    266      */
    267     public void testGetNestedBeanDeclarations()
    268     {
    269         HierarchicalConfiguration config = prepareNestedBeanDeclarations();
    270         decl = new XMLBeanDeclaration(config, KEY);
    271         checkProperties(decl, TEST_PROPS, TEST_VALUES);
    272
    273         Map nested = decl.getNestedBeanDeclarations();
    274         assertEquals("Wrong number of nested declarations",
    275                 COMPLEX_PROPS.length, nested.size());
    276         for (int i = 0; i < COMPLEX_PROPS.length; i++)
    277         {
    278             XMLBeanDeclaration d = (XMLBeanDeclaration) nested
    279                     .get(COMPLEX_PROPS[i]);
    280             assertNotNull("No declaration found for " + COMPLEX_PROPS[i], d);
    281             checkProperties(d, COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]);
    282             assertEquals("Wrong bean class", COMPLEX_CLASSES[i], d
    283                     .getBeanClassName());
    284         }
    285     }
    286
    287     /***
    288      * Tests whether the factory method for creating nested bean declarations
    289      * gets called.
    290      */
    291     public void testGetNestedBeanDeclarationsFactoryMethod()
    292     {
    293         HierarchicalConfiguration config = prepareNestedBeanDeclarations();
    294         decl = new XMLBeanDeclaration(config, KEY)
    295         {
    296             protected BeanDeclaration createBeanDeclaration(
    297                     ConfigurationNode node)
    298             {
    299                 return new XMLBeanDeclarationTestImpl(getConfiguration()
    300                         .configurationAt(node.getName()), node);
    301             }
    302         };
    303         Map nested = decl.getNestedBeanDeclarations();
    304         for (int i = 0; i < COMPLEX_PROPS.length; i++)
    305         {
    306             Object d = nested.get(COMPLEX_PROPS[i]);
    307             assertTrue("Wrong class for bean declaration: " + d,
    308                     d instanceof XMLBeanDeclarationTestImpl);
    309         }
    310     }
    311
    312     /***
    313      * Tests fetching nested bean declarations if none are defined.
    314      */
    315     public void testGetNestedBeanDeclarationsEmpty()
    316     {
    317         HierarchicalConfiguration config = new HierarchicalConfiguration();
    318         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    319         decl = new XMLBeanDeclaration(config, KEY);
    320         Map nested = decl.getNestedBeanDeclarations();
    321         assertTrue("Found nested declarations", nested == null
    322                 || nested.isEmpty());
    323     }
    324
    325     /***
    326      * Tests whether interpolation of bean properties works.
    327      */
    328     public void testGetInterpolatedBeanProperties()
    329     {
    330         HierarchicalConfiguration config = new HierarchicalConfiguration();
    331         String[] varValues = new String[TEST_PROPS.length];
    332         for(int i = 0; i < TEST_PROPS.length; i++)
    333         {
    334             varValues[i] = "${" + VARS + TEST_PROPS[i] + "}";
    335             config.addProperty(VARS + TEST_PROPS[i], TEST_VALUES[i]);
    336         }
    337         setupBeanDeclaration(config, KEY, TEST_PROPS, varValues);
    338         decl = new XMLBeanDeclaration(config, KEY);
    339         checkProperties(decl, TEST_PROPS, TEST_VALUES);
    340     }
    341
    342     /***
    343      * Tests constructing a bean declaration from an undefined key. This should
    344      * cause an exception.
    345      */
    346     public void testInitFromUndefinedKey()
    347     {
    348         HierarchicalConfiguration config = new HierarchicalConfiguration();
    349         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    350         try
    351         {
    352             decl = new XMLBeanDeclaration(config, "undefined_key");
    353             fail("Could create declaration from an undefined key!");
    354         }
    355         catch (IllegalArgumentException iex)
    356         {
    357             // ok
    358         }
    359     }
    360
    361     /***
    362      * Tests constructing a bean declaration from a key, which is undefined when
    363      * the optional flag is set. In this case an empty declaration should be
    364      * created, which can be used for creating beans as long as a default class
    365      * is provided.
    366      */
    367     public void testInitFromUndefinedKeyOptional()
    368     {
    369         HierarchicalConfiguration config = new HierarchicalConfiguration();
    370         setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES);
    371         decl = new XMLBeanDeclaration(config, "undefined_key", true);
    372         assertNull("Found a bean class", decl.getBeanClassName());
    373     }
    374
    375     /***
    376      * Tests constructing a bean declaration from a key with multiple values.
    377      * This should cause an exception because keys must be unique.
    378      */
    379     public void testInitFromMultiValueKey()
    380     {
    381         HierarchicalConfiguration config = new HierarchicalConfiguration();
    382         config.addProperty(KEY, "myFirstKey");
    383         config.addProperty(KEY, "mySecondKey");
    384         try
    385         {
    386             decl = new XMLBeanDeclaration(config, KEY);
    387             fail("Could create declaration from multi-valued property!");
    388         }
    389         catch (IllegalArgumentException iex)
    390         {
    391             // ok
    392         }
    393     }
    394
    395     /***
    396      * Initializes a configuration object with a bean declaration. Under the
    397      * specified key the given properties will be added.
    398      *
    399      * @param config the configuration to initialize
    400      * @param key the key of the bean declaration
    401      * @param names an array with the names of the properties
    402      * @param values an array with the corresponding values
    403      */
    404     private void setupBeanDeclaration(HierarchicalConfiguration config,
    405             String key, String[] names, String[] values)
    406     {
    407         for (int i = 0; i < names.length; i++)
    408         {
    409             config.addProperty(key + "[@" + names[i] + "]", values[i]);
    410         }
    411     }
    412
    413     /***
    414      * Checks the properties returned by a bean declaration.
    415      *
    416      * @param beanDecl the bean declaration
    417      * @param names an array with the expected property names
    418      * @param values an array with the expected property values
    419      */
    420     private void checkProperties(BeanDeclaration beanDecl, String[] names,
    421             String[] values)
    422     {
    423         Map props = beanDecl.getBeanProperties();
    424         assertEquals("Wrong number of properties", names.length, props.size());
    425         for (int i = 0; i < names.length; i++)
    426         {
    427             assertTrue("Property " + names[i] + " not contained", props
    428                     .containsKey(names[i]));
    429             assertEquals("Wrong value for property " + names[i], values[i],
    430                     props.get(names[i]));
    431         }
    432     }
    433
    434     /***
    435      * A helper class used for testing the createBeanDeclaration() factory
    436      * method.
    437      */
    438     private static class XMLBeanDeclarationTestImpl extends XMLBeanDeclaration
    439     {
    440         public XMLBeanDeclarationTestImpl(SubnodeConfiguration config,
    441                 ConfigurationNode node)
    442         {
    443             super(config, node);
    444         }
    445     }
    446 }