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 }