1   /*
2    * Copyright 2001-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.configuration;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.commons.configuration.HierarchicalConfiguration.Node;
27  
28  import junit.framework.TestCase;
29  
30  /***
31   * Test class for HierarchicalConfiguration.
32   * 
33   * @version $Id: TestHierarchicalConfiguration.java 234100 2005-08-20 18:18:16Z oheger $
34   */
35  public class TestHierarchicalConfiguration extends TestCase
36  {
37      private static String[] tables = { "users", "documents" };
38      
39      private static String[][] fields =
40      {
41          { "uid", "uname", "firstName", "lastName", "email" },
42          { "docid", "name", "creationDate", "authorID", "version" }
43      };
44          
45      private HierarchicalConfiguration config;
46  
47      protected void setUp() throws Exception
48      {
49          /***
50           * Initialize the configuration with the following structure:
51           *
52           * tables
53           *      table
54           *         name
55           *         fields
56           *             field
57           *                 name
58           *             field
59           *                 name
60           */
61          config = new HierarchicalConfiguration();
62          HierarchicalConfiguration.Node nodeTables = createNode("tables", null);
63          for(int i = 0; i < tables.length; i++)
64          {
65              HierarchicalConfiguration.Node nodeTable = createNode("table", null); 
66              nodeTables.addChild(nodeTable);
67              HierarchicalConfiguration.Node nodeName = createNode("name", tables[i]);
68              nodeTable.addChild(nodeName);
69              HierarchicalConfiguration.Node nodeFields = createNode("fields", null);
70              nodeTable.addChild(nodeFields);
71  
72              for (int j = 0; j < fields[i].length; j++)
73              {
74                  nodeFields.addChild(createFieldNode(fields[i][j]));
75              }
76          }
77  
78          config.getRoot().addChild(nodeTables);
79      }
80      
81      public void testSetRoot()
82      {
83          try
84          {
85              config.setRoot(null);
86              fail("Could set null root node!");
87          }
88          catch(IllegalArgumentException iex)
89          {
90              //ok
91          }
92          
93          config.setRoot(new HierarchicalConfiguration.Node("test"));
94          assertTrue(config.isEmpty());
95      }
96  
97      public void testIsEmpty()
98      {
99          assertFalse(config.isEmpty());
100         HierarchicalConfiguration conf2 = new HierarchicalConfiguration();
101         assertTrue(conf2.isEmpty());
102         HierarchicalConfiguration.Node child1 = new HierarchicalConfiguration.Node("child1");
103         HierarchicalConfiguration.Node child2 = new HierarchicalConfiguration.Node("child2");
104         child1.addChild(child2);
105         conf2.getRoot().addChild(child1);
106         assertTrue(conf2.isEmpty());
107     }
108 
109     public void testGetProperty()
110     {
111         assertNull(config.getProperty("tables.table.resultset"));
112         assertNull(config.getProperty("tables.table.fields.field"));
113         
114         Object prop = config.getProperty("tables.table(0).fields.field.name");
115         assertNotNull(prop);
116         assertTrue(prop instanceof Collection);
117         assertEquals(5, ((Collection) prop).size());
118         
119         prop = config.getProperty("tables.table.fields.field.name");
120         assertNotNull(prop);
121         assertTrue(prop instanceof Collection);
122         assertEquals(10, ((Collection) prop).size());
123         
124         prop = config.getProperty("tables.table.fields.field(3).name");
125         assertNotNull(prop);
126         assertTrue(prop instanceof Collection);
127         assertEquals(2, ((Collection) prop).size());
128         
129         prop = config.getProperty("tables.table(1).fields.field(2).name");
130         assertNotNull(prop);
131         assertEquals("creationDate", prop.toString());
132     }
133     
134     public void testSetProperty()
135     {
136         config.setProperty("tables.table(0).name", "resources");
137         assertEquals("resources", config.getString("tables.table(0).name"));
138         config.setProperty("tables.table.name", "tab1,tab2");
139         assertEquals("tab1", config.getString("tables.table(0).name"));
140         assertEquals("tab2", config.getString("tables.table(1).name"));
141         
142         config.setProperty("test.items.item", new int[] { 2, 4, 8, 16 });
143         assertEquals(3, config.getMaxIndex("test.items.item"));
144         assertEquals(8, config.getInt("test.items.item(2)"));
145         config.setProperty("test.items.item(2)", new Integer(6));
146         assertEquals(6, config.getInt("test.items.item(2)"));
147         config.setProperty("test.items.item(2)", new int[] { 7, 9, 11 });
148         assertEquals(5, config.getMaxIndex("test.items.item"));
149         
150         config.setProperty("test", Boolean.TRUE);
151         config.setProperty("test.items", "01/01/05");
152         assertEquals(5, config.getMaxIndex("test.items.item"));
153         assertTrue(config.getBoolean("test"));
154         assertEquals("01/01/05", config.getProperty("test.items"));
155         
156         config.setProperty("test.items.item", new Integer(42));
157         assertEquals(0, config.getMaxIndex("test.items.item"));
158         assertEquals(42, config.getInt("test.items.item"));
159     }
160     
161     public void testClearProperty()
162     {
163         config.clearProperty("tables.table(0).fields.field(0).name");
164         assertEquals("uname", config.getProperty("tables.table(0).fields.field(0).name"));
165         config.clearProperty("tables.table(0).name");
166         assertFalse(config.containsKey("tables.table(0).name"));
167         assertEquals("firstName", config.getProperty("tables.table(0).fields.field(1).name"));
168         assertEquals("documents", config.getProperty("tables.table.name"));
169         config.clearProperty("tables.table");
170         assertEquals("documents", config.getProperty("tables.table.name"));
171         
172         config.addProperty("test", "first");
173         config.addProperty("test.level", "second");
174         config.clearProperty("test");
175         assertEquals("second", config.getString("test.level"));
176         assertFalse(config.containsKey("test"));
177     }
178     
179     public void testClearTree()
180     {
181         Object prop = config.getProperty("tables.table(0).fields.field.name");
182         assertNotNull(prop);
183         config.clearTree("tables.table(0).fields.field(3)");
184         prop = config.getProperty("tables.table(0).fields.field.name");
185         assertNotNull(prop);
186         assertTrue(prop instanceof Collection);
187         assertEquals(4, ((Collection) prop).size());
188         
189         config.clearTree("tables.table(0).fields");
190         assertNull(config.getProperty("tables.table(0).fields.field.name"));
191         prop = config.getProperty("tables.table.fields.field.name");
192         assertNotNull(prop);
193         assertTrue(prop instanceof Collection);
194         assertEquals(5, ((Collection) prop).size());
195         
196         config.clearTree("tables.table(1)");
197         assertNull(config.getProperty("tables.table.fields.field.name"));
198     }
199     
200     public void testContainsKey()
201     {
202         assertTrue(config.containsKey("tables.table(0).name"));
203         assertTrue(config.containsKey("tables.table(1).name"));
204         assertFalse(config.containsKey("tables.table(2).name"));
205         
206         assertTrue(config.containsKey("tables.table(0).fields.field.name"));
207         assertFalse(config.containsKey("tables.table(0).fields.field"));
208         config.clearTree("tables.table(0).fields");
209         assertFalse(config.containsKey("tables.table(0).fields.field.name"));
210         
211         assertTrue(config.containsKey("tables.table.fields.field.name"));
212     }
213     
214     public void testGetKeys()
215     {
216         List keys = new ArrayList();
217         for (Iterator it = config.getKeys(); it.hasNext();)
218         {
219             keys.add(it.next()); 
220         }
221         
222         assertEquals(2, keys.size());
223         assertTrue(keys.contains("tables.table.name"));
224         assertTrue(keys.contains("tables.table.fields.field.name"));
225 
226         // test the order of the keys returned
227         config.addProperty("order.key1", "value1");
228         config.addProperty("order.key2", "value2");
229         config.addProperty("order.key3", "value3");
230 
231         Iterator it = config.getKeys("order");
232         assertEquals("1st key", "order.key1", it.next());
233         assertEquals("2nd key", "order.key2", it.next());
234         assertEquals("3rd key", "order.key3", it.next());
235     }
236     
237     public void testGetKeysString()
238     {
239         // add some more properties to make it more interesting
240         config.addProperty("tables.table(0).fields.field(1).type", "VARCHAR");
241         config.addProperty("tables.table(0)[@type]", "system");
242         config.addProperty("tables.table(0).size", "42");
243         config.addProperty("tables.table(0).fields.field(0).size", "128");
244         config.addProperty("connections.connection.param.url", "url1");
245         config.addProperty("connections.connection.param.user", "me");
246         config.addProperty("connections.connection.param.pwd", "secret");
247         config.addProperty("connections.connection(-1).param.url", "url2");
248         config.addProperty("connections.connection(1).param.user", "guest");
249         
250         checkKeys("tables.table(1)", new String[] { "name", "fields.field.name" });
251         checkKeys("tables.table(0)",
252                 new String[] { "name", "fields.field.name", "tables.table(0)[@type]", "size", "fields.field.type", "fields.field.size" });
253         checkKeys("connections.connection(0).param",
254                 new String[] {"url", "user", "pwd" });
255         checkKeys("connections.connection(1).param",
256                 new String[] {"url", "user" });
257     }
258     
259     public void testAddProperty()
260     {
261         config.addProperty("tables.table(0).fields.field(-1).name", "phone");
262         Object prop = config.getProperty("tables.table(0).fields.field.name");
263         assertNotNull(prop);
264         assertTrue(prop instanceof Collection);
265         assertEquals(6, ((Collection) prop).size());
266         
267         config.addProperty("tables.table(0).fields.field.name", "fax");
268         prop = config.getProperty("tables.table.fields.field(5).name");
269         assertNotNull(prop);
270         assertTrue(prop instanceof List);
271         List list = (List) prop;
272         assertEquals("phone", list.get(0));
273         assertEquals("fax", list.get(1));
274         
275         config.addProperty("tables.table(-1).name", "config");
276         prop = config.getProperty("tables.table.name");
277         assertNotNull(prop);
278         assertTrue(prop instanceof Collection);
279         assertEquals(3, ((Collection) prop).size());
280         config.addProperty("tables.table(2).fields.field(0).name", "cid");
281         config.addProperty("tables.table(2).fields.field(-1).name",
282         "confName");
283         prop = config.getProperty("tables.table(2).fields.field.name");
284         assertNotNull(prop);
285         assertTrue(prop instanceof Collection);
286         assertEquals(2, ((Collection) prop).size());
287         assertEquals("confName",
288         config.getProperty("tables.table(2).fields.field(1).name"));
289         
290         config.addProperty("connection.user", "scott");
291         config.addProperty("connection.passwd", "tiger");
292         assertEquals("tiger", config.getProperty("connection.passwd"));
293         
294         ConfigurationKey key = new ConfigurationKey();
295         key.append("tables").append("table").appendIndex(0);
296         key.appendAttribute("tableType");
297         config.addProperty(key.toString(), "system");
298         assertEquals("system", config.getProperty(key.toString()));
299         
300         try
301         {
302             config.addProperty(".", "InvalidKey");
303             fail("Could add invalid key!");
304         }
305         catch(IllegalArgumentException iex)
306         {
307             //ok
308         }
309     }
310     
311     public void testGetMaxIndex()
312     {
313         assertEquals(4, config.getMaxIndex("tables.table(0).fields.field"));
314         assertEquals(4, config.getMaxIndex("tables.table(1).fields.field"));
315         assertEquals(1, config.getMaxIndex("tables.table"));
316         assertEquals(1, config.getMaxIndex("tables.table.name"));
317         assertEquals(0, config.getMaxIndex("tables.table(0).name"));
318         assertEquals(0, config.getMaxIndex("tables.table(1).fields.field(1)"));
319         assertEquals(-1, config.getMaxIndex("tables.table(2).fields"));
320         
321         int maxIdx = config.getMaxIndex("tables.table(0).fields.field.name");
322         for(int i = 0; i <= maxIdx; i++)
323         {
324             ConfigurationKey key = new ConfigurationKey("tables.table(0).fields");
325             key.append("field").appendIndex(i).append("name");
326             assertNotNull(config.getProperty(key.toString()));
327         }
328     }
329     
330     public void testSubset()
331     {
332         // test the subset on the first table
333         Configuration subset = config.subset("tables.table(0)");
334         assertEquals(tables[0], subset.getProperty("name"));
335 
336         Object prop = subset.getProperty("fields.field.name");
337         assertNotNull(prop);
338         assertTrue(prop instanceof Collection);
339         assertEquals(5, ((Collection) prop).size());
340         
341         for (int i = 0; i < fields[0].length; i++)
342         {
343             ConfigurationKey key = new ConfigurationKey();
344             key.append("fields").append("field").appendIndex(i);
345             key.append("name");
346             assertEquals(fields[0][i], subset.getProperty(key.toString()));
347         }
348 
349         // test the subset on the second table
350         assertTrue("subset is not empty", config.subset("tables.table(2)").isEmpty());
351 
352         // test the subset on the fields
353         subset = config.subset("tables.table.fields.field");
354         prop = subset.getProperty("name");
355         assertTrue("prop is not a collection", prop instanceof Collection);
356         assertEquals(10, ((Collection) prop).size());
357 
358         assertEquals(fields[0][0], subset.getProperty("name(0)"));
359 
360         // tset the subset on the field names
361         subset = config.subset("tables.table.fields.field.name");
362         assertTrue("subset is not empty", subset.isEmpty());
363     }
364     
365     public void testClone()
366     {
367         Configuration copy = (Configuration) config.clone();
368         assertTrue(copy instanceof HierarchicalConfiguration);
369         for (int i = 0; i < tables.length; i++)
370         {
371             assertEquals(tables[i], copy.getString("tables.table(" + i + ").name"));
372             for (int j = 0; j < fields[i].length; j++)
373             {
374                 assertEquals(fields[i][j], copy.getString("tables.table(" + i + ").fields.field(" + j + ").name"));
375             }
376         }
377     }
378     
379     public void testAddNodes()
380     {
381         Collection nodes = new ArrayList();
382         nodes.add(createFieldNode("birthDate"));
383         nodes.add(createFieldNode("lastLogin"));
384         nodes.add(createFieldNode("language"));
385         config.addNodes("tables.table(0).fields", nodes);
386         assertEquals(7, config.getMaxIndex("tables.table(0).fields.field"));
387         assertEquals("birthDate", config.getString("tables.table(0).fields.field(5).name"));
388         assertEquals("lastLogin", config.getString("tables.table(0).fields.field(6).name"));
389         assertEquals("language", config.getString("tables.table(0).fields.field(7).name"));
390         
391         try
392         {
393             config.addNodes(".", nodes);
394             fail("Could use empty key!");
395         }
396         catch(IllegalArgumentException iex)
397         {
398             //ok
399         }
400     }
401     
402     /***
403      * Tests removing children from a configuration node.
404      */
405     public void testNodeRemove()
406     {
407         HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(
408                 "parent", "test");
409         assertFalse(node.hasChildren());
410         node.removeChildren(); // should have no effect
411         assertFalse(node.remove("child"));
412         
413         node.addChild(createNode("test", "test"));
414         assertTrue(node.hasChildren());
415         assertTrue(node.remove("test"));
416         assertFalse(node.hasChildren());
417 
418         for (int i = 0; i < 10; i++)
419         {
420             node.addChild(createNode("child" + i, "test" + i));
421         }
422         assertTrue(node.hasChildren());
423         assertFalse(node.remove("child"));
424         assertTrue(node.remove("child2"));
425         assertTrue(node.getChildren("child2").isEmpty());
426 
427         HierarchicalConfiguration.Node child = createNode("child0", "testChild");
428         assertFalse(node.remove(child));
429         node.addChild(child);
430         assertTrue(node.remove(child));
431         assertEquals(1, node.getChildren("child0").size());
432         assertEquals("test0", ((HierarchicalConfiguration.Node) node
433                 .getChildren("child0").get(0)).getValue());
434 
435         assertTrue(node.remove("child0"));
436         assertFalse(node.remove(child));
437 
438         node.removeChildren();
439         assertTrue(node.getChildren().isEmpty());
440         assertFalse(node.remove(child));
441     }
442 
443     /***
444      * Tests the visitor mechanism.
445      */
446     public void testNodeVisitor()
447     {
448         CountVisitor v = new CountVisitor();
449         config.getRoot().visit(v, null);
450         assertEquals(28, v.beforeCount);
451         assertEquals(v.beforeCount, v.afterCount);
452     }
453     
454     /***
455      * Helper method for testing the getKeys(String) method.
456      * @param prefix the key to pass into getKeys()
457      * @param expected the expected result
458      */
459     private void checkKeys(String prefix, String[] expected)
460     {
461         Set values = new HashSet();
462         for(int i = 0; i < expected.length; i++)
463         {
464             values.add((expected[i].startsWith(prefix)) ? expected[i] :  prefix + "." + expected[i]);
465         }
466         
467         Iterator itKeys = config.getKeys(prefix);
468         while(itKeys.hasNext())
469         {
470             String key = (String) itKeys.next();
471             if(!values.contains(key))
472             {
473                 fail("Found unexpected key: " + key);
474             }
475             else
476             {
477                 values.remove(key);
478             }
479         }
480         
481         assertTrue("Remaining keys " + values, values.isEmpty());
482     }
483     
484     /***
485      * Helper method for creating a field node with its children.
486      * @param name the name of the field
487      * @return the field node
488      */
489     private static HierarchicalConfiguration.Node createFieldNode(String name)
490     {
491         HierarchicalConfiguration.Node fld = createNode("field", null);
492         fld.addChild(createNode("name", name));
493         return fld;
494     }
495     
496     /***
497      * Helper method for creating a configuration node.
498      * @param name the node's name
499      * @param value the node's value
500      * @return the new node
501      */
502     private static HierarchicalConfiguration.Node createNode(String name, Object value)
503     {
504         HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(name);
505         node.setValue(value);
506         return node;
507     }
508     
509     /***
510      * A test visitor implementation for checking whether all visitor methods
511      * are correctly called.
512      */
513     static class CountVisitor extends HierarchicalConfiguration.NodeVisitor
514     {
515         public int beforeCount;
516 
517         public int afterCount;
518 
519         public void visitAfterChildren(Node node, ConfigurationKey key)
520         {
521             super.visitAfterChildren(node, key);
522             afterCount++;
523         }
524 
525         public void visitBeforeChildren(Node node, ConfigurationKey key)
526         {
527             super.visitBeforeChildren(node, key);
528             beforeCount++;
529         }
530     }
531 }