    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.tree;
    18
    19  import java.util.Iterator;
    20  import java.util.List;
    21  import java.util.StringTokenizer;
    22
    23  import junit.framework.TestCase;
    24
    25  /***
    26   * Test class for DefaultConfigurationNode.
    27   *
    28   * @author Oliver Heger
    29   */
    30  public class TestDefaultConfigurationNode extends TestCase
    31  {
    32      /*** Constant array for the field names. */
    33      private static final String[] FIELD_NAMES =
    34      { "UID", "NAME", "FIRSTNAME", "LASTLOGIN"};
    35
    36      /*** Constant array for the field data types. */
    37      private static final String[] FIELD_TYPES =
    38      { "long", "string", "string", "date"};
    39
    40      /*** Constant array for additional field attributes. */
    41      private static final String[] FIELD_ATTRS =
    42      { "primarykey,unique", "notnull", "notnull", null};
    43
    44      /*** The node to be tested. */
    45      DefaultConfigurationNode node;
    46
    47      protected void setUp() throws Exception
    48      {
    49          super.setUp();
    50          node = new DefaultConfigurationNode();
    51          node.setName("table");
    52          node.setReference("TestReference");
    53          node.addAttribute(new DefaultConfigurationNode("type", "system"));
    54          node.addChild(new DefaultConfigurationNode("name", "users"));
    55
    56          // Add nodes for the table's fields
    57          for (int i = 0; i < FIELD_NAMES.length; i++)
    58          {
    59              DefaultConfigurationNode field = new DefaultConfigurationNode(
    60                      "field");
    61              field
    62                      .addChild(new DefaultConfigurationNode("name",
    63                              FIELD_NAMES[i]));
    64              field.addAttribute(new DefaultConfigurationNode("type",
    65                      FIELD_TYPES[i]));
    66              if (FIELD_ATTRS[i] != null)
    67              {
    68                  StringTokenizer tok = new StringTokenizer(FIELD_ATTRS[i], ", ");
    69                  while (tok.hasMoreTokens())
    70                  {
    71                      field.addAttribute(new DefaultConfigurationNode(
    72                              "attribute", tok.nextToken()));
    73                  }
    74              }
    75              node.addChild(field);
    76          }
    77      }
    78
    79      /***
    80       * Tests a newly created, uninitialized node.
    81       */
    82      public void testNewNode()
    83      {
    84          node = new DefaultConfigurationNode();
    85          assertNull("name is not null", node.getName());
    86          assertNull("value is not null", node.getValue());
    87          assertNull("reference is not null", node.getReference());
    88          assertTrue("Children are not empty", node.getChildren().isEmpty());
    89          assertTrue("Named children are not empty", node.getChildren("test")
    90                  .isEmpty());
    91          assertEquals("Children cound is not 0", 0, node.getChildrenCount());
    92          assertEquals("Named children count is not 0", 0, node
    93                  .getChildrenCount("test"));
    94          assertTrue("Attributes are not empty", node.getAttributes().isEmpty());
    95          assertTrue("Named attributes are not empty", node.getAttributes("test")
    96                  .isEmpty());
    97          assertNull("Node has a parent", node.getParentNode());
    98          assertFalse("Node is defined", node.isDefined());
    99          try
    100         {
    101             node.getAttribute(0);
    102             fail("Could access non existing attribute!");
    103         }
    104         catch (IndexOutOfBoundsException iex)
    105         {
    106             // ok
    107         }
    108     }
    109
    110     /***
    111      * Tests accessing a node's reference.
    112      */
    113     public void testGetReference()
    114     {
    115         assertEquals("Reference was not stored", "TestReference", node
    116                 .getReference());
    117     }
    118
    119     /***
    120      * Tests accessing the node's children.
    121      */
    122     public void testGetChildren()
    123     {
    124         assertEquals("Number of children incorrect", FIELD_NAMES.length + 1,
    125                 node.getChildrenCount());
    126         List children = node.getChildren();
    127         Iterator it = children.iterator();
    128         DefaultConfigurationNode child = (DefaultConfigurationNode) it.next();
    129         assertEquals("Wrong node", "name", child.getName());
    130         checkFieldNodes(it);
    131     }
    132
    133     /***
    134      * Tests accessing the node's children by name.
    135      */
    136     public void testGetChildrenByName()
    137     {
    138         List children = node.getChildren("field");
    139         assertEquals("Incorrect number of child nodes", FIELD_NAMES.length,
    140                 children.size());
    141         assertEquals("Incorrect result of getChildrenCount()",
    142                 FIELD_NAMES.length, node.getChildrenCount("field"));
    143         checkFieldNodes(children.iterator());
    144         assertTrue("Found non existing nodes", node.getChildren("test")
    145                 .isEmpty());
    146         assertEquals("Wrong children list for null", node.getChildren(), node
    147                 .getChildren(null));
    148     }
    149
    150     /***
    151      * Tests adding a new child node.
    152      */
    153     public void testAddChild()
    154     {
    155         int cnt = node.getChildrenCount();
    156         DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
    157                 "xyz");
    158         node.addChild(ndNew);
    159         assertEquals("New node was not added", cnt + 1, node.getChildrenCount());
    160         List children = node.getChildren();
    161         assertEquals("Incorrect number of children", node.getChildrenCount(),
    162                 children.size());
    163         assertSame("Node was not added to end", ndNew, children.get(cnt));
    164         assertEquals("Incorrect number of named children", 1, node
    165                 .getChildrenCount(ndNew.getName()));
    166         assertFalse("Child is an attribute", ndNew.isAttribute());
    167         assertSame("Parent was not set", node, ndNew.getParentNode());
    168     }
    169
    170     /***
    171      * Tests adding invalid child nodes.
    172      */
    173     public void testAddUndefinedChild()
    174     {
    175         try
    176         {
    177             node.addChild(null);
    178             fail("null node could be added!");
    179         }
    180         catch (IllegalArgumentException iex)
    181         {
    182             // ok
    183         }
    184
    185         try
    186         {
    187             node.addChild(new DefaultConfigurationNode());
    188             fail("Node without name could be added!");
    189         }
    190         catch (IllegalArgumentException iex)
    191         {
    192             // ok
    193         }
    194     }
    195
    196     /***
    197      * Tests removing a child node.
    198      */
    199     public void testRemoveChild()
    200     {
    201         DefaultConfigurationNode child = (DefaultConfigurationNode) node
    202                 .getChildren().get(3);
    203         int cnt = node.getChildrenCount();
    204         node.removeChild(child);
    205         assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
    206         for (Iterator it = node.getChildren().iterator(); it.hasNext();)
    207         {
    208             assertNotSame("Found removed node", child, it.next());
    209         }
    210         assertNull("Parent reference was not removed", child.getParentNode());
    211     }
    212
    213     /***
    214      * Tests removing a child node that does not belong to this node.
    215      */
    216     public void testRemoveNonExistingChild()
    217     {
    218         int cnt = node.getChildrenCount();
    219         node.removeChild(new DefaultConfigurationNode("test"));
    220         node.removeChild(new DefaultConfigurationNode());
    221         node.removeChild((ConfigurationNode) null);
    222         node.removeChild("non existing child node");
    223         node.removeChild((String) null);
    224         assertEquals("Children were changed", cnt, node.getChildrenCount());
    225     }
    226
    227     /***
    228      * Tests removing children by their name.
    229      */
    230     public void testRemoveChildByName()
    231     {
    232         int cnt = node.getChildrenCount();
    233         node.removeChild("name");
    234         assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
    235         assertEquals("Still found name child", 0, node.getChildrenCount("name"));
    236         node.removeChild("field");
    237         assertEquals("Still remaining nodes", 0, node.getChildrenCount());
    238     }
    239
    240     /***
    241      * Tests removing all children at once.
    242      */
    243     public void testRemoveChildren()
    244     {
    245         node.removeChildren();
    246         assertEquals("Children count is not 0", 0, node.getChildrenCount());
    247         assertTrue("Children are not empty", node.getChildren().isEmpty());
    248     }
    249
    250     /***
    251      * Tests accessing a child by its index.
    252      */
    253     public void testGetChild()
    254     {
    255         ConfigurationNode child = node.getChild(2);
    256         assertEquals("Wrong child returned", child, node.getChildren().get(2));
    257     }
    258
    259     /***
    260      * Tests accessing child nodes with invalid indices.
    261      */
    262     public void testGetChildInvalidIndex()
    263     {
    264         try
    265         {
    266             node.getChild(4724);
    267             fail("Could access invalid index!");
    268         }
    269         catch (IndexOutOfBoundsException iex)
    270         {
    271             // ok
    272         }
    273     }
    274
    275     /***
    276      * Tests accessing the node's attributes.
    277      */
    278     public void testGetAttributes()
    279     {
    280         assertEquals("Number of attributes incorrect", 1, node
    281                 .getAttributeCount());
    282         List attributes = node.getAttributes();
    283         Iterator it = attributes.iterator();
    284         DefaultConfigurationNode attr = (DefaultConfigurationNode) it.next();
    285         assertEquals("Wrong node", "type", attr.getName());
    286         assertFalse("More attributes", it.hasNext());
    287     }
    288
    289     /***
    290      * Tests accessing the node's attributes by name.
    291      */
    292     public void testGetAttributesByName()
    293     {
    294         assertEquals("Incorrect number of attributes", 1, node
    295                 .getAttributeCount("type"));
    296         DefaultConfigurationNode field = (DefaultConfigurationNode) node
    297                 .getChildren().get(1);
    298         assertEquals("Incorrect number of attributes", 2, field
    299                 .getAttributeCount("attribute"));
    300         List attrs = field.getAttributes("attribute");
    301         assertEquals("Wrong value", "primarykey",
    302                 ((DefaultConfigurationNode) attrs.get(0)).getValue());
    303         assertEquals("Wrong value", "unique", ((DefaultConfigurationNode) attrs
    304                 .get(1)).getValue());
    305     }
    306
    307     /***
    308      * Tests adding a new attribute node.
    309      */
    310     public void testAddAttribute()
    311     {
    312         int cnt = node.getAttributeCount();
    313         DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
    314                 "xyz");
    315         node.addAttribute(ndNew);
    316         assertEquals("New node was not added", cnt + 1, node
    317                 .getAttributeCount());
    318         List attrs = node.getAttributes();
    319         assertEquals("Incorrect number of attributes",
    320                 node.getAttributeCount(), attrs.size());
    321         assertSame("Node was not added to end", ndNew, attrs.get(cnt));
    322         assertEquals("Incorrect number of named attributes", 1, node
    323                 .getAttributeCount(ndNew.getName()));
    324         assertTrue("Child is no attribute", ndNew.isAttribute());
    325         assertSame("Parent was not set", node, ndNew.getParentNode());
    326     }
    327
    328     /***
    329      * Tests removing an attribute node.
    330      */
    331     public void testRemoveAttribute()
    332     {
    333         DefaultConfigurationNode attr = (DefaultConfigurationNode) node
    334                 .getAttributes().get(0);
    335         int cnt = node.getAttributeCount();
    336         node.removeAttribute(attr);
    337         assertEquals("Attribute was not removed", cnt - 1, node
    338                 .getAttributeCount());
    339         for (Iterator it = node.getAttributes().iterator(); it.hasNext();)
    340         {
    341             assertNotSame("Found removed node", attr, it.next());
    342         }
    343         assertNull("Parent reference was not removed", attr.getParentNode());
    344     }
    345
    346     /***
    347      * Tests removing attributes by their names.
    348      */
    349     public void testRemoveAttributeByName()
    350     {
    351         ConfigurationNode field = node.getChild(1);
    352         assertEquals("Incorrect number of attributes", 3, field
    353                 .getAttributeCount());
    354         field.removeAttribute("attribute");
    355         assertEquals("Not all nodes removed", 1, field.getAttributeCount());
    356         assertTrue("Remaining attributes", field.getAttributes("attribute")
    357                 .isEmpty());
    358         field.removeAttribute("type");
    359         assertEquals("Remaining attributes", 0, field.getAttributeCount());
    360     }
    361
    362     /***
    363      * Tests removing all attributes.
    364      */
    365     public void testRemoveAttributes()
    366     {
    367         node.removeAttributes();
    368         assertEquals("Not all attributes removed", 0, node.getAttributeCount());
    369         assertTrue("Attributes not empty", node.getAttributes().isEmpty());
    370     }
    371
    372     /***
    373      * Tests changing a node's attribute state.
    374      */
    375     public void testChangeAttributeState()
    376     {
    377         ConfigurationNode attr = node.getAttribute(0);
    378         try
    379         {
    380             attr.setAttribute(false);
    381             fail("Could change node's attribute state!");
    382         }
    383         catch (IllegalStateException iex)
    384         {
    385             // ok
    386         }
    387     }
    388
    389     /***
    390      * Tests the visit() method using a simple visitor.
    391      */
    392     public void testVisit()
    393     {
    394         CountNodeVisitor visitor = new CountNodeVisitor();
    395         node.visit(visitor);
    396         assertEquals("Not all nodes visited", 19, visitor.beforeCalls);
    397         assertEquals("Different number of before and after calls",
    398                 visitor.beforeCalls, visitor.afterCalls);
    399     }
    400
    401     /***
    402      * Tests the visit() method with a visitor that terminates the visit
    403      * process.
    404      */
    405     public void testVisitWithTerminate()
    406     {
    407         CountNodeVisitor visitor = new CountNodeVisitor(10);
    408         node.visit(visitor);
    409         assertEquals("Incorrect number of nodes visited", visitor.maxCalls,
    410                 visitor.beforeCalls);
    411         assertEquals("Different number of before and after calls",
    412                 visitor.beforeCalls, visitor.afterCalls);
    413     }
    414
    415     /***
    416      * Tests the visit() method when null is passed in. This should throw an
    417      * exception.
    418      */
    419     public void testVisitWithNullVisitor()
    420     {
    421         try
    422         {
    423             node.visit(null);
    424             fail("Could pass in null visitor!");
    425         }
    426         catch (IllegalArgumentException iex)
    427         {
    428             // ok
    429         }
    430     }
    431
    432     /***
    433      * Tests cloning a node.
    434      */
    435     public void testClone()
    436     {
    437         node.setValue("TestValue");
    438         DefaultConfigurationNode clone = (DefaultConfigurationNode) node.clone();
    439         assertEquals("Value not cloned", "TestValue", clone.getValue());
    440         assertEquals("Name not cloned", "table", clone.getName());
    441         assertEquals("Reference not cloned", "TestReference", clone.getReference());
    442         assertEquals("Children were cloned", 0, clone.getChildrenCount());
    443         assertEquals("Attributes were cloned", 0, clone.getAttributeCount());
    444     }
    445
    446     /***
    447      * Helper method for checking the child nodes of type &quot;field&quot;.
    448      *
    449      * @param itFields the iterator with the child nodes
    450      */
    451     private void checkFieldNodes(Iterator itFields)
    452     {
    453         for (int i = 0; i < FIELD_NAMES.length; i++)
    454         {
    455             DefaultConfigurationNode child = (DefaultConfigurationNode) itFields
    456                     .next();
    457             assertEquals("Wrong node", "field", child.getName());
    458             List nameNodes = child.getChildren("name");
    459             assertEquals("Wrong number of name nodes", 1, nameNodes.size());
    460             DefaultConfigurationNode nameNode = (DefaultConfigurationNode) nameNodes
    461                     .get(0);
    462             assertEquals("Wrong field name", FIELD_NAMES[i], nameNode
    463                     .getValue());
    464         }
    465     }
    466
    467     /***
    468      * A test visitor implementation that is able to count the number of visits.
    469      * It also supports a maximum number of visits to be set; if this number is
    470      * reached, the <code>terminate()</code> method returns <b>true</b>.
    471      */
    472     static class CountNodeVisitor implements ConfigurationNodeVisitor
    473     {
    474         public int beforeCalls;
    475
    476         public int afterCalls;
    477
    478         public int maxCalls;
    479
    480         public CountNodeVisitor()
    481         {
    482             this(Integer.MAX_VALUE);
    483         }
    484
    485         public CountNodeVisitor(int maxNumberOfVisits)
    486         {
    487             maxCalls = maxNumberOfVisits;
    488         }
    489
    490         public void visitBeforeChildren(ConfigurationNode node)
    491         {
    492             beforeCalls++;
    493         }
    494
    495         public void visitAfterChildren(ConfigurationNode node)
    496         {
    497             afterCalls++;
    498         }
    499
    500         public boolean terminate()
    501         {
    502             return beforeCalls >= maxCalls;
    503         }
    504     }
    505 }