001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.configuration.tree;
018    
019    import static org.junit.Assert.assertEquals;
020    import static org.junit.Assert.assertFalse;
021    import static org.junit.Assert.assertNotSame;
022    import static org.junit.Assert.assertNull;
023    import static org.junit.Assert.assertSame;
024    import static org.junit.Assert.assertTrue;
025    
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.StringTokenizer;
029    
030    import org.junit.Before;
031    import org.junit.Test;
032    
033    /**
034     * Test class for DefaultConfigurationNode.
035     *
036     * @author <a
037     * href="http://commons.apache.org/configuration/team-list.html">Commons
038     * Configuration team</a>
039     * @version $Id: TestDefaultConfigurationNode.java 1225917 2011-12-30 20:42:09Z oheger $
040     */
041    public class TestDefaultConfigurationNode
042    {
043        /** Constant array for the field names. */
044        private static final String[] FIELD_NAMES =
045        { "UID", "NAME", "FIRSTNAME", "LASTLOGIN"};
046    
047        /** Constant array for the field data types. */
048        private static final String[] FIELD_TYPES =
049        { "long", "string", "string", "date"};
050    
051        /** Constant array for additional field attributes. */
052        private static final String[] FIELD_ATTRS =
053        { "primarykey,unique", "notnull", "notnull", null};
054    
055        /** The node to be tested. */
056        DefaultConfigurationNode node;
057    
058        @Before
059        public void setUp() throws Exception
060        {
061            node = new DefaultConfigurationNode();
062            node.setName("table");
063            node.setReference("TestReference");
064            node.addAttribute(new DefaultConfigurationNode("type", "system"));
065            node.addChild(new DefaultConfigurationNode("name", "users"));
066    
067            // Add nodes for the table's fields
068            for (int i = 0; i < FIELD_NAMES.length; i++)
069            {
070                DefaultConfigurationNode field = new DefaultConfigurationNode(
071                        "field");
072                field
073                        .addChild(new DefaultConfigurationNode("name",
074                                FIELD_NAMES[i]));
075                field.addAttribute(new DefaultConfigurationNode("type",
076                        FIELD_TYPES[i]));
077                if (FIELD_ATTRS[i] != null)
078                {
079                    StringTokenizer tok = new StringTokenizer(FIELD_ATTRS[i], ", ");
080                    while (tok.hasMoreTokens())
081                    {
082                        field.addAttribute(new DefaultConfigurationNode(
083                                "attribute", tok.nextToken()));
084                    }
085                }
086                node.addChild(field);
087            }
088        }
089    
090        /**
091         * Tests a newly created, uninitialized node.
092         */
093        @Test
094        public void testNewNode()
095        {
096            node = new DefaultConfigurationNode();
097            assertNull("name is not null", node.getName());
098            assertNull("value is not null", node.getValue());
099            assertNull("reference is not null", node.getReference());
100            assertTrue("Children are not empty", node.getChildren().isEmpty());
101            assertTrue("Named children are not empty", node.getChildren("test")
102                    .isEmpty());
103            assertEquals("Children cound is not 0", 0, node.getChildrenCount());
104            assertEquals("Named children count is not 0", 0, node
105                    .getChildrenCount("test"));
106            assertTrue("Attributes are not empty", node.getAttributes().isEmpty());
107            assertTrue("Named attributes are not empty", node.getAttributes("test")
108                    .isEmpty());
109            assertNull("Node has a parent", node.getParentNode());
110            assertFalse("Node is defined", node.isDefined());
111        }
112    
113        /**
114         * Tries to access an attribute using an invalid index.
115         */
116        @Test(expected = IndexOutOfBoundsException.class)
117        public void testGetAttributeNonExisting()
118        {
119            node = new DefaultConfigurationNode();
120            node.getAttribute(0);
121        }
122    
123        /**
124         * Tests accessing a node's reference.
125         */
126        @Test
127        public void testGetReference()
128        {
129            assertEquals("Reference was not stored", "TestReference", node
130                    .getReference());
131        }
132    
133        /**
134         * Tests accessing the node's children.
135         */
136        @Test
137        public void testGetChildren()
138        {
139            assertEquals("Number of children incorrect", FIELD_NAMES.length + 1,
140                    node.getChildrenCount());
141            List<ConfigurationNode> children = node.getChildren();
142            Iterator<ConfigurationNode> it = children.iterator();
143            DefaultConfigurationNode child = (DefaultConfigurationNode) it.next();
144            assertEquals("Wrong node", "name", child.getName());
145            checkFieldNodes(it);
146        }
147    
148        /**
149         * Tests accessing the node's children by name.
150         */
151        @Test
152        public void testGetChildrenByName()
153        {
154            List<ConfigurationNode> children = node.getChildren("field");
155            assertEquals("Incorrect number of child nodes", FIELD_NAMES.length,
156                    children.size());
157            assertEquals("Incorrect result of getChildrenCount()",
158                    FIELD_NAMES.length, node.getChildrenCount("field"));
159            checkFieldNodes(children.iterator());
160            assertTrue("Found non existing nodes", node.getChildren("test")
161                    .isEmpty());
162            assertEquals("Wrong children list for null", node.getChildren(), node
163                    .getChildren(null));
164        }
165    
166        /**
167         * Tests adding a new child node.
168         */
169        @Test
170        public void testAddChild()
171        {
172            int cnt = node.getChildrenCount();
173            DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
174                    "xyz");
175            node.addChild(ndNew);
176            assertEquals("New node was not added", cnt + 1, node.getChildrenCount());
177            List<ConfigurationNode> children = node.getChildren();
178            assertEquals("Incorrect number of children", node.getChildrenCount(),
179                    children.size());
180            assertSame("Node was not added to end", ndNew, children.get(cnt));
181            assertEquals("Incorrect number of named children", 1, node
182                    .getChildrenCount(ndNew.getName()));
183            assertFalse("Child is an attribute", ndNew.isAttribute());
184            assertSame("Parent was not set", node, ndNew.getParentNode());
185        }
186    
187        /**
188         * Tries to add a null child node.
189         */
190        @Test(expected = IllegalArgumentException.class)
191        public void testAddChildNull()
192        {
193            node.addChild(null);
194        }
195    
196        /**
197         * Tries to add a node without a name.
198         */
199        @Test(expected = IllegalArgumentException.class)
200        public void testAddUndefinedChild()
201        {
202            node.addChild(new DefaultConfigurationNode());
203        }
204    
205        /**
206         * Tests removing a child node.
207         */
208        @Test
209        public void testRemoveChild()
210        {
211            DefaultConfigurationNode child = (DefaultConfigurationNode) node
212                    .getChildren().get(3);
213            int cnt = node.getChildrenCount();
214            node.removeChild(child);
215            assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
216            for (ConfigurationNode nd : node.getChildren())
217            {
218                assertNotSame("Found removed node", child, nd);
219            }
220            assertNull("Parent reference was not removed", child.getParentNode());
221        }
222    
223        /**
224         * Tests removing a child node that does not belong to this node.
225         */
226        @Test
227        public void testRemoveNonExistingChild()
228        {
229            int cnt = node.getChildrenCount();
230            node.removeChild(new DefaultConfigurationNode("test"));
231            node.removeChild(new DefaultConfigurationNode());
232            node.removeChild((ConfigurationNode) null);
233            node.removeChild("non existing child node");
234            node.removeChild((String) null);
235            assertEquals("Children were changed", cnt, node.getChildrenCount());
236        }
237    
238        /**
239         * Tests removing children by their name.
240         */
241        @Test
242        public void testRemoveChildByName()
243        {
244            int cnt = node.getChildrenCount();
245            node.removeChild("name");
246            assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
247            assertEquals("Still found name child", 0, node.getChildrenCount("name"));
248            node.removeChild("field");
249            assertEquals("Still remaining nodes", 0, node.getChildrenCount());
250        }
251    
252        /**
253         * Tests removing all children at once.
254         */
255        @Test
256        public void testRemoveChildren()
257        {
258            node.removeChildren();
259            assertEquals("Children count is not 0", 0, node.getChildrenCount());
260            assertTrue("Children are not empty", node.getChildren().isEmpty());
261        }
262    
263        /**
264         * Tests accessing a child by its index.
265         */
266        @Test
267        public void testGetChild()
268        {
269            ConfigurationNode child = node.getChild(2);
270            assertEquals("Wrong child returned", child, node.getChildren().get(2));
271        }
272    
273        /**
274         * Tests accessing child nodes with invalid indices.
275         */
276        @Test(expected = IndexOutOfBoundsException.class)
277        public void testGetChildInvalidIndex()
278        {
279            node.getChild(4724);
280        }
281    
282        /**
283         * Tests accessing the node's attributes.
284         */
285        @Test
286        public void testGetAttributes()
287        {
288            assertEquals("Number of attributes incorrect", 1, node
289                    .getAttributeCount());
290            List<ConfigurationNode> attributes = node.getAttributes();
291            Iterator<ConfigurationNode> it = attributes.iterator();
292            DefaultConfigurationNode attr = (DefaultConfigurationNode) it.next();
293            assertEquals("Wrong node", "type", attr.getName());
294            assertFalse("More attributes", it.hasNext());
295        }
296    
297        /**
298         * Tests accessing the node's attributes by name.
299         */
300        @Test
301        public void testGetAttributesByName()
302        {
303            assertEquals("Incorrect number of attributes", 1, node
304                    .getAttributeCount("type"));
305            DefaultConfigurationNode field = (DefaultConfigurationNode) node
306                    .getChildren().get(1);
307            assertEquals("Incorrect number of attributes", 2, field
308                    .getAttributeCount("attribute"));
309            List<ConfigurationNode> attrs = field.getAttributes("attribute");
310            assertEquals("Wrong value", "primarykey",
311                    ((DefaultConfigurationNode) attrs.get(0)).getValue());
312            assertEquals("Wrong value", "unique", ((DefaultConfigurationNode) attrs
313                    .get(1)).getValue());
314        }
315    
316        /**
317         * Tests adding a new attribute node.
318         */
319        @Test
320        public void testAddAttribute()
321        {
322            int cnt = node.getAttributeCount();
323            DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
324                    "xyz");
325            node.addAttribute(ndNew);
326            assertEquals("New node was not added", cnt + 1, node
327                    .getAttributeCount());
328            List<ConfigurationNode> attrs = node.getAttributes();
329            assertEquals("Incorrect number of attributes",
330                    node.getAttributeCount(), attrs.size());
331            assertSame("Node was not added to end", ndNew, attrs.get(cnt));
332            assertEquals("Incorrect number of named attributes", 1, node
333                    .getAttributeCount(ndNew.getName()));
334            assertTrue("Child is no attribute", ndNew.isAttribute());
335            assertSame("Parent was not set", node, ndNew.getParentNode());
336        }
337    
338        /**
339         * Tests removing an attribute node.
340         */
341        @Test
342        public void testRemoveAttribute()
343        {
344            DefaultConfigurationNode attr = (DefaultConfigurationNode) node
345                    .getAttributes().get(0);
346            int cnt = node.getAttributeCount();
347            node.removeAttribute(attr);
348            assertEquals("Attribute was not removed", cnt - 1, node
349                    .getAttributeCount());
350            for (ConfigurationNode nd : node.getAttributes())
351            {
352                assertNotSame("Found removed node", attr, nd);
353            }
354            assertNull("Parent reference was not removed", attr.getParentNode());
355        }
356    
357        /**
358         * Tests removing attributes by their names.
359         */
360        @Test
361        public void testRemoveAttributeByName()
362        {
363            ConfigurationNode field = node.getChild(1);
364            assertEquals("Incorrect number of attributes", 3, field
365                    .getAttributeCount());
366            field.removeAttribute("attribute");
367            assertEquals("Not all nodes removed", 1, field.getAttributeCount());
368            assertTrue("Remaining attributes", field.getAttributes("attribute")
369                    .isEmpty());
370            field.removeAttribute("type");
371            assertEquals("Remaining attributes", 0, field.getAttributeCount());
372        }
373    
374        /**
375         * Tests removing all attributes.
376         */
377        @Test
378        public void testRemoveAttributes()
379        {
380            node.removeAttributes();
381            assertEquals("Not all attributes removed", 0, node.getAttributeCount());
382            assertTrue("Attributes not empty", node.getAttributes().isEmpty());
383        }
384    
385        /**
386         * Tests changing a node's attribute state.
387         */
388        @Test(expected = IllegalStateException.class)
389        public void testChangeAttributeState()
390        {
391            ConfigurationNode attr = node.getAttribute(0);
392            attr.setAttribute(false);
393        }
394    
395        /**
396         * Tests the visit() method using a simple visitor.
397         */
398        @Test
399        public void testVisit()
400        {
401            CountNodeVisitor visitor = new CountNodeVisitor();
402            node.visit(visitor);
403            assertEquals("Not all nodes visited", 19, visitor.beforeCalls);
404            assertEquals("Different number of before and after calls",
405                    visitor.beforeCalls, visitor.afterCalls);
406        }
407    
408        /**
409         * Tests the visit() method with a visitor that terminates the visit
410         * process.
411         */
412        @Test
413        public void testVisitWithTerminate()
414        {
415            CountNodeVisitor visitor = new CountNodeVisitor(10);
416            node.visit(visitor);
417            assertEquals("Incorrect number of nodes visited", visitor.maxCalls,
418                    visitor.beforeCalls);
419            assertEquals("Different number of before and after calls",
420                    visitor.beforeCalls, visitor.afterCalls);
421        }
422    
423        /**
424         * Tests the visit() method when null is passed in. This should throw an
425         * exception.
426         */
427        @Test(expected = IllegalArgumentException.class)
428        public void testVisitWithNullVisitor()
429        {
430            node.visit(null);
431        }
432    
433        /**
434         * Tests cloning a node.
435         */
436        @Test
437        public void testClone()
438        {
439            node.setValue("TestValue");
440            DefaultConfigurationNode clone = (DefaultConfigurationNode) node.clone();
441            assertEquals("Value not cloned", "TestValue", clone.getValue());
442            assertEquals("Name not cloned", "table", clone.getName());
443            assertEquals("Reference not cloned", "TestReference", clone.getReference());
444            assertEquals("Children were cloned", 0, clone.getChildrenCount());
445            assertEquals("Attributes were cloned", 0, clone.getAttributeCount());
446        }
447    
448        /**
449         * Helper method for checking the child nodes of type &quot;field&quot;.
450         *
451         * @param itFields the iterator with the child nodes
452         */
453        private void checkFieldNodes(Iterator<ConfigurationNode> itFields)
454        {
455            for (int i = 0; i < FIELD_NAMES.length; i++)
456            {
457                DefaultConfigurationNode child = (DefaultConfigurationNode) itFields
458                        .next();
459                assertEquals("Wrong node", "field", child.getName());
460                List<ConfigurationNode> nameNodes = child.getChildren("name");
461                assertEquals("Wrong number of name nodes", 1, nameNodes.size());
462                DefaultConfigurationNode nameNode = (DefaultConfigurationNode) nameNodes
463                        .get(0);
464                assertEquals("Wrong field name", FIELD_NAMES[i], nameNode
465                        .getValue());
466            }
467        }
468    
469        /**
470         * A test visitor implementation that is able to count the number of visits.
471         * It also supports a maximum number of visits to be set; if this number is
472         * reached, the <code>terminate()</code> method returns <b>true</b>.
473         */
474        public static class CountNodeVisitor implements ConfigurationNodeVisitor
475        {
476            public int beforeCalls;
477    
478            public int afterCalls;
479    
480            public int maxCalls;
481    
482            public CountNodeVisitor()
483            {
484                this(Integer.MAX_VALUE);
485            }
486    
487            public CountNodeVisitor(int maxNumberOfVisits)
488            {
489                maxCalls = maxNumberOfVisits;
490            }
491    
492            public void visitBeforeChildren(ConfigurationNode node)
493            {
494                beforeCalls++;
495            }
496    
497            public void visitAfterChildren(ConfigurationNode node)
498            {
499                afterCalls++;
500            }
501    
502            public boolean terminate()
503            {
504                return beforeCalls >= maxCalls;
505            }
506        }
507    }