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 018 package org.apache.commons.configuration; 019 020 import static org.junit.Assert.assertEquals; 021 import static org.junit.Assert.assertFalse; 022 import static org.junit.Assert.assertNotNull; 023 import static org.junit.Assert.assertNotSame; 024 import static org.junit.Assert.assertNull; 025 import static org.junit.Assert.assertSame; 026 import static org.junit.Assert.assertTrue; 027 import static org.junit.Assert.fail; 028 029 import java.util.ArrayList; 030 import java.util.Collection; 031 import java.util.HashSet; 032 import java.util.Iterator; 033 import java.util.List; 034 import java.util.Set; 035 036 import org.apache.commons.collections.CollectionUtils; 037 import org.apache.commons.configuration.HierarchicalConfiguration.Node; 038 import org.apache.commons.configuration.event.ConfigurationEvent; 039 import org.apache.commons.configuration.event.ConfigurationListener; 040 import org.apache.commons.configuration.tree.ConfigurationNode; 041 import org.apache.commons.configuration.tree.DefaultConfigurationKey; 042 import org.apache.commons.configuration.tree.DefaultConfigurationNode; 043 import org.apache.commons.configuration.tree.DefaultExpressionEngine; 044 import org.apache.commons.configuration.tree.ExpressionEngine; 045 import org.junit.Before; 046 import org.junit.Test; 047 048 /** 049 * Test class for HierarchicalConfiguration. 050 * 051 * @version $Id: TestHierarchicalConfiguration.java 1231749 2012-01-15 20:48:56Z oheger $ 052 */ 053 public class TestHierarchicalConfiguration 054 { 055 private static String[] tables = { "users", "documents" }; 056 057 private static String[][] fields = 058 { 059 { "uid", "uname", "firstName", "lastName", "email" }, 060 { "docid", "name", "creationDate", "authorID", "version" } 061 }; 062 063 private HierarchicalConfiguration config; 064 065 @Before 066 public void setUp() throws Exception 067 { 068 /** 069 * Initialize the configuration with the following structure: 070 * 071 * tables 072 * table 073 * name 074 * fields 075 * field 076 * name 077 * field 078 * name 079 */ 080 config = new HierarchicalConfiguration(); 081 HierarchicalConfiguration.Node nodeTables = createNode("tables", null); 082 for(int i = 0; i < tables.length; i++) 083 { 084 HierarchicalConfiguration.Node nodeTable = createNode("table", null); 085 nodeTables.addChild(nodeTable); 086 HierarchicalConfiguration.Node nodeName = createNode("name", tables[i]); 087 nodeTable.addChild(nodeName); 088 HierarchicalConfiguration.Node nodeFields = createNode("fields", null); 089 nodeTable.addChild(nodeFields); 090 091 for (int j = 0; j < fields[i].length; j++) 092 { 093 nodeFields.addChild(createFieldNode(fields[i][j])); 094 } 095 } 096 097 config.getRoot().addChild(nodeTables); 098 } 099 100 @Test 101 public void testSetRoot() 102 { 103 config.setRoot(new HierarchicalConfiguration.Node("test")); 104 assertTrue(config.isEmpty()); 105 } 106 107 @Test(expected = IllegalArgumentException.class) 108 public void testSetRootNull() 109 { 110 config.setRoot(null); 111 } 112 113 @Test 114 public void testSetRootNode() 115 { 116 config.setRootNode(new DefaultConfigurationNode("testNode")); 117 assertNotSame("Same root node", config.getRootNode(), config.getRoot()); 118 assertEquals("Wrong name of root node", "testNode", config.getRoot().getName()); 119 120 config.setRootNode(new HierarchicalConfiguration.Node("test")); 121 assertSame("Wrong root node", config.getRootNode(), config.getRoot()); 122 } 123 124 @Test(expected = IllegalArgumentException.class) 125 public void testSetRootNodeNull() 126 { 127 config.setRootNode(null); 128 } 129 130 @Test 131 public void testIsEmpty() 132 { 133 assertFalse(config.isEmpty()); 134 HierarchicalConfiguration conf2 = new HierarchicalConfiguration(); 135 assertTrue(conf2.isEmpty()); 136 HierarchicalConfiguration.Node child1 = new HierarchicalConfiguration.Node("child1"); 137 HierarchicalConfiguration.Node child2 = new HierarchicalConfiguration.Node("child2"); 138 child1.addChild(child2); 139 conf2.getRoot().addChild(child1); 140 assertTrue(conf2.isEmpty()); 141 } 142 143 @Test 144 public void testGetProperty() 145 { 146 assertNull(config.getProperty("tables.table.resultset")); 147 assertNull(config.getProperty("tables.table.fields.field")); 148 149 Object prop = config.getProperty("tables.table(0).fields.field.name"); 150 assertNotNull(prop); 151 assertTrue(prop instanceof Collection); 152 assertEquals(5, ((Collection<?>) prop).size()); 153 154 prop = config.getProperty("tables.table.fields.field.name"); 155 assertNotNull(prop); 156 assertTrue(prop instanceof Collection); 157 assertEquals(10, ((Collection<?>) prop).size()); 158 159 prop = config.getProperty("tables.table.fields.field(3).name"); 160 assertNotNull(prop); 161 assertTrue(prop instanceof Collection); 162 assertEquals(2, ((Collection<?>) prop).size()); 163 164 prop = config.getProperty("tables.table(1).fields.field(2).name"); 165 assertNotNull(prop); 166 assertEquals("creationDate", prop.toString()); 167 } 168 169 @Test 170 public void testSetProperty() 171 { 172 config.setProperty("tables.table(0).name", "resources"); 173 assertEquals("resources", config.getString("tables.table(0).name")); 174 config.setProperty("tables.table.name", "tab1,tab2"); 175 assertEquals("tab1", config.getString("tables.table(0).name")); 176 assertEquals("tab2", config.getString("tables.table(1).name")); 177 178 config.setProperty("test.items.item", new int[] { 2, 4, 8, 16 }); 179 assertEquals(3, config.getMaxIndex("test.items.item")); 180 assertEquals(8, config.getInt("test.items.item(2)")); 181 config.setProperty("test.items.item(2)", new Integer(6)); 182 assertEquals(6, config.getInt("test.items.item(2)")); 183 config.setProperty("test.items.item(2)", new int[] { 7, 9, 11 }); 184 assertEquals(5, config.getMaxIndex("test.items.item")); 185 186 config.setProperty("test", Boolean.TRUE); 187 config.setProperty("test.items", "01/01/05"); 188 assertEquals(5, config.getMaxIndex("test.items.item")); 189 assertTrue(config.getBoolean("test")); 190 assertEquals("01/01/05", config.getProperty("test.items")); 191 192 config.setProperty("test.items.item", new Integer(42)); 193 assertEquals(0, config.getMaxIndex("test.items.item")); 194 assertEquals(42, config.getInt("test.items.item")); 195 } 196 197 @Test 198 public void testClear() 199 { 200 config.setProperty(null, "value"); 201 config.addProperty("[@attr]", "defined"); 202 config.clear(); 203 assertTrue("Configuration not empty", config.isEmpty()); 204 } 205 206 @Test 207 public void testClearProperty() 208 { 209 config.clearProperty("tables.table(0).fields.field(0).name"); 210 assertEquals("uname", config.getProperty("tables.table(0).fields.field(0).name")); 211 config.clearProperty("tables.table(0).name"); 212 assertFalse(config.containsKey("tables.table(0).name")); 213 assertEquals("firstName", config.getProperty("tables.table(0).fields.field(1).name")); 214 assertEquals("documents", config.getProperty("tables.table.name")); 215 config.clearProperty("tables.table"); 216 assertEquals("documents", config.getProperty("tables.table.name")); 217 218 config.addProperty("test", "first"); 219 config.addProperty("test.level", "second"); 220 config.clearProperty("test"); 221 assertEquals("second", config.getString("test.level")); 222 assertFalse(config.containsKey("test")); 223 } 224 225 @Test 226 public void testClearTree() 227 { 228 Object prop = config.getProperty("tables.table(0).fields.field.name"); 229 assertNotNull(prop); 230 config.clearTree("tables.table(0).fields.field(3)"); 231 prop = config.getProperty("tables.table(0).fields.field.name"); 232 assertNotNull(prop); 233 assertTrue(prop instanceof Collection); 234 assertEquals(4, ((Collection<?>) prop).size()); 235 236 config.clearTree("tables.table(0).fields"); 237 assertNull(config.getProperty("tables.table(0).fields.field.name")); 238 prop = config.getProperty("tables.table.fields.field.name"); 239 assertNotNull(prop); 240 assertTrue(prop instanceof Collection); 241 assertEquals(5, ((Collection<?>) prop).size()); 242 243 config.clearTree("tables.table(1)"); 244 assertNull(config.getProperty("tables.table.fields.field.name")); 245 } 246 247 /** 248 * Tests removing more complex node structures. 249 */ 250 @Test 251 public void testClearTreeComplex() 252 { 253 final int count = 5; 254 // create the structure 255 for (int idx = 0; idx < count; idx++) 256 { 257 config.addProperty("indexList.index(-1)[@default]", Boolean.FALSE); 258 config.addProperty("indexList.index[@name]", "test" + idx); 259 config.addProperty("indexList.index.dir", "testDir" + idx); 260 } 261 assertEquals("Wrong number of nodes", count - 1, config 262 .getMaxIndex("indexList.index[@name]")); 263 264 // Remove a sub tree 265 boolean found = false; 266 for (int idx = 0; true; idx++) 267 { 268 String name = config.getString("indexList.index(" + idx 269 + ")[@name]"); 270 if (name == null) 271 { 272 break; 273 } 274 if ("test3".equals(name)) 275 { 276 assertEquals("Wrong dir", "testDir3", config 277 .getString("indexList.index(" + idx + ").dir")); 278 config.clearTree("indexList.index(" + idx + ")"); 279 found = true; 280 } 281 } 282 assertTrue("Key to remove not found", found); 283 assertEquals("Wrong number of nodes after remove", count - 2, config 284 .getMaxIndex("indexList.index[@name]")); 285 assertEquals("Wrong number of dir nodes after remove", count - 2, 286 config.getMaxIndex("indexList.index.dir")); 287 288 // Verify 289 for (int idx = 0; true; idx++) 290 { 291 String name = config.getString("indexList.index(" + idx 292 + ")[@name]"); 293 if (name == null) 294 { 295 break; 296 } 297 if ("test3".equals(name)) 298 { 299 fail("Key was not removed!"); 300 } 301 } 302 } 303 304 /** 305 * Tests the clearTree() method on a hierarchical structure of nodes. This 306 * is a test case for CONFIGURATION-293. 307 */ 308 @Test 309 public void testClearTreeHierarchy() 310 { 311 config.addProperty("a.b.c", "c"); 312 config.addProperty("a.b.c.d", "d"); 313 config.addProperty("a.b.c.d.e", "e"); 314 config.clearTree("a.b.c"); 315 assertFalse("Property not removed", config.containsKey("a.b.c")); 316 assertFalse("Sub property not removed", config.containsKey("a.b.c.d")); 317 } 318 319 @Test 320 public void testContainsKey() 321 { 322 assertTrue(config.containsKey("tables.table(0).name")); 323 assertTrue(config.containsKey("tables.table(1).name")); 324 assertFalse(config.containsKey("tables.table(2).name")); 325 326 assertTrue(config.containsKey("tables.table(0).fields.field.name")); 327 assertFalse(config.containsKey("tables.table(0).fields.field")); 328 config.clearTree("tables.table(0).fields"); 329 assertFalse(config.containsKey("tables.table(0).fields.field.name")); 330 331 assertTrue(config.containsKey("tables.table.fields.field.name")); 332 } 333 334 @Test 335 public void testGetKeys() 336 { 337 List<String> keys = new ArrayList<String>(); 338 for (Iterator<String> it = config.getKeys(); it.hasNext();) 339 { 340 keys.add(it.next()); 341 } 342 343 assertEquals(2, keys.size()); 344 assertTrue(keys.contains("tables.table.name")); 345 assertTrue(keys.contains("tables.table.fields.field.name")); 346 347 // test the order of the keys returned 348 config.addProperty("order.key1", "value1"); 349 config.addProperty("order.key2", "value2"); 350 config.addProperty("order.key3", "value3"); 351 352 Iterator<String> it = config.getKeys("order"); 353 assertEquals("1st key", "order.key1", it.next()); 354 assertEquals("2nd key", "order.key2", it.next()); 355 assertEquals("3rd key", "order.key3", it.next()); 356 } 357 358 @Test 359 public void testGetKeysString() 360 { 361 // add some more properties to make it more interesting 362 config.addProperty("tables.table(0).fields.field(1).type", "VARCHAR"); 363 config.addProperty("tables.table(0)[@type]", "system"); 364 config.addProperty("tables.table(0).size", "42"); 365 config.addProperty("tables.table(0).fields.field(0).size", "128"); 366 config.addProperty("connections.connection.param.url", "url1"); 367 config.addProperty("connections.connection.param.user", "me"); 368 config.addProperty("connections.connection.param.pwd", "secret"); 369 config.addProperty("connections.connection(-1).param.url", "url2"); 370 config.addProperty("connections.connection(1).param.user", "guest"); 371 372 checkKeys("tables.table(1)", new String[] { "name", "fields.field.name" }); 373 checkKeys("tables.table(0)", 374 new String[] { "name", "fields.field.name", "tables.table(0)[@type]", "size", "fields.field.type", "fields.field.size" }); 375 checkKeys("connections.connection(0).param", 376 new String[] {"url", "user", "pwd" }); 377 checkKeys("connections.connection(1).param", 378 new String[] {"url", "user" }); 379 } 380 381 /** 382 * Tests getKeys() with a prefix when the prefix matches exactly a key. 383 */ 384 @Test 385 public void testGetKeysWithKeyAsPrefix() 386 { 387 config.addProperty("order.key1", "value1"); 388 config.addProperty("order.key2", "value2"); 389 Iterator<String> it = config.getKeys("order.key1"); 390 assertTrue("no key found", it.hasNext()); 391 assertEquals("1st key", "order.key1", it.next()); 392 assertFalse("more keys than expected", it.hasNext()); 393 } 394 395 /** 396 * Tests getKeys() with a prefix when the prefix matches exactly a key, and 397 * there are multiple keys starting with this prefix. 398 */ 399 @Test 400 public void testGetKeysWithKeyAsPrefixMultiple() 401 { 402 config.addProperty("order.key1", "value1"); 403 config.addProperty("order.key1.test", "value2"); 404 config.addProperty("order.key1.test.complex", "value2"); 405 Iterator<String> it = config.getKeys("order.key1"); 406 assertEquals("Wrong key 1", "order.key1", it.next()); 407 assertEquals("Wrong key 2", "order.key1.test", it.next()); 408 assertEquals("Wrong key 3", "order.key1.test.complex", it.next()); 409 assertFalse("More keys than expected", it.hasNext()); 410 } 411 412 @Test 413 public void testAddProperty() 414 { 415 config.addProperty("tables.table(0).fields.field(-1).name", "phone"); 416 Object prop = config.getProperty("tables.table(0).fields.field.name"); 417 assertNotNull(prop); 418 assertTrue(prop instanceof Collection); 419 assertEquals(6, ((Collection<?>) prop).size()); 420 421 config.addProperty("tables.table(0).fields.field.name", "fax"); 422 prop = config.getProperty("tables.table.fields.field(5).name"); 423 assertNotNull(prop); 424 assertTrue(prop instanceof List); 425 List<?> list = (List<?>) prop; 426 assertEquals("phone", list.get(0)); 427 assertEquals("fax", list.get(1)); 428 429 config.addProperty("tables.table(-1).name", "config"); 430 prop = config.getProperty("tables.table.name"); 431 assertNotNull(prop); 432 assertTrue(prop instanceof Collection); 433 assertEquals(3, ((Collection<?>) prop).size()); 434 config.addProperty("tables.table(2).fields.field(0).name", "cid"); 435 config.addProperty("tables.table(2).fields.field(-1).name", 436 "confName"); 437 prop = config.getProperty("tables.table(2).fields.field.name"); 438 assertNotNull(prop); 439 assertTrue(prop instanceof Collection); 440 assertEquals(2, ((Collection<?>) prop).size()); 441 assertEquals("confName", 442 config.getProperty("tables.table(2).fields.field(1).name")); 443 444 config.addProperty("connection.user", "scott"); 445 config.addProperty("connection.passwd", "tiger"); 446 assertEquals("tiger", config.getProperty("connection.passwd")); 447 448 DefaultConfigurationKey key = createConfigurationKey(); 449 key.append("tables").append("table").appendIndex(0); 450 key.appendAttribute("tableType"); 451 config.addProperty(key.toString(), "system"); 452 assertEquals("system", config.getProperty(key.toString())); 453 } 454 455 /** 456 * Creates a {@code DefaultConfigurationKey} object. 457 * 458 * @return the new key object 459 */ 460 private static DefaultConfigurationKey createConfigurationKey() 461 { 462 return new DefaultConfigurationKey(new DefaultExpressionEngine()); 463 } 464 465 @Test(expected = IllegalArgumentException.class) 466 public void testAddPropertyInvalidKey() 467 { 468 config.addProperty(".", "InvalidKey"); 469 } 470 471 @Test 472 public void testGetMaxIndex() 473 { 474 assertEquals(4, config.getMaxIndex("tables.table(0).fields.field")); 475 assertEquals(4, config.getMaxIndex("tables.table(1).fields.field")); 476 assertEquals(1, config.getMaxIndex("tables.table")); 477 assertEquals(1, config.getMaxIndex("tables.table.name")); 478 assertEquals(0, config.getMaxIndex("tables.table(0).name")); 479 assertEquals(0, config.getMaxIndex("tables.table(1).fields.field(1)")); 480 assertEquals(-1, config.getMaxIndex("tables.table(2).fields")); 481 482 int maxIdx = config.getMaxIndex("tables.table(0).fields.field.name"); 483 for(int i = 0; i <= maxIdx; i++) 484 { 485 DefaultConfigurationKey key = 486 new DefaultConfigurationKey(new DefaultExpressionEngine(), 487 "tables.table(0).fields"); 488 key.append("field").appendIndex(i).append("name"); 489 assertNotNull(config.getProperty(key.toString())); 490 } 491 } 492 493 @Test 494 public void testSubset() 495 { 496 // test the subset on the first table 497 Configuration subset = config.subset("tables.table(0)"); 498 assertEquals(tables[0], subset.getProperty("name")); 499 500 Object prop = subset.getProperty("fields.field.name"); 501 assertNotNull(prop); 502 assertTrue(prop instanceof Collection); 503 assertEquals(5, ((Collection<?>) prop).size()); 504 505 for (int i = 0; i < fields[0].length; i++) 506 { 507 DefaultConfigurationKey key = createConfigurationKey(); 508 key.append("fields").append("field").appendIndex(i); 509 key.append("name"); 510 assertEquals(fields[0][i], subset.getProperty(key.toString())); 511 } 512 513 // test the subset on the second table 514 assertTrue("subset is not empty", config.subset("tables.table(2)").isEmpty()); 515 516 // test the subset on the fields 517 subset = config.subset("tables.table.fields.field"); 518 prop = subset.getProperty("name"); 519 assertTrue("prop is not a collection", prop instanceof Collection); 520 assertEquals(10, ((Collection<?>) prop).size()); 521 522 assertEquals(fields[0][0], subset.getProperty("name(0)")); 523 524 // test the subset on the field names 525 subset = config.subset("tables.table.fields.field.name"); 526 assertTrue("subset is not empty", subset.isEmpty()); 527 } 528 529 /** 530 * Tests the subset() method when the specified node has a value. This value 531 * must be available in the subset, too. Related to CONFIGURATION-295. 532 */ 533 @Test 534 public void testSubsetNodeWithValue() 535 { 536 config.setProperty("tables.table(0).fields", "My fields"); 537 Configuration subset = config.subset("tables.table(0).fields"); 538 assertEquals("Wrong field name", fields[0][0], subset 539 .getString("field(0).name")); 540 assertEquals("Wrong value of root", "My fields", subset.getString("")); 541 } 542 543 /** 544 * Tests the subset() method when the specified key selects multiple keys. 545 * The resulting root node should have a value only if exactly one of the 546 * selected nodes has a value. Related to CONFIGURATION-295. 547 */ 548 @Test 549 public void testSubsetMultipleNodesWithValues() 550 { 551 config.setProperty("tables.table(0).fields", "My fields"); 552 Configuration subset = config.subset("tables.table.fields"); 553 assertEquals("Wrong value of root", "My fields", subset.getString("")); 554 config.setProperty("tables.table(1).fields", "My other fields"); 555 subset = config.subset("tables.table.fields"); 556 assertNull("Root value is not null though there are multiple values", 557 subset.getString("")); 558 } 559 560 /** 561 * Tests the configurationAt() method to obtain a configuration for a sub 562 * tree. 563 */ 564 @Test 565 public void testConfigurationAt() 566 { 567 HierarchicalConfiguration subConfig = config 568 .configurationAt("tables.table(1)"); 569 assertEquals("Wrong table name", tables[1], subConfig.getString("name")); 570 List<Object> lstFlds = subConfig.getList("fields.field.name"); 571 assertEquals("Wrong number of fields", fields[1].length, lstFlds.size()); 572 for (int i = 0; i < fields[1].length; i++) 573 { 574 assertEquals("Wrong field at position " + i, fields[1][i], lstFlds 575 .get(i)); 576 } 577 578 subConfig.setProperty("name", "testTable"); 579 assertEquals("Change not visible in parent", "testTable", config 580 .getString("tables.table(1).name")); 581 config.setProperty("tables.table(1).fields.field(2).name", "testField"); 582 assertEquals("Change not visible in sub config", "testField", subConfig 583 .getString("fields.field(2).name")); 584 } 585 586 /** 587 * Tests the configurationAt() method when the passed in key does not exist. 588 */ 589 @Test(expected = IllegalArgumentException.class) 590 public void testConfigurationAtUnknownSubTree() 591 { 592 config.configurationAt("non.existing.key"); 593 } 594 595 /** 596 * Tests the configurationAt() method when the passed in key selects 597 * multiple nodes. This should cause an exception. 598 */ 599 @Test(expected = IllegalArgumentException.class) 600 public void testConfigurationAtMultipleNodes() 601 { 602 config.configurationAt("tables.table.name"); 603 } 604 605 /** 606 * Tests whether a sub configuration obtained by configurationAt() can be 607 * cleared. 608 */ 609 @Test 610 public void testConfigurationAtClear() 611 { 612 config.addProperty("test.sub.test", "fail"); 613 assertEquals("Wrong index (1)", 0, config.getMaxIndex("test")); 614 SubnodeConfiguration sub = config.configurationAt("test.sub"); 615 assertEquals("Wrong value", "fail", sub.getString("test")); 616 sub.clear(); 617 assertNull("Key still found", config.getString("test.sub.key")); 618 sub.setProperty("test", "success"); 619 assertEquals("Property not set", "success", 620 config.getString("test.sub.test")); 621 assertEquals("Wrong index (2)", 0, config.getMaxIndex("test")); 622 } 623 624 /** 625 * Tests the configurationsAt() method. 626 */ 627 @Test 628 public void testConfigurationsAt() 629 { 630 List<HierarchicalConfiguration> lstFlds = config.configurationsAt("tables.table(1).fields.field"); 631 assertEquals("Wrong size of fields", fields[1].length, lstFlds.size()); 632 for (int i = 0; i < fields[1].length; i++) 633 { 634 HierarchicalConfiguration sub = lstFlds.get(i); 635 assertEquals("Wrong field at position " + i, fields[1][i], sub 636 .getString("name")); 637 } 638 } 639 640 /** 641 * Tests the configurationsAt() method when the passed in key does not 642 * select any sub nodes. 643 */ 644 @Test 645 public void testConfigurationsAtEmpty() 646 { 647 assertTrue("List is not empty", config.configurationsAt("unknown.key") 648 .isEmpty()); 649 } 650 651 @Test 652 public void testClone() 653 { 654 Configuration copy = (Configuration) config.clone(); 655 assertTrue(copy instanceof HierarchicalConfiguration); 656 checkContent(copy); 657 } 658 659 /** 660 * Tests whether registered event handlers are handled correctly when a 661 * configuration is cloned. They should not be registered at the clone. 662 */ 663 @Test 664 public void testCloneWithEventListeners() 665 { 666 config.addConfigurationListener(new ConfigurationListener() 667 { 668 public void configurationChanged(ConfigurationEvent event) 669 { 670 // just a dummy 671 } 672 }); 673 HierarchicalConfiguration copy = (HierarchicalConfiguration) config 674 .clone(); 675 assertTrue("Event listener registered at clone", copy 676 .getConfigurationListeners().isEmpty()); 677 } 678 679 @Test 680 public void testAddNodes() 681 { 682 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); 683 nodes.add(createFieldNode("birthDate")); 684 nodes.add(createFieldNode("lastLogin")); 685 nodes.add(createFieldNode("language")); 686 config.addNodes("tables.table(0).fields", nodes); 687 assertEquals(7, config.getMaxIndex("tables.table(0).fields.field")); 688 assertEquals("birthDate", config.getString("tables.table(0).fields.field(5).name")); 689 assertEquals("lastLogin", config.getString("tables.table(0).fields.field(6).name")); 690 assertEquals("language", config.getString("tables.table(0).fields.field(7).name")); 691 } 692 693 /** 694 * Tests the addNodes() method when the provided key does not exist. In 695 * this case, a new node (or even a complete new branch) will be created. 696 */ 697 @Test 698 public void testAddNodesForNonExistingKey() 699 { 700 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); 701 nodes.add(createNode("usr", "scott")); 702 Node nd = createNode("pwd", "tiger"); 703 nd.setAttribute(true); 704 nodes.add(nd); 705 config.addNodes("database.connection.settings", nodes); 706 707 assertEquals("Usr node not found", "scott", config.getString("database.connection.settings.usr")); 708 assertEquals("Pwd node not found", "tiger", config.getString("database.connection.settings[@pwd]")); 709 } 710 711 /** 712 * Tests the addNodes() method when the new nodes should be added to an 713 * attribute node. This is not allowed. 714 */ 715 @Test(expected = IllegalArgumentException.class) 716 public void testAddNodesWithAttributeKey() 717 { 718 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); 719 nodes.add(createNode("testNode", "yes")); 720 config.addNodes("database.connection[@settings]", nodes); 721 } 722 723 /** 724 * Tests copying nodes from one configuration to another one. 725 */ 726 @Test 727 public void testAddNodesCopy() 728 { 729 HierarchicalConfiguration configDest = new HierarchicalConfiguration(); 730 configDest.addProperty("test", "TEST"); 731 Collection<ConfigurationNode> nodes = config.getRootNode().getChildren(); 732 assertEquals("Wrong number of children", 1, nodes.size()); 733 configDest.addNodes("newNodes", nodes); 734 for (int i = 0; i < tables.length; i++) 735 { 736 String keyTab = "newNodes.tables.table(" + i + ")."; 737 assertEquals("Table " + i + " not found", tables[i], configDest 738 .getString(keyTab + "name")); 739 for (int j = 0; j < fields[i].length; j++) 740 { 741 assertEquals("Invalid field " + j + " in table " + i, 742 fields[i][j], configDest.getString(keyTab 743 + "fields.field(" + j + ").name")); 744 } 745 } 746 } 747 748 /** 749 * Tests adding an attribute node with the addNodes() method. 750 */ 751 @Test 752 public void testAddNodesAttributeNode() 753 { 754 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); 755 ConfigurationNode nd = createNode("length", "10"); 756 nd.setAttribute(true); 757 nodes.add(nd); 758 config.addNodes("tables.table(0).fields.field(1)", nodes); 759 assertEquals("Attribute was not added", "10", config 760 .getString("tables.table(0).fields.field(1)[@length]")); 761 } 762 763 /** 764 * Tests removing children from a configuration node. 765 */ 766 @Test 767 public void testNodeRemove() 768 { 769 HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node( 770 "parent", "test"); 771 assertFalse(node.hasChildren()); 772 node.removeChildren(); // should have no effect 773 assertFalse(node.remove("child")); 774 775 node.addChild(createNode("test", "test")); 776 assertTrue(node.hasChildren()); 777 assertTrue(node.remove("test")); 778 assertFalse(node.hasChildren()); 779 780 for (int i = 0; i < 10; i++) 781 { 782 node.addChild(createNode("child" + i, "test" + i)); 783 } 784 assertTrue(node.hasChildren()); 785 assertFalse(node.remove("child")); 786 assertTrue(node.remove("child2")); 787 assertTrue(node.getChildren("child2").isEmpty()); 788 789 HierarchicalConfiguration.Node child = createNode("child0", "testChild"); 790 assertFalse(node.remove(child)); 791 node.addChild(child); 792 assertTrue(node.remove(child)); 793 assertEquals(1, node.getChildren("child0").size()); 794 assertEquals("test0", ((HierarchicalConfiguration.Node) node 795 .getChildren("child0").get(0)).getValue()); 796 797 assertTrue(node.remove("child0")); 798 assertFalse(node.remove(child)); 799 800 node.removeChildren(); 801 assertTrue(node.getChildren().isEmpty()); 802 assertFalse(node.remove(child)); 803 } 804 805 /** 806 * Tests the visitor mechanism. 807 */ 808 @Test 809 public void testNodeVisitor() 810 { 811 CountVisitor v = new CountVisitor(); 812 config.getRoot().visit(v, null); 813 assertEquals("Wrong number of visits", 28, v.beforeCount); 814 assertEquals("Different number of before and after visits", 815 v.beforeCount, v.afterCount); 816 } 817 818 /** 819 * Tests the visitor mechanism if a ConfigurationKey is passed in. 820 */ 821 @Test 822 public void testNodeVisitorKeys() 823 { 824 CountVisitor v = new CountVisitor(); 825 @SuppressWarnings("deprecation") 826 ConfigurationKey configKey = new ConfigurationKey(); 827 config.getRoot().visit(v, configKey); 828 for (Iterator<String> it = config.getKeys(); it.hasNext();) 829 { 830 String key = it.next(); 831 assertTrue("Key not found in before keys: " + key, v.beforeKeys 832 .contains(key)); 833 assertTrue("Key not found in after keys: " + key, v.afterKeys 834 .contains(key)); 835 } 836 } 837 838 /** 839 * Tests setting a custom expression engine, which uses a slightly different 840 * syntax. 841 */ 842 @Test 843 public void testSetExpressionEngine() 844 { 845 config.setExpressionEngine(null); 846 assertNotNull("Expression engine is null", config.getExpressionEngine()); 847 assertSame("Default engine is not used", HierarchicalConfiguration 848 .getDefaultExpressionEngine(), config.getExpressionEngine()); 849 850 config.setExpressionEngine(createAlternativeExpressionEngine()); 851 checkAlternativeSyntax(); 852 } 853 854 /** 855 * Tests setting the default expression engine. This should impact all 856 * configuration instances that do not have their own engine. 857 */ 858 @Test 859 public void testSetDefaultExpressionEngine() 860 { 861 ExpressionEngine engineOld = HierarchicalConfiguration.getDefaultExpressionEngine(); 862 HierarchicalConfiguration 863 .setDefaultExpressionEngine(createAlternativeExpressionEngine()); 864 checkAlternativeSyntax(); 865 HierarchicalConfiguration.setDefaultExpressionEngine(engineOld); 866 } 867 868 /** 869 * Tests setting the default expression engine to null. This should not be 870 * allowed. 871 */ 872 @Test(expected = IllegalArgumentException.class) 873 public void testSetDefaultExpressionEngineNull() 874 { 875 HierarchicalConfiguration.setDefaultExpressionEngine(null); 876 } 877 878 /** 879 * Tests the copy constructor. 880 */ 881 @Test 882 public void testInitCopy() 883 { 884 HierarchicalConfiguration copy = new HierarchicalConfiguration(config); 885 checkContent(copy); 886 } 887 888 /** 889 * Tests whether the nodes of a copied configuration are independent from 890 * the source configuration. 891 */ 892 @Test 893 public void testInitCopyUpdate() 894 { 895 HierarchicalConfiguration copy = new HierarchicalConfiguration(config); 896 config.setProperty("tables.table(0).name", "NewTable"); 897 checkContent(copy); 898 } 899 900 /** 901 * Tests interpolation facilities. 902 */ 903 @Test 904 public void testInterpolation() 905 { 906 config.addProperty("base.dir", "/home/foo"); 907 config.addProperty("test.absolute.dir.dir1", "${base.dir}/path1"); 908 config.addProperty("test.absolute.dir.dir2", "${base.dir}/path2"); 909 config.addProperty("test.absolute.dir.dir3", "${base.dir}/path3"); 910 911 Configuration sub = config.subset("test.absolute.dir"); 912 for (int i = 1; i < 4; i++) 913 { 914 assertEquals("Wrong interpolation in parent", "/home/foo/path" + i, 915 config.getString("test.absolute.dir.dir" + i)); 916 assertEquals("Wrong interpolation in subnode", 917 "/home/foo/path" + i, sub.getString("dir" + i)); 918 } 919 } 920 921 /** 922 * Basic interpolation tests. 923 */ 924 @Test 925 public void testInterpolationBasic() 926 { 927 InterpolationTestHelper.testInterpolation(config); 928 } 929 930 /** 931 * Tests multiple levels of interpolation. 932 */ 933 @Test 934 public void testInterpolationMultipleLevels() 935 { 936 InterpolationTestHelper.testMultipleInterpolation(config); 937 } 938 939 /** 940 * Tests an invalid interpolation that causes an endless loop. 941 */ 942 @Test 943 public void testInterpolationLoop() 944 { 945 InterpolationTestHelper.testInterpolationLoop(config); 946 } 947 948 /** 949 * Tests interpolation with a subset. 950 */ 951 @Test 952 public void testInterpolationSubset() 953 { 954 InterpolationTestHelper.testInterpolationSubset(config); 955 } 956 957 /** 958 * Tests whether interpolation with a subset configuration works over 959 * multiple layers. 960 */ 961 @Test 962 public void testInterpolationSubsetMultipleLayers() 963 { 964 config.clear(); 965 config.addProperty("var", "value"); 966 config.addProperty("prop2.prop[@attr]", "${var}"); 967 Configuration sub1 = config.subset("prop2"); 968 Configuration sub2 = sub1.subset("prop"); 969 assertEquals("Wrong value", "value", sub2.getString("[@attr]")); 970 } 971 972 /** 973 * Tests interpolation of a variable, which cannot be resolved. 974 */ 975 @Test 976 public void testInterpolationUnknownProperty() 977 { 978 InterpolationTestHelper.testInterpolationUnknownProperty(config); 979 } 980 981 /** 982 * Tests interpolation with system properties. 983 */ 984 @Test 985 public void testInterpolationSysProperties() 986 { 987 InterpolationTestHelper.testInterpolationSystemProperties(config); 988 } 989 990 /** 991 * Tests interpolation with constant values. 992 */ 993 @Test 994 public void testInterpolationConstants() 995 { 996 InterpolationTestHelper.testInterpolationConstants(config); 997 } 998 999 /** 1000 * Tests escaping variables. 1001 */ 1002 @Test 1003 public void testInterpolationEscaped() 1004 { 1005 InterpolationTestHelper.testInterpolationEscaped(config); 1006 } 1007 1008 /** 1009 * Tests manipulating the interpolator. 1010 */ 1011 @Test 1012 public void testInterpolator() 1013 { 1014 InterpolationTestHelper.testGetInterpolator(config); 1015 } 1016 1017 /** 1018 * Tests obtaining a configuration with all variables substituted. 1019 */ 1020 @Test 1021 public void testInterpolatedConfiguration() 1022 { 1023 HierarchicalConfiguration c = (HierarchicalConfiguration) InterpolationTestHelper 1024 .testInterpolatedConfiguration(config); 1025 1026 // tests whether the hierarchical structure has been maintained 1027 config = c; 1028 testGetProperty(); 1029 } 1030 1031 /** 1032 * Tests the copy constructor when a null reference is passed. 1033 */ 1034 @Test 1035 public void testInitCopyNull() 1036 { 1037 HierarchicalConfiguration copy = new HierarchicalConfiguration(null); 1038 assertTrue("Configuration not empty", copy.isEmpty()); 1039 } 1040 1041 /** 1042 * Tests the parents of nodes when setRootNode() is involved. This is 1043 * related to CONFIGURATION-334. 1044 */ 1045 @Test 1046 public void testNodeParentsAfterSetRootNode() 1047 { 1048 DefaultConfigurationNode root = new DefaultConfigurationNode(); 1049 DefaultConfigurationNode child1 = new DefaultConfigurationNode( 1050 "child1", "test1"); 1051 root.addChild(child1); 1052 config.setRootNode(root); 1053 config.addProperty("child2", "test2"); 1054 List<ConfigurationNode> nodes = config.getExpressionEngine().query(config.getRootNode(), 1055 "child2"); 1056 assertEquals("Wrong number of result nodes", 1, nodes.size()); 1057 ConfigurationNode child2 = nodes.get(0); 1058 assertEquals("Different parent nodes", child1.getParentNode(), child2 1059 .getParentNode()); 1060 } 1061 1062 /** 1063 * Tests calling getRoot() after a root node was set using setRootNode() and 1064 * further child nodes have been added. The newly add child nodes should be 1065 * present in the root node returned. 1066 */ 1067 @Test 1068 public void testGetRootAfterSetRootNode() 1069 { 1070 DefaultConfigurationNode root = new DefaultConfigurationNode(); 1071 DefaultConfigurationNode child1 = new DefaultConfigurationNode( 1072 "child1", "test1"); 1073 root.addChild(child1); 1074 config.setRootNode(root); 1075 config.addProperty("child2", "test2"); 1076 ConfigurationNode oldRoot = config.getRoot(); 1077 assertEquals("Wrong number of children", 2, oldRoot.getChildrenCount()); 1078 } 1079 1080 /** 1081 * Tests whether keys that contains brackets can be used. 1082 */ 1083 @Test 1084 public void testGetPropertyKeyWithBrackets() 1085 { 1086 final String key = "test.directory.platform(x86)"; 1087 config.addProperty(key, "C:\\Temp"); 1088 assertEquals("Wrong property value", "C:\\Temp", config.getString(key)); 1089 } 1090 1091 /** 1092 * Helper method for testing the getKeys(String) method. 1093 * 1094 * @param prefix the key to pass into getKeys() 1095 * @param expected the expected result 1096 */ 1097 private void checkKeys(String prefix, String[] expected) 1098 { 1099 Set<String> values = new HashSet<String>(); 1100 for(int i = 0; i < expected.length; i++) 1101 { 1102 values.add((expected[i].startsWith(prefix)) ? expected[i] : prefix + "." + expected[i]); 1103 } 1104 1105 Iterator<String> itKeys = config.getKeys(prefix); 1106 while(itKeys.hasNext()) 1107 { 1108 String key = itKeys.next(); 1109 if(!values.contains(key)) 1110 { 1111 fail("Found unexpected key: " + key); 1112 } 1113 else 1114 { 1115 values.remove(key); 1116 } 1117 } 1118 1119 assertTrue("Remaining keys " + values, values.isEmpty()); 1120 } 1121 1122 /** 1123 * Helper method for checking keys using an alternative syntax. 1124 */ 1125 private void checkAlternativeSyntax() 1126 { 1127 assertNull(config.getProperty("tables/table/resultset")); 1128 assertNull(config.getProperty("tables/table/fields/field")); 1129 1130 Object prop = config.getProperty("tables/table[0]/fields/field/name"); 1131 assertNotNull(prop); 1132 assertTrue(prop instanceof Collection); 1133 assertEquals(5, ((Collection<?>) prop).size()); 1134 1135 prop = config.getProperty("tables/table/fields/field/name"); 1136 assertNotNull(prop); 1137 assertTrue(prop instanceof Collection); 1138 assertEquals(10, ((Collection<?>) prop).size()); 1139 1140 prop = config.getProperty("tables/table/fields/field[3]/name"); 1141 assertNotNull(prop); 1142 assertTrue(prop instanceof Collection); 1143 assertEquals(2, ((Collection<?>) prop).size()); 1144 1145 prop = config.getProperty("tables/table[1]/fields/field[2]/name"); 1146 assertNotNull(prop); 1147 assertEquals("creationDate", prop.toString()); 1148 1149 Set<String> keys = new HashSet<String>(); 1150 CollectionUtils.addAll(keys, config.getKeys()); 1151 assertEquals("Wrong number of defined keys", 2, keys.size()); 1152 assertTrue("Key not found", keys.contains("tables/table/name")); 1153 assertTrue("Key not found", keys 1154 .contains("tables/table/fields/field/name")); 1155 } 1156 1157 /** 1158 * Checks the content of the passed in configuration object. Used by some 1159 * tests that copy a configuration. 1160 * 1161 * @param c the configuration to check 1162 */ 1163 private void checkContent(Configuration c) 1164 { 1165 for (int i = 0; i < tables.length; i++) 1166 { 1167 assertEquals(tables[i], c.getString("tables.table(" + i + ").name")); 1168 for (int j = 0; j < fields[i].length; j++) 1169 { 1170 assertEquals(fields[i][j], c.getString("tables.table(" + i 1171 + ").fields.field(" + j + ").name")); 1172 } 1173 } 1174 } 1175 1176 private ExpressionEngine createAlternativeExpressionEngine() 1177 { 1178 DefaultExpressionEngine engine = new DefaultExpressionEngine(); 1179 engine.setPropertyDelimiter("/"); 1180 engine.setIndexStart("["); 1181 engine.setIndexEnd("]"); 1182 return engine; 1183 } 1184 1185 /** 1186 * Helper method for creating a field node with its children. 1187 * 1188 * @param name the name of the field 1189 * @return the field node 1190 */ 1191 private static HierarchicalConfiguration.Node createFieldNode(String name) 1192 { 1193 HierarchicalConfiguration.Node fld = createNode("field", null); 1194 fld.addChild(createNode("name", name)); 1195 return fld; 1196 } 1197 1198 /** 1199 * Helper method for creating a configuration node. 1200 * @param name the node's name 1201 * @param value the node's value 1202 * @return the new node 1203 */ 1204 private static HierarchicalConfiguration.Node createNode(String name, Object value) 1205 { 1206 HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(name); 1207 node.setValue(value); 1208 return node; 1209 } 1210 1211 /** 1212 * A test visitor implementation for checking whether all visitor methods 1213 * are correctly called. 1214 */ 1215 @SuppressWarnings("deprecation") 1216 static class CountVisitor extends HierarchicalConfiguration.NodeVisitor 1217 { 1218 /** The number of invocations of visitBeforeChildren(). */ 1219 int beforeCount; 1220 1221 /** The number of invocations of visitAfterChildren(). */ 1222 int afterCount; 1223 1224 /** A set with the keys passed to visitBeforeChildren(). */ 1225 final Set<String> beforeKeys = new HashSet<String>(); 1226 1227 /** A set with the keys passed to visitAfterChildren(). */ 1228 final Set<String> afterKeys = new HashSet<String>(); 1229 1230 @Override 1231 public void visitAfterChildren(Node node, ConfigurationKey key) 1232 { 1233 super.visitAfterChildren(node, key); 1234 afterCount++; 1235 if (key != null) 1236 { 1237 afterKeys.add(key.toString()); 1238 } 1239 } 1240 1241 @Override 1242 public void visitBeforeChildren(Node node, ConfigurationKey key) 1243 { 1244 super.visitBeforeChildren(node, key); 1245 beforeCount++; 1246 if (key != null) 1247 { 1248 beforeKeys.add(key.toString()); 1249 } 1250 } 1251 } 1252 }