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.assertNull; 024 import static org.junit.Assert.assertTrue; 025 import static org.junit.Assert.fail; 026 027 import java.io.ByteArrayInputStream; 028 import java.io.File; 029 import java.io.FileOutputStream; 030 import java.io.FileWriter; 031 import java.io.IOException; 032 import java.io.PrintWriter; 033 import java.io.StringReader; 034 import java.io.StringWriter; 035 import java.net.URL; 036 import java.util.ArrayList; 037 import java.util.Arrays; 038 import java.util.Collection; 039 import java.util.Iterator; 040 import java.util.List; 041 042 import javax.xml.parsers.DocumentBuilder; 043 import javax.xml.parsers.DocumentBuilderFactory; 044 import javax.xml.parsers.ParserConfigurationException; 045 046 import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; 047 import org.apache.commons.configuration.reloading.InvariantReloadingStrategy; 048 import org.apache.commons.configuration.resolver.CatalogResolver; 049 import org.apache.commons.configuration.tree.ConfigurationNode; 050 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; 051 import org.junit.Before; 052 import org.junit.Test; 053 import org.xml.sax.SAXException; 054 import org.xml.sax.SAXParseException; 055 import org.xml.sax.helpers.DefaultHandler; 056 057 /** 058 * test for loading and saving xml properties files 059 * 060 * @version $Id: TestXMLConfiguration.java 1330666 2012-04-26 06:12:30Z oheger $ 061 */ 062 public class TestXMLConfiguration 063 { 064 /** XML Catalog */ 065 private static final String CATALOG_FILES = ConfigurationAssert 066 .getTestFile("catalog.xml").getAbsolutePath(); 067 068 /** Constant for the used encoding.*/ 069 static final String ENCODING = "ISO-8859-1"; 070 071 /** Constant for the test system ID.*/ 072 static final String SYSTEM_ID = "properties.dtd"; 073 074 /** Constant for the test public ID.*/ 075 static final String PUBLIC_ID = "-//Commons Configuration//DTD Test Configuration 1.3//EN"; 076 077 /** Constant for the DOCTYPE declaration.*/ 078 static final String DOCTYPE_DECL = " PUBLIC \"" + PUBLIC_ID + "\" \"" + SYSTEM_ID + "\">"; 079 080 /** Constant for the DOCTYPE prefix.*/ 081 static final String DOCTYPE = "<!DOCTYPE "; 082 083 /** Constant for the transformer factory property.*/ 084 static final String PROP_FACTORY = "javax.xml.transform.TransformerFactory"; 085 086 /** The File that we test with */ 087 private String testProperties = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath(); 088 private String testProperties2 = ConfigurationAssert.getTestFile("testDigesterConfigurationInclude1.xml").getAbsolutePath(); 089 private String testBasePath = ConfigurationAssert.TEST_DIR.getAbsolutePath(); 090 private File testSaveConf = ConfigurationAssert.getOutFile("testsave.xml"); 091 private File testSaveFile = ConfigurationAssert.getOutFile("testsample2.xml"); 092 private String testFile2 = ConfigurationAssert.getTestFile("sample.xml").getAbsolutePath(); 093 094 /** Constant for the number of test threads. */ 095 private static final int THREAD_COUNT = 5; 096 097 /** Constant for the number of loops in tests with multiple threads. */ 098 private static final int LOOP_COUNT = 100; 099 100 private XMLConfiguration conf; 101 102 @Before 103 public void setUp() throws Exception 104 { 105 conf = new XMLConfiguration(); 106 conf.setFile(new File(testProperties)); 107 conf.load(); 108 removeTestFile(); 109 } 110 111 @Test 112 public void testGetProperty() 113 { 114 assertEquals("value", conf.getProperty("element")); 115 } 116 117 @Test 118 public void testGetCommentedProperty() 119 { 120 assertEquals("", conf.getProperty("test.comment")); 121 } 122 123 @Test 124 public void testGetPropertyWithXMLEntity() 125 { 126 assertEquals("1<2", conf.getProperty("test.entity")); 127 } 128 129 @Test 130 public void testClearProperty() throws Exception 131 { 132 // test non-existent element 133 String key = "clearly"; 134 conf.clearProperty(key); 135 assertNull(key, conf.getProperty(key)); 136 assertNull(key, conf.getProperty(key)); 137 138 // test single element 139 conf.load(); 140 key = "clear.element"; 141 conf.clearProperty(key); 142 assertNull(key, conf.getProperty(key)); 143 assertNull(key, conf.getProperty(key)); 144 145 // test single element with attribute 146 conf.load(); 147 key = "clear.element2"; 148 conf.clearProperty(key); 149 assertNull(key, conf.getProperty(key)); 150 assertNull(key, conf.getProperty(key)); 151 key = "clear.element2[@id]"; 152 assertNotNull(key, conf.getProperty(key)); 153 assertNotNull(key, conf.getProperty(key)); 154 155 // test non-text/cdata element 156 conf.load(); 157 key = "clear.comment"; 158 conf.clearProperty(key); 159 assertNull(key, conf.getProperty(key)); 160 assertNull(key, conf.getProperty(key)); 161 162 // test cdata element 163 conf.load(); 164 key = "clear.cdata"; 165 conf.clearProperty(key); 166 assertNull(key, conf.getProperty(key)); 167 assertNull(key, conf.getProperty(key)); 168 169 // test multiple sibling elements 170 conf.load(); 171 key = "clear.list.item"; 172 conf.clearProperty(key); 173 assertNull(key, conf.getProperty(key)); 174 assertNull(key, conf.getProperty(key)); 175 key = "clear.list.item[@id]"; 176 assertNotNull(key, conf.getProperty(key)); 177 assertNotNull(key, conf.getProperty(key)); 178 179 // test multiple, disjoined elements 180 conf.load(); 181 key = "list.item"; 182 conf.clearProperty(key); 183 assertNull(key, conf.getProperty(key)); 184 assertNull(key, conf.getProperty(key)); 185 } 186 187 @Test 188 public void testgetProperty() { 189 // test non-leaf element 190 Object property = conf.getProperty("clear"); 191 assertNull(property); 192 193 // test non-existent element 194 property = conf.getProperty("e"); 195 assertNull(property); 196 197 // test non-existent element 198 property = conf.getProperty("element3[@n]"); 199 assertNull(property); 200 201 // test single element 202 property = conf.getProperty("element"); 203 assertNotNull(property); 204 assertTrue(property instanceof String); 205 assertEquals("value", property); 206 207 // test single attribute 208 property = conf.getProperty("element3[@name]"); 209 assertNotNull(property); 210 assertTrue(property instanceof String); 211 assertEquals("foo", property); 212 213 // test non-text/cdata element 214 property = conf.getProperty("test.comment"); 215 assertEquals("", property); 216 217 // test cdata element 218 property = conf.getProperty("test.cdata"); 219 assertNotNull(property); 220 assertTrue(property instanceof String); 221 assertEquals("<cdata value>", property); 222 223 // test multiple sibling elements 224 property = conf.getProperty("list.sublist.item"); 225 assertNotNull(property); 226 assertTrue(property instanceof List); 227 List<?> list = (List<?>) property; 228 assertEquals(2, list.size()); 229 assertEquals("five", list.get(0)); 230 assertEquals("six", list.get(1)); 231 232 // test multiple, disjoined elements 233 property = conf.getProperty("list.item"); 234 assertNotNull(property); 235 assertTrue(property instanceof List); 236 list = (List<?>) property; 237 assertEquals(4, list.size()); 238 assertEquals("one", list.get(0)); 239 assertEquals("two", list.get(1)); 240 assertEquals("three", list.get(2)); 241 assertEquals("four", list.get(3)); 242 243 // test multiple, disjoined attributes 244 property = conf.getProperty("list.item[@name]"); 245 assertNotNull(property); 246 assertTrue(property instanceof List); 247 list = (List<?>) property; 248 assertEquals(2, list.size()); 249 assertEquals("one", list.get(0)); 250 assertEquals("three", list.get(1)); 251 } 252 253 @Test 254 public void testGetAttribute() 255 { 256 assertEquals("element3[@name]", "foo", conf.getProperty("element3[@name]")); 257 } 258 259 @Test 260 public void testClearAttribute() throws Exception 261 { 262 // test non-existent attribute 263 String key = "clear[@id]"; 264 conf.clearProperty(key); 265 assertNull(key, conf.getProperty(key)); 266 assertNull(key, conf.getProperty(key)); 267 268 // test single attribute 269 conf.load(); 270 key = "clear.element2[@id]"; 271 conf.clearProperty(key); 272 assertNull(key, conf.getProperty(key)); 273 assertNull(key, conf.getProperty(key)); 274 key = "clear.element2"; 275 assertNotNull(key, conf.getProperty(key)); 276 assertNotNull(key, conf.getProperty(key)); 277 278 // test multiple, disjoined attributes 279 conf.load(); 280 key = "clear.list.item[@id]"; 281 conf.clearProperty(key); 282 assertNull(key, conf.getProperty(key)); 283 assertNull(key, conf.getProperty(key)); 284 key = "clear.list.item"; 285 assertNotNull(key, conf.getProperty(key)); 286 assertNotNull(key, conf.getProperty(key)); 287 } 288 289 @Test 290 public void testSetAttribute() 291 { 292 // replace an existing attribute 293 conf.setProperty("element3[@name]", "bar"); 294 assertEquals("element3[@name]", "bar", conf.getProperty("element3[@name]")); 295 296 // set a new attribute 297 conf.setProperty("foo[@bar]", "value"); 298 assertEquals("foo[@bar]", "value", conf.getProperty("foo[@bar]")); 299 300 conf.setProperty("name1","value1"); 301 assertEquals("value1",conf.getProperty("name1")); 302 } 303 304 @Test 305 public void testAddAttribute() 306 { 307 conf.addProperty("element3[@name]", "bar"); 308 309 List<Object> list = conf.getList("element3[@name]"); 310 assertNotNull("null list", list); 311 assertTrue("'foo' element missing", list.contains("foo")); 312 assertTrue("'bar' element missing", list.contains("bar")); 313 assertEquals("list size", 2, list.size()); 314 } 315 316 @Test 317 public void testAddObjectAttribute() 318 { 319 conf.addProperty("test.boolean[@value]", Boolean.TRUE); 320 assertTrue("test.boolean[@value]", conf.getBoolean("test.boolean[@value]")); 321 } 322 323 /** 324 * Tests setting an attribute on the root element. 325 */ 326 @Test 327 public void testSetRootAttribute() throws ConfigurationException 328 { 329 conf.setProperty("[@test]", "true"); 330 assertEquals("Root attribute not set", "true", conf 331 .getString("[@test]")); 332 conf.save(testSaveConf); 333 XMLConfiguration checkConf = new XMLConfiguration(); 334 checkConf.setFile(testSaveConf); 335 checkSavedConfig(checkConf); 336 assertTrue("Attribute not found after save", checkConf 337 .containsKey("[@test]")); 338 checkConf.setProperty("[@test]", "newValue"); 339 checkConf.save(); 340 conf = checkConf; 341 checkConf = new XMLConfiguration(); 342 checkConf.setFile(testSaveConf); 343 checkSavedConfig(checkConf); 344 assertEquals("Attribute not modified after save", "newValue", checkConf 345 .getString("[@test]")); 346 } 347 348 /** 349 * Tests whether the configuration's root node is initialized with a 350 * reference to the corresponding XML element. 351 */ 352 @Test 353 public void testGetRootReference() 354 { 355 assertNotNull("Root node has no reference", conf.getRootNode() 356 .getReference()); 357 } 358 359 @Test 360 public void testAddList() 361 { 362 conf.addProperty("test.array", "value1"); 363 conf.addProperty("test.array", "value2"); 364 365 List<Object> list = conf.getList("test.array"); 366 assertNotNull("null list", list); 367 assertTrue("'value1' element missing", list.contains("value1")); 368 assertTrue("'value2' element missing", list.contains("value2")); 369 assertEquals("list size", 2, list.size()); 370 } 371 372 @Test 373 public void testGetComplexProperty() 374 { 375 assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); 376 } 377 378 @Test 379 public void testSettingFileNames() 380 { 381 conf = new XMLConfiguration(); 382 conf.setFileName(testProperties); 383 assertEquals(testProperties.toString(), conf.getFileName()); 384 385 conf.setBasePath(testBasePath); 386 conf.setFileName("hello.xml"); 387 assertEquals("hello.xml", conf.getFileName()); 388 assertEquals(testBasePath.toString(), conf.getBasePath()); 389 assertEquals(new File(testBasePath, "hello.xml"), conf.getFile()); 390 391 conf.setBasePath(testBasePath); 392 conf.setFileName("subdir/hello.xml"); 393 assertEquals("subdir/hello.xml", conf.getFileName()); 394 assertEquals(testBasePath.toString(), conf.getBasePath()); 395 assertEquals(new File(testBasePath, "subdir/hello.xml"), conf.getFile()); 396 } 397 398 @Test 399 public void testLoad() throws Exception 400 { 401 conf = new XMLConfiguration(); 402 conf.setFileName(testProperties); 403 conf.load(); 404 405 assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); 406 } 407 408 @Test 409 public void testLoadWithBasePath() throws Exception 410 { 411 conf = new XMLConfiguration(); 412 413 conf.setFileName("test.xml"); 414 conf.setBasePath(testBasePath); 415 conf.load(); 416 417 assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); 418 } 419 420 /** 421 * Tests constructing an XMLConfiguration from a non existing file and 422 * later saving to this file. 423 */ 424 @Test 425 public void testLoadAndSaveFromFile() throws Exception 426 { 427 // If the file does not exist, an empty config is created 428 conf = new XMLConfiguration(testSaveConf); 429 assertTrue(conf.isEmpty()); 430 conf.addProperty("test", "yes"); 431 conf.save(); 432 433 conf = new XMLConfiguration(testSaveConf); 434 assertEquals("yes", conf.getString("test")); 435 } 436 437 /** 438 * Tests loading a configuration from a URL. 439 */ 440 @Test 441 public void testLoadFromURL() throws Exception 442 { 443 URL url = new File(testProperties).toURI().toURL(); 444 conf = new XMLConfiguration(url); 445 assertEquals("value", conf.getProperty("element")); 446 assertEquals(url, conf.getURL()); 447 } 448 449 /** 450 * Tests loading from a stream. 451 */ 452 @Test 453 public void testLoadFromStream() throws Exception 454 { 455 String xml = "<?xml version=\"1.0\"?><config><test>1</test></config>"; 456 conf = new XMLConfiguration(); 457 conf.load(new ByteArrayInputStream(xml.getBytes())); 458 assertEquals(1, conf.getInt("test")); 459 460 conf = new XMLConfiguration(); 461 conf.load(new ByteArrayInputStream(xml.getBytes()), "UTF8"); 462 assertEquals(1, conf.getInt("test")); 463 } 464 465 /** 466 * Tests loading a non well formed XML from a string. 467 */ 468 @Test(expected = ConfigurationException.class) 469 public void testLoadInvalidXML() throws Exception 470 { 471 String xml = "<?xml version=\"1.0\"?><config><test>1</rest></config>"; 472 conf = new XMLConfiguration(); 473 conf.load(new StringReader(xml)); 474 } 475 476 @Test 477 public void testSetProperty() throws Exception 478 { 479 conf.setProperty("element.string", "hello"); 480 481 assertEquals("'element.string'", "hello", conf.getString("element.string")); 482 assertEquals("XML value of element.string", "hello", conf.getProperty("element.string")); 483 } 484 485 @Test 486 public void testAddProperty() 487 { 488 // add a property to a non initialized xml configuration 489 XMLConfiguration config = new XMLConfiguration(); 490 config.addProperty("test.string", "hello"); 491 492 assertEquals("'test.string'", "hello", config.getString("test.string")); 493 } 494 495 @Test 496 public void testAddObjectProperty() 497 { 498 // add a non string property 499 conf.addProperty("test.boolean", Boolean.TRUE); 500 assertTrue("'test.boolean'", conf.getBoolean("test.boolean")); 501 } 502 503 @Test 504 public void testSave() throws Exception 505 { 506 // add an array of strings to the configuration 507 conf.addProperty("string", "value1"); 508 for (int i = 1; i < 5; i++) 509 { 510 conf.addProperty("test.array", "value" + i); 511 } 512 513 // add an array of strings in an attribute 514 for (int i = 1; i < 5; i++) 515 { 516 conf.addProperty("test.attribute[@array]", "value" + i); 517 } 518 519 // add comma delimited lists with escaped delimiters 520 conf.addProperty("split.list5", "a\\,b\\,c"); 521 conf.setProperty("element3", "value\\,value1\\,value2"); 522 conf.setProperty("element3[@name]", "foo\\,bar"); 523 524 // save the configuration 525 conf.save(testSaveConf.getAbsolutePath()); 526 527 // read the configuration and compare the properties 528 XMLConfiguration checkConfig = new XMLConfiguration(); 529 checkConfig.setFileName(testSaveConf.getAbsolutePath()); 530 checkSavedConfig(checkConfig); 531 } 532 533 /** 534 * Tests saving to a URL. 535 */ 536 @Test 537 public void testSaveToURL() throws Exception 538 { 539 conf.save(testSaveConf.toURI().toURL()); 540 XMLConfiguration checkConfig = new XMLConfiguration(); 541 checkConfig.setFile(testSaveConf); 542 checkSavedConfig(checkConfig); 543 } 544 545 /** 546 * Tests saving to a stream. 547 */ 548 @Test 549 public void testSaveToStream() throws Exception 550 { 551 assertNull(conf.getEncoding()); 552 conf.setEncoding("UTF8"); 553 FileOutputStream out = null; 554 try 555 { 556 out = new FileOutputStream(testSaveConf); 557 conf.save(out); 558 } 559 finally 560 { 561 if(out != null) 562 { 563 out.close(); 564 } 565 } 566 567 XMLConfiguration checkConfig = new XMLConfiguration(); 568 checkConfig.setFile(testSaveConf); 569 checkSavedConfig(checkConfig); 570 571 try 572 { 573 out = new FileOutputStream(testSaveConf); 574 conf.save(out, "UTF8"); 575 } 576 finally 577 { 578 if(out != null) 579 { 580 out.close(); 581 } 582 } 583 584 checkConfig.clear(); 585 checkSavedConfig(checkConfig); 586 } 587 588 @Test 589 public void testAutoSave() throws Exception 590 { 591 conf.setFile(testSaveConf); 592 assertFalse(conf.isAutoSave()); 593 conf.setAutoSave(true); 594 assertTrue(conf.isAutoSave()); 595 conf.setProperty("autosave", "ok"); 596 597 // reload the configuration 598 XMLConfiguration conf2 = new XMLConfiguration(conf.getFile()); 599 assertEquals("'autosave' property", "ok", conf2.getString("autosave")); 600 601 conf.clearTree("clear"); 602 conf2 = new XMLConfiguration(conf.getFile()); 603 Configuration sub = conf2.subset("clear"); 604 assertTrue(sub.isEmpty()); 605 } 606 607 /** 608 * Tests if a second file can be appended to a first. 609 */ 610 @Test 611 public void testAppend() throws Exception 612 { 613 conf = new XMLConfiguration(); 614 conf.setFileName(testProperties); 615 conf.load(); 616 conf.load(testProperties2); 617 assertEquals("value", conf.getString("element")); 618 assertEquals("tasks", conf.getString("table.name")); 619 620 conf.save(testSaveConf); 621 conf = new XMLConfiguration(testSaveConf); 622 assertEquals("value", conf.getString("element")); 623 assertEquals("tasks", conf.getString("table.name")); 624 assertEquals("application", conf.getString("table[@tableType]")); 625 } 626 627 /** 628 * Tests saving attributes (related to issue 34442). 629 */ 630 @Test 631 public void testSaveAttributes() throws Exception 632 { 633 conf.clear(); 634 conf.load(); 635 conf.save(testSaveConf); 636 conf = new XMLConfiguration(); 637 conf.load(testSaveConf); 638 assertEquals("foo", conf.getString("element3[@name]")); 639 } 640 641 /** 642 * Tests collaboration between XMLConfiguration and a reloading strategy. 643 */ 644 @Test 645 public void testReloading() throws Exception 646 { 647 assertNotNull(conf.getReloadingStrategy()); 648 assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy); 649 PrintWriter out = null; 650 651 try 652 { 653 out = new PrintWriter(new FileWriter(testSaveConf)); 654 out.println("<?xml version=\"1.0\"?><config><test>1</test></config>"); 655 out.close(); 656 out = null; 657 conf.setFile(testSaveConf); 658 FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy(); 659 strategy.setRefreshDelay(100); 660 conf.setReloadingStrategy(strategy); 661 assertEquals(strategy, conf.getReloadingStrategy()); 662 assertEquals("Wrong file monitored", testSaveConf.getAbsolutePath(), 663 strategy.getMonitoredFile().getAbsolutePath()); 664 conf.load(); 665 assertEquals(1, conf.getInt("test")); 666 667 out = new PrintWriter(new FileWriter(testSaveConf)); 668 out.println("<?xml version=\"1.0\"?><config><test>2</test></config>"); 669 out.close(); 670 out = null; 671 672 int value = conf.getInt("test"); 673 assertEquals("No reloading performed", 2, value); 674 } 675 finally 676 { 677 if (out != null) 678 { 679 out.close(); 680 } 681 } 682 } 683 684 @Test 685 public void testReloadingOOM() throws Exception 686 { 687 assertNotNull(conf.getReloadingStrategy()); 688 assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy); 689 PrintWriter out = null; 690 691 try 692 { 693 out = new PrintWriter(new FileWriter(testSaveConf)); 694 out.println("<?xml version=\"1.0\"?><config><test>1</test></config>"); 695 out.close(); 696 out = null; 697 conf.setFile(testSaveConf); 698 FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy(); 699 strategy.setRefreshDelay(100); 700 conf.setReloadingStrategy(strategy); 701 conf.load(); 702 assertEquals(1, conf.getInt("test")); 703 704 for (int i = 1; i < LOOP_COUNT; ++i) 705 { 706 assertEquals(1, conf.getInt("test")); 707 } 708 } 709 finally 710 { 711 if (out != null) 712 { 713 out.close(); 714 } 715 } 716 } 717 718 /** 719 * Tests the refresh() method. 720 */ 721 @Test 722 public void testRefresh() throws ConfigurationException 723 { 724 conf.setProperty("element", "anotherValue"); 725 conf.refresh(); 726 assertEquals("Wrong property after refresh", "value", 727 conf.getString("element")); 728 } 729 730 /** 731 * Tries to call refresh() when the configuration is not associated with a 732 * file. 733 */ 734 @Test(expected = ConfigurationException.class) 735 public void testRefreshNoFile() throws ConfigurationException 736 { 737 conf = new XMLConfiguration(); 738 conf.refresh(); 739 } 740 741 /** 742 * Tests access to tag names with delimiter characters. 743 */ 744 @Test 745 public void testComplexNames() 746 { 747 assertEquals("Name with dot", conf.getString("complexNames.my..elem")); 748 assertEquals("Another dot", conf.getString("complexNames.my..elem.sub..elem")); 749 } 750 751 /** 752 * Creates a validating document builder. 753 * @return the document builder 754 * @throws ParserConfigurationException if an error occurs 755 */ 756 private DocumentBuilder createValidatingDocBuilder() 757 throws ParserConfigurationException 758 { 759 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 760 factory.setValidating(true); 761 DocumentBuilder builder = factory.newDocumentBuilder(); 762 builder.setErrorHandler(new DefaultHandler() { 763 @Override 764 public void error(SAXParseException ex) throws SAXException 765 { 766 throw ex; 767 } 768 }); 769 return builder; 770 } 771 772 /** 773 * Tests setting a custom document builder. 774 */ 775 @Test 776 public void testCustomDocBuilder() throws Exception 777 { 778 // Load an invalid XML file with the default (non validating) 779 // doc builder. This should work... 780 conf = new XMLConfiguration(); 781 conf.load(ConfigurationAssert.getTestFile("testValidateInvalid.xml")); 782 assertEquals("customers", conf.getString("table.name")); 783 assertFalse(conf.containsKey("table.fields.field(1).type")); 784 } 785 786 /** 787 * Tests whether a validating document builder detects a validation error. 788 */ 789 @Test(expected = ConfigurationException.class) 790 public void testCustomDocBuilderValidationError() throws Exception 791 { 792 DocumentBuilder builder = createValidatingDocBuilder(); 793 conf = new XMLConfiguration(); 794 conf.setDocumentBuilder(builder); 795 conf.load(new File("conf/testValidateInvalid.xml")); 796 } 797 798 /** 799 * Tests whether a valid document can be loaded with a validating document builder. 800 */ 801 @Test 802 public void testCustomDocBuilderValidationSuccess() throws Exception 803 { 804 DocumentBuilder builder = createValidatingDocBuilder(); 805 conf = new XMLConfiguration(); 806 conf.setDocumentBuilder(builder); 807 conf.load(ConfigurationAssert.getTestFile("testValidateValid.xml")); 808 assertTrue(conf.containsKey("table.fields.field(1).type")); 809 } 810 811 /** 812 * Tests the clone() method. 813 */ 814 @Test 815 public void testClone() 816 { 817 Configuration c = (Configuration) conf.clone(); 818 assertTrue(c instanceof XMLConfiguration); 819 XMLConfiguration copy = (XMLConfiguration) c; 820 assertNotNull(conf.getDocument()); 821 assertNull(copy.getDocument()); 822 assertNotNull(conf.getFileName()); 823 assertNull(copy.getFileName()); 824 825 copy.setProperty("element3", "clonedValue"); 826 assertEquals("value", conf.getString("element3")); 827 conf.setProperty("element3[@name]", "originalFoo"); 828 assertEquals("foo", copy.getString("element3[@name]")); 829 } 830 831 /** 832 * Tests saving a configuration after cloning to ensure that the clone and 833 * the original are completely detached. 834 */ 835 @Test 836 public void testCloneWithSave() throws ConfigurationException 837 { 838 XMLConfiguration c = (XMLConfiguration) conf.clone(); 839 c.addProperty("test.newProperty", Boolean.TRUE); 840 conf.addProperty("test.orgProperty", Boolean.TRUE); 841 c.save(testSaveConf); 842 XMLConfiguration c2 = new XMLConfiguration(testSaveConf); 843 assertTrue("New property after clone() was not saved", c2 844 .getBoolean("test.newProperty")); 845 assertFalse("Property of original config was saved", c2 846 .containsKey("test.orgProperty")); 847 } 848 849 /** 850 * Tests the subset() method. There was a bug that calling subset() had 851 * undesired side effects. 852 */ 853 @Test 854 public void testSubset() throws ConfigurationException 855 { 856 conf = new XMLConfiguration(); 857 conf.load(ConfigurationAssert.getTestFile("testHierarchicalXMLConfiguration.xml")); 858 conf.subset("tables.table(0)"); 859 conf.save(testSaveConf); 860 861 conf = new XMLConfiguration(testSaveConf); 862 assertEquals("users", conf.getString("tables.table(0).name")); 863 } 864 865 /** 866 * Tests string properties with list delimiters and escaped delimiters. 867 */ 868 @Test 869 public void testSplitLists() 870 { 871 assertEquals("a", conf.getString("split.list3[@values]")); 872 assertEquals(2, conf.getMaxIndex("split.list3[@values]")); 873 assertEquals("a,b,c", conf.getString("split.list4[@values]")); 874 assertEquals("a", conf.getString("split.list1")); 875 assertEquals(2, conf.getMaxIndex("split.list1")); 876 assertEquals("a,b,c", conf.getString("split.list2")); 877 } 878 879 /** 880 * Tests string properties with list delimiters when delimiter parsing 881 * is disabled 882 */ 883 @Test 884 public void testDelimiterParsingDisabled() throws ConfigurationException { 885 XMLConfiguration conf2 = new XMLConfiguration(); 886 conf2.setDelimiterParsingDisabled(true); 887 conf2.setFile(new File(testProperties)); 888 conf2.load(); 889 890 assertEquals("a,b,c", conf2.getString("split.list3[@values]")); 891 assertEquals(0, conf2.getMaxIndex("split.list3[@values]")); 892 assertEquals("a\\,b\\,c", conf2.getString("split.list4[@values]")); 893 assertEquals("a,b,c", conf2.getString("split.list1")); 894 assertEquals(0, conf2.getMaxIndex("split.list1")); 895 assertEquals("a\\,b\\,c", conf2.getString("split.list2")); 896 conf2 = new XMLConfiguration(); 897 conf2.setExpressionEngine(new XPathExpressionEngine()); 898 conf2.setDelimiterParsingDisabled(true); 899 conf2.setFile(new File(testProperties)); 900 conf2.load(); 901 902 assertEquals("a,b,c", conf2.getString("split/list3/@values")); 903 assertEquals(0, conf2.getMaxIndex("split/list3/@values")); 904 assertEquals("a\\,b\\,c", conf2.getString("split/list4/@values")); 905 assertEquals("a,b,c", conf2.getString("split/list1")); 906 assertEquals(0, conf2.getMaxIndex("split/list1")); 907 assertEquals("a\\,b\\,c", conf2.getString("split/list2")); 908 } 909 910 /** 911 * Tests string properties with list delimiters when delimiter parsing 912 * is disabled 913 */ 914 @Test 915 public void testSaveWithDelimiterParsingDisabled() throws ConfigurationException { 916 XMLConfiguration conf = new XMLConfiguration(); 917 conf.setExpressionEngine(new XPathExpressionEngine()); 918 conf.setDelimiterParsingDisabled(true); 919 conf.setAttributeSplittingDisabled(true); 920 conf.setFile(new File(testProperties)); 921 conf.load(); 922 923 assertEquals("a,b,c", conf.getString("split/list3/@values")); 924 assertEquals(0, conf.getMaxIndex("split/list3/@values")); 925 assertEquals("a\\,b\\,c", conf.getString("split/list4/@values")); 926 assertEquals("a,b,c", conf.getString("split/list1")); 927 assertEquals(0, conf.getMaxIndex("split/list1")); 928 assertEquals("a\\,b\\,c", conf.getString("split/list2")); 929 // save the configuration 930 conf.save(testSaveConf.getAbsolutePath()); 931 932 // read the configuration and compare the properties 933 XMLConfiguration checkConfig = new XMLConfiguration(); 934 checkConfig.setFileName(testSaveConf.getAbsolutePath()); 935 checkSavedConfig(checkConfig); 936 XMLConfiguration config = new XMLConfiguration(); 937 config.setFileName(testFile2); 938 //config.setExpressionEngine(new XPathExpressionEngine()); 939 config.setDelimiterParsingDisabled(true); 940 config.setAttributeSplittingDisabled(true); 941 config.load(); 942 config.setProperty("Employee[@attr1]", "3,2,1"); 943 assertEquals("3,2,1", config.getString("Employee[@attr1]")); 944 config.save(testSaveFile.getAbsolutePath()); 945 config = new XMLConfiguration(); 946 config.setFileName(testSaveFile.getAbsolutePath()); 947 //config.setExpressionEngine(new XPathExpressionEngine()); 948 config.setDelimiterParsingDisabled(true); 949 config.setAttributeSplittingDisabled(true); 950 config.load(); 951 config.setProperty("Employee[@attr1]", "1,2,3"); 952 assertEquals("1,2,3", config.getString("Employee[@attr1]")); 953 config.setProperty("Employee[@attr2]", "one, two, three"); 954 assertEquals("one, two, three", config.getString("Employee[@attr2]")); 955 config.setProperty("Employee.text", "a,b,d"); 956 assertEquals("a,b,d", config.getString("Employee.text")); 957 config.setProperty("Employee.Salary", "100,000"); 958 assertEquals("100,000", config.getString("Employee.Salary")); 959 config.save(testSaveFile.getAbsolutePath()); 960 checkConfig = new XMLConfiguration(); 961 checkConfig.setFileName(testSaveFile.getAbsolutePath()); 962 checkConfig.setExpressionEngine(new XPathExpressionEngine()); 963 checkConfig.setDelimiterParsingDisabled(true); 964 checkConfig.setAttributeSplittingDisabled(true); 965 checkConfig.load(); 966 assertEquals("1,2,3", checkConfig.getString("Employee/@attr1")); 967 assertEquals("one, two, three", checkConfig.getString("Employee/@attr2")); 968 assertEquals("a,b,d", checkConfig.getString("Employee/text")); 969 assertEquals("100,000", checkConfig.getString("Employee/Salary")); 970 } 971 972 /** 973 * Tests whether a DTD can be accessed. 974 */ 975 @Test 976 public void testDtd() throws ConfigurationException 977 { 978 conf = new XMLConfiguration("testDtd.xml"); 979 assertEquals("value1", conf.getString("entry(0)")); 980 assertEquals("test2", conf.getString("entry(1)[@key]")); 981 } 982 983 /** 984 * Tests DTD validation using the setValidating() method. 985 */ 986 @Test 987 public void testValidating() throws ConfigurationException 988 { 989 File nonValidFile = ConfigurationAssert.getTestFile("testValidateInvalid.xml"); 990 conf = new XMLConfiguration(); 991 assertFalse(conf.isValidating()); 992 993 // Load a non valid XML document. Should work for isValidating() == false 994 conf.load(nonValidFile); 995 assertEquals("customers", conf.getString("table.name")); 996 assertFalse(conf.containsKey("table.fields.field(1).type")); 997 998 // Now set the validating flag to true 999 conf.setValidating(true); 1000 try 1001 { 1002 conf.load(nonValidFile); 1003 fail("Validation was not performed!"); 1004 } 1005 catch(ConfigurationException cex) 1006 { 1007 //ok 1008 } 1009 } 1010 1011 /** 1012 * Tests handling of empty elements. 1013 */ 1014 @Test 1015 public void testEmptyElements() throws ConfigurationException 1016 { 1017 assertTrue(conf.containsKey("empty")); 1018 assertEquals("", conf.getString("empty")); 1019 conf.addProperty("empty2", ""); 1020 conf.setProperty("empty", "no more empty"); 1021 conf.save(testSaveConf); 1022 1023 conf = new XMLConfiguration(testSaveConf); 1024 assertEquals("no more empty", conf.getString("empty")); 1025 assertEquals("", conf.getProperty("empty2")); 1026 } 1027 1028 /** 1029 * Tests the isEmpty() method for an empty configuration that was reloaded. 1030 */ 1031 @Test 1032 public void testEmptyReload() throws ConfigurationException 1033 { 1034 XMLConfiguration config = new XMLConfiguration(); 1035 assertTrue("Newly created configuration not empty", config.isEmpty()); 1036 config.save(testSaveConf); 1037 config.load(testSaveConf); 1038 assertTrue("Reloaded configuration not empty", config.isEmpty()); 1039 } 1040 1041 /** 1042 * Tests whether the encoding is correctly detected by the XML parser. This 1043 * is done by loading an XML file with the encoding "UTF-16". If this 1044 * encoding is not detected correctly, an exception will be thrown that 1045 * "Content is not allowed in prolog". This test case is related to issue 1046 * 34204. 1047 */ 1048 @Test 1049 public void testLoadWithEncoding() throws ConfigurationException 1050 { 1051 File file = ConfigurationAssert.getTestFile("testEncoding.xml"); 1052 conf = new XMLConfiguration(); 1053 conf.load(file); 1054 assertEquals("test3_yoge", conf.getString("yoge")); 1055 } 1056 1057 /** 1058 * Tests whether the encoding is written to the generated XML file. 1059 */ 1060 @Test 1061 public void testSaveWithEncoding() throws ConfigurationException 1062 { 1063 conf = new XMLConfiguration(); 1064 conf.setProperty("test", "a value"); 1065 conf.setEncoding(ENCODING); 1066 1067 StringWriter out = new StringWriter(); 1068 conf.save(out); 1069 assertTrue("Encoding was not written to file", out.toString().indexOf( 1070 "encoding=\"" + ENCODING + "\"") >= 0); 1071 } 1072 1073 /** 1074 * Tests whether a default encoding is used if no specific encoding is set. 1075 * According to the XSLT specification (http://www.w3.org/TR/xslt#output) 1076 * this should be either UTF-8 or UTF-16. 1077 */ 1078 @Test 1079 public void testSaveWithNullEncoding() throws ConfigurationException 1080 { 1081 conf = new XMLConfiguration(); 1082 conf.setProperty("testNoEncoding", "yes"); 1083 conf.setEncoding(null); 1084 1085 StringWriter out = new StringWriter(); 1086 conf.save(out); 1087 assertTrue("Encoding was written to file", out.toString().indexOf( 1088 "encoding=\"UTF-") >= 0); 1089 } 1090 1091 /** 1092 * Tests whether the DOCTYPE survives a save operation. 1093 */ 1094 @Test 1095 public void testSaveWithDoctype() throws ConfigurationException 1096 { 1097 String content = "<?xml version=\"1.0\"?>" 1098 + DOCTYPE 1099 + "properties" 1100 + DOCTYPE_DECL 1101 + "<properties version=\"1.0\"><entry key=\"test\">value</entry></properties>"; 1102 StringReader in = new StringReader(content); 1103 conf = new XMLConfiguration(); 1104 conf.setFileName("testDtd.xml"); 1105 conf.load(); 1106 conf.clear(); 1107 conf.load(in); 1108 1109 assertEquals("Wrong public ID", PUBLIC_ID, conf.getPublicID()); 1110 assertEquals("Wrong system ID", SYSTEM_ID, conf.getSystemID()); 1111 StringWriter out = new StringWriter(); 1112 conf.save(out); 1113 assertTrue("Did not find DOCTYPE", out.toString().indexOf(DOCTYPE) >= 0); 1114 } 1115 1116 /** 1117 * Tests setting public and system IDs for the D'OCTYPE and then saving the 1118 * configuration. This should generate a DOCTYPE declaration. 1119 */ 1120 @Test 1121 public void testSaveWithDoctypeIDs() throws ConfigurationException 1122 { 1123 assertNull("A public ID was found", conf.getPublicID()); 1124 assertNull("A system ID was found", conf.getSystemID()); 1125 conf.setPublicID(PUBLIC_ID); 1126 conf.setSystemID(SYSTEM_ID); 1127 StringWriter out = new StringWriter(); 1128 conf.save(out); 1129 assertTrue("Did not find DOCTYPE", out.toString().indexOf( 1130 DOCTYPE + "testconfig" + DOCTYPE_DECL) >= 0); 1131 } 1132 1133 /** 1134 * Tests saving a configuration when an invalid transformer factory is 1135 * specified. In this case the error thrown by the TransformerFactory class 1136 * should be caught and re-thrown as a ConfigurationException. 1137 */ 1138 @Test 1139 public void testSaveWithInvalidTransformerFactory() 1140 { 1141 System.setProperty(PROP_FACTORY, "an.invalid.Class"); 1142 try 1143 { 1144 conf.save(testSaveConf); 1145 fail("Could save with invalid TransformerFactory!"); 1146 } 1147 catch (ConfigurationException cex) 1148 { 1149 // ok 1150 } 1151 finally 1152 { 1153 System.getProperties().remove(PROP_FACTORY); 1154 } 1155 } 1156 1157 /** 1158 * Tests if reloads are recognized by subset(). 1159 */ 1160 @Test 1161 public void testSubsetWithReload() throws ConfigurationException 1162 { 1163 XMLConfiguration c = setUpReloadTest(); 1164 Configuration sub = c.subset("test"); 1165 assertEquals("New value not read", "newValue", sub.getString("entity")); 1166 } 1167 1168 /** 1169 * Tests if reloads are recognized by configurationAt(). 1170 */ 1171 @Test 1172 public void testConfigurationAtWithReload() throws ConfigurationException 1173 { 1174 XMLConfiguration c = setUpReloadTest(); 1175 HierarchicalConfiguration sub = c.configurationAt("test(0)"); 1176 assertEquals("New value not read", "newValue", sub.getString("entity")); 1177 } 1178 1179 /** 1180 * Tests if reloads are recognized by configurationsAt(). 1181 */ 1182 @Test 1183 public void testConfigurationsAtWithReload() throws ConfigurationException 1184 { 1185 XMLConfiguration c = setUpReloadTest(); 1186 List<HierarchicalConfiguration> configs = c.configurationsAt("test"); 1187 assertEquals("New value not read", "newValue", 1188 configs.get(0).getString("entity")); 1189 } 1190 1191 /** 1192 * Tests whether reloads are recognized when querying the configuration's 1193 * keys. 1194 */ 1195 @Test 1196 public void testGetKeysWithReload() throws ConfigurationException 1197 { 1198 XMLConfiguration c = setUpReloadTest(); 1199 conf.addProperty("aNewKey", "aNewValue"); 1200 conf.save(testSaveConf); 1201 boolean found = false; 1202 for (Iterator<String> it = c.getKeys(); it.hasNext();) 1203 { 1204 if ("aNewKey".equals(it.next())) 1205 { 1206 found = true; 1207 } 1208 } 1209 assertTrue("Reload not performed", found); 1210 } 1211 1212 /** 1213 * Tests accessing properties when the XPATH expression engine is set. 1214 */ 1215 @Test 1216 public void testXPathExpressionEngine() 1217 { 1218 conf.setExpressionEngine(new XPathExpressionEngine()); 1219 assertEquals("Wrong attribute value", "foo\"bar", conf 1220 .getString("test[1]/entity/@name")); 1221 conf.clear(); 1222 assertNull(conf.getString("test[1]/entity/@name")); 1223 } 1224 1225 /** 1226 * Tests the copy constructor. 1227 */ 1228 @Test 1229 public void testInitCopy() throws ConfigurationException 1230 { 1231 XMLConfiguration copy = new XMLConfiguration(conf); 1232 assertEquals("value", copy.getProperty("element")); 1233 assertNull("Document was copied, too", copy.getDocument()); 1234 ConfigurationNode root = copy.getRootNode(); 1235 for (ConfigurationNode node : root.getChildren()) 1236 { 1237 assertNull("Reference was not cleared", node.getReference()); 1238 } 1239 1240 removeTestFile(); 1241 copy.setFile(testSaveConf); 1242 copy.save(); 1243 copy.clear(); 1244 checkSavedConfig(copy); 1245 } 1246 1247 /** 1248 * Tests setting text of the root element. 1249 */ 1250 @Test 1251 public void testSetTextRootElement() throws ConfigurationException 1252 { 1253 conf.setProperty("", "Root text"); 1254 conf.save(testSaveConf); 1255 XMLConfiguration copy = new XMLConfiguration(); 1256 copy.setFile(testSaveConf); 1257 checkSavedConfig(copy); 1258 } 1259 1260 /** 1261 * Tests removing the text of the root element. 1262 */ 1263 @Test 1264 public void testClearTextRootElement() throws ConfigurationException 1265 { 1266 final String xml = "<e a=\"v\">text</e>"; 1267 conf.clear(); 1268 StringReader in = new StringReader(xml); 1269 conf.load(in); 1270 assertEquals("Wrong text of root", "text", conf.getString("")); 1271 1272 conf.clearProperty(""); 1273 conf.save(testSaveConf); 1274 XMLConfiguration copy = new XMLConfiguration(); 1275 copy.setFile(testSaveConf); 1276 checkSavedConfig(copy); 1277 } 1278 1279 /** 1280 * Tests list nodes with multiple values and attributes. 1281 */ 1282 @Test 1283 public void testListWithAttributes() 1284 { 1285 assertEquals("Wrong number of <a> elements", 6, conf.getList( 1286 "attrList.a").size()); 1287 assertEquals("Wrong value of first element", "ABC", conf 1288 .getString("attrList.a(0)")); 1289 assertEquals("Wrong value of first name attribute", "x", conf 1290 .getString("attrList.a(0)[@name]")); 1291 assertEquals("Wrong number of name attributes", 5, conf.getList( 1292 "attrList.a[@name]").size()); 1293 } 1294 1295 /** 1296 * Tests a list node with attributes that has multiple values separated by 1297 * the list delimiter. In this scenario the attribute should be added to the 1298 * node with the first value. 1299 */ 1300 @Test 1301 public void testListWithAttributesMultiValue() 1302 { 1303 assertEquals("Wrong value of 2nd element", "1", conf 1304 .getString("attrList.a(1)")); 1305 assertEquals("Wrong value of 2nd name attribute", "y", conf 1306 .getString("attrList.a(1)[@name]")); 1307 for (int i = 2; i <= 3; i++) 1308 { 1309 assertEquals("Wrong value of element " + (i + 1), i, conf 1310 .getInt("attrList.a(" + i + ")")); 1311 assertFalse("element " + (i + 1) + " has attribute", conf 1312 .containsKey("attrList.a(2)[@name]")); 1313 } 1314 } 1315 1316 /** 1317 * Tests a list node with a multi-value attribute and multiple values. All 1318 * attribute values should be assigned to the node with the first value. 1319 */ 1320 @Test 1321 public void testListWithMultiAttributesMultiValue() 1322 { 1323 for (int i = 1; i <= 2; i++) 1324 { 1325 assertEquals("Wrong value of multi-valued node", "value" + i, conf 1326 .getString("attrList.a(" + (i + 3) + ")")); 1327 } 1328 List<Object> attrs = conf.getList("attrList.a(4)[@name]"); 1329 final String attrVal = "uvw"; 1330 assertEquals("Wrong number of name attributes", attrVal.length(), attrs 1331 .size()); 1332 for (int i = 0; i < attrVal.length(); i++) 1333 { 1334 assertEquals("Wrong value for attribute " + i, String 1335 .valueOf(attrVal.charAt(i)), attrs.get(i)); 1336 } 1337 assertEquals("Wrong value of test attribute", "yes", conf 1338 .getString("attrList.a(4)[@test]")); 1339 assertFalse("Name attribute for 2nd value", conf 1340 .containsKey("attrList.a(5)[@name]")); 1341 assertFalse("Test attribute for 2nd value", conf 1342 .containsKey("attrList.a(5)[@test]")); 1343 } 1344 1345 /** 1346 * Tests whether the auto save mechanism is triggered by changes at a 1347 * subnode configuration. 1348 */ 1349 @Test 1350 public void testAutoSaveWithSubnodeConfig() throws ConfigurationException 1351 { 1352 final String newValue = "I am autosaved"; 1353 conf.setFile(testSaveConf); 1354 conf.setAutoSave(true); 1355 Configuration sub = conf.configurationAt("element2.subelement"); 1356 sub.setProperty("subsubelement", newValue); 1357 assertEquals("Change not visible to parent", newValue, conf 1358 .getString("element2.subelement.subsubelement")); 1359 XMLConfiguration conf2 = new XMLConfiguration(testSaveConf); 1360 assertEquals("Change was not saved", newValue, conf2 1361 .getString("element2.subelement.subsubelement")); 1362 } 1363 1364 /** 1365 * Tests whether a subnode configuration created from another subnode 1366 * configuration of a XMLConfiguration can trigger the auto save mechanism. 1367 */ 1368 @Test 1369 public void testAutoSaveWithSubSubnodeConfig() throws ConfigurationException 1370 { 1371 final String newValue = "I am autosaved"; 1372 conf.setFile(testSaveConf); 1373 conf.setAutoSave(true); 1374 SubnodeConfiguration sub1 = conf.configurationAt("element2"); 1375 SubnodeConfiguration sub2 = sub1.configurationAt("subelement"); 1376 sub2.setProperty("subsubelement", newValue); 1377 assertEquals("Change not visible to parent", newValue, conf 1378 .getString("element2.subelement.subsubelement")); 1379 XMLConfiguration conf2 = new XMLConfiguration(testSaveConf); 1380 assertEquals("Change was not saved", newValue, conf2 1381 .getString("element2.subelement.subsubelement")); 1382 } 1383 1384 /** 1385 * Tests saving and loading a configuration when delimiter parsing is 1386 * disabled. 1387 */ 1388 @Test 1389 public void testSaveDelimiterParsingDisabled() 1390 throws ConfigurationException 1391 { 1392 checkSaveDelimiterParsingDisabled("list.delimiter.test"); 1393 } 1394 1395 /** 1396 * Tests saving and loading a configuration when delimiter parsing is 1397 * disabled and attributes are involved. 1398 */ 1399 @Test 1400 public void testSaveDelimiterParsingDisabledAttrs() 1401 throws ConfigurationException 1402 { 1403 checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]"); 1404 } 1405 1406 /** 1407 * Helper method for testing saving and loading a configuration when 1408 * delimiter parsing is disabled. 1409 * 1410 * @param key the key to be checked 1411 * @throws ConfigurationException if an error occurs 1412 */ 1413 private void checkSaveDelimiterParsingDisabled(String key) 1414 throws ConfigurationException 1415 { 1416 conf.clear(); 1417 conf.setDelimiterParsingDisabled(true); 1418 conf.load(); 1419 conf.setProperty(key, "C:\\Temp\\,C:\\Data\\"); 1420 conf.addProperty(key, "a,b,c"); 1421 conf.save(testSaveConf); 1422 XMLConfiguration checkConf = new XMLConfiguration(); 1423 checkConf.setDelimiterParsingDisabled(true); 1424 checkConf.setFile(testSaveConf); 1425 checkSavedConfig(checkConf); 1426 } 1427 1428 /** 1429 * Tests multiple attribute values in delimiter parsing disabled mode. 1430 */ 1431 @Test 1432 public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException 1433 { 1434 conf.clear(); 1435 conf.setDelimiterParsingDisabled(true); 1436 conf.load(); 1437 List<Object> expr = conf.getList("expressions[@value]"); 1438 assertEquals("Wrong list size", 2, expr.size()); 1439 assertEquals("Wrong element 1", "a || (b && c)", expr.get(0)); 1440 assertEquals("Wrong element 2", "!d", expr.get(1)); 1441 } 1442 1443 /** 1444 * Tests using multiple attribute values, which are partly escaped when 1445 * delimiter parsing is not disabled. 1446 */ 1447 @Test 1448 public void testMultipleAttrValuesEscaped() throws ConfigurationException 1449 { 1450 conf.addProperty("test.dir[@name]", "C:\\Temp\\"); 1451 conf.addProperty("test.dir[@name]", "C:\\Data\\"); 1452 conf.save(testSaveConf); 1453 XMLConfiguration checkConf = new XMLConfiguration(); 1454 checkConf.setFile(testSaveConf); 1455 checkSavedConfig(checkConf); 1456 } 1457 1458 /** 1459 * Tests a combination of auto save = true and an associated reloading 1460 * strategy. 1461 */ 1462 @Test 1463 public void testAutoSaveWithReloadingStrategy() throws ConfigurationException 1464 { 1465 conf.setFile(testSaveConf); 1466 conf.save(); 1467 conf.setReloadingStrategy(new FileAlwaysReloadingStrategy()); 1468 conf.setAutoSave(true); 1469 assertEquals("Value not found", "value", conf.getProperty("element")); 1470 } 1471 1472 /** 1473 * Tests adding nodes from another configuration. 1474 */ 1475 @Test 1476 public void testAddNodesCopy() throws ConfigurationException 1477 { 1478 XMLConfiguration c2 = new XMLConfiguration(testProperties2); 1479 conf.addNodes("copiedProperties", c2.getRootNode().getChildren()); 1480 conf.save(testSaveConf); 1481 XMLConfiguration checkConf = new XMLConfiguration(); 1482 checkConf.setFile(testSaveConf); 1483 checkSavedConfig(checkConf); 1484 } 1485 1486 /** 1487 * Tests whether the addNodes() method triggers an auto save. 1488 */ 1489 @Test 1490 public void testAutoSaveAddNodes() throws ConfigurationException 1491 { 1492 conf.setFile(testSaveConf); 1493 conf.setAutoSave(true); 1494 HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node( 1495 "addNodesTest", Boolean.TRUE); 1496 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(1); 1497 nodes.add(node); 1498 conf.addNodes("test.autosave", nodes); 1499 XMLConfiguration c2 = new XMLConfiguration(testSaveConf); 1500 assertTrue("Added nodes are not saved", c2 1501 .getBoolean("test.autosave.addNodesTest")); 1502 } 1503 1504 /** 1505 * Tests saving a configuration after a node was added. Test for 1506 * CONFIGURATION-294. 1507 */ 1508 @Test 1509 public void testAddNodesAndSave() throws ConfigurationException 1510 { 1511 ConfigurationNode node = new HierarchicalConfiguration.Node("test"); 1512 ConfigurationNode child = new HierarchicalConfiguration.Node("child"); 1513 node.addChild(child); 1514 ConfigurationNode attr = new HierarchicalConfiguration.Node("attr"); 1515 node.addAttribute(attr); 1516 ConfigurationNode node2 = conf.createNode("test2"); 1517 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(2); 1518 nodes.add(node); 1519 nodes.add(node2); 1520 conf.addNodes("add.nodes", nodes); 1521 conf.setFile(testSaveConf); 1522 conf.save(); 1523 conf.setProperty("add.nodes.test", "true"); 1524 conf.setProperty("add.nodes.test.child", "yes"); 1525 conf.setProperty("add.nodes.test[@attr]", "existing"); 1526 conf.setProperty("add.nodes.test2", "anotherValue"); 1527 conf.save(); 1528 XMLConfiguration c2 = new XMLConfiguration(testSaveConf); 1529 assertEquals("Value was not saved", "true", c2 1530 .getString("add.nodes.test")); 1531 assertEquals("Child value was not saved", "yes", c2 1532 .getString("add.nodes.test.child")); 1533 assertEquals("Attr value was not saved", "existing", c2 1534 .getString("add.nodes.test[@attr]")); 1535 assertEquals("Node2 not saved", "anotherValue", c2 1536 .getString("add.nodes.test2")); 1537 } 1538 1539 /** 1540 * Tests registering the publicId of a DTD. 1541 */ 1542 @Test 1543 public void testRegisterEntityId() throws Exception 1544 { 1545 URL dtdURL = getClass().getResource("/properties.dtd"); 1546 final String publicId = "http://commons.apache.org/test/properties.dtd"; 1547 conf = new XMLConfiguration("testDtd.xml"); 1548 conf.setPublicID(publicId); 1549 conf.save(testSaveConf); 1550 XMLConfiguration checkConfig = new XMLConfiguration(); 1551 checkConfig.setFile(testSaveConf); 1552 checkConfig.registerEntityId(publicId, dtdURL); 1553 checkConfig.setValidating(true); 1554 checkSavedConfig(checkConfig); 1555 } 1556 1557 /** 1558 * Tries to register a null public ID. This should cause an exception. 1559 */ 1560 @Test(expected = IllegalArgumentException.class) 1561 public void testRegisterEntityIdNull() throws IOException 1562 { 1563 conf.registerEntityId(null, new URL("http://commons.apache.org")); 1564 } 1565 1566 /** 1567 * Tests saving a configuration that was created from a hierarchical 1568 * configuration. This test exposes bug CONFIGURATION-301. 1569 */ 1570 @Test 1571 public void testSaveAfterCreateWithCopyConstructor() 1572 throws ConfigurationException 1573 { 1574 HierarchicalConfiguration hc = conf.configurationAt("element2"); 1575 conf = new XMLConfiguration(hc); 1576 conf.save(testSaveConf); 1577 XMLConfiguration checkConfig = new XMLConfiguration(); 1578 checkConfig.setFile(testSaveConf); 1579 checkSavedConfig(checkConfig); 1580 assertEquals("Wrong name of root element", "element2", checkConfig 1581 .getRootElementName()); 1582 } 1583 1584 /** 1585 * Tests whether the name of the root element is copied when a configuration 1586 * is created using the copy constructor. 1587 */ 1588 @Test 1589 public void testCopyRootName() throws ConfigurationException 1590 { 1591 final String rootName = "rootElement"; 1592 final String xml = "<" + rootName + "><test>true</test></" + rootName 1593 + ">"; 1594 conf.clear(); 1595 conf.load(new StringReader(xml)); 1596 XMLConfiguration copy = new XMLConfiguration(conf); 1597 assertEquals("Wrong name of root element", rootName, copy 1598 .getRootElementName()); 1599 copy.save(testSaveConf); 1600 copy = new XMLConfiguration(testSaveConf); 1601 assertEquals("Wrong name of root element after save", rootName, copy 1602 .getRootElementName()); 1603 } 1604 1605 /** 1606 * Tests whether the name of the root element is copied for a configuration 1607 * for which not yet a document exists. 1608 */ 1609 @Test 1610 public void testCopyRootNameNoDocument() throws ConfigurationException 1611 { 1612 final String rootName = "rootElement"; 1613 conf = new XMLConfiguration(); 1614 conf.setRootElementName(rootName); 1615 conf.setProperty("test", Boolean.TRUE); 1616 XMLConfiguration copy = new XMLConfiguration(conf); 1617 assertEquals("Wrong name of root element", rootName, copy 1618 .getRootElementName()); 1619 copy.save(testSaveConf); 1620 copy = new XMLConfiguration(testSaveConf); 1621 assertEquals("Wrong name of root element after save", rootName, copy 1622 .getRootElementName()); 1623 } 1624 1625 /** 1626 * Tests adding an attribute node using the addNodes() method. 1627 */ 1628 @Test 1629 public void testAddNodesAttributeNode() 1630 { 1631 conf.addProperty("testAddNodes.property[@name]", "prop1"); 1632 conf.addProperty("testAddNodes.property(0).value", "value1"); 1633 conf.addProperty("testAddNodes.property(-1)[@name]", "prop2"); 1634 conf.addProperty("testAddNodes.property(1).value", "value2"); 1635 Collection<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); 1636 nodes.add(new HierarchicalConfiguration.Node("property")); 1637 conf.addNodes("testAddNodes", nodes); 1638 nodes.clear(); 1639 ConfigurationNode nd = new HierarchicalConfiguration.Node("name", 1640 "prop3"); 1641 nd.setAttribute(true); 1642 nodes.add(nd); 1643 conf.addNodes("testAddNodes.property(2)", nodes); 1644 assertEquals("Attribute not added", "prop3", conf 1645 .getString("testAddNodes.property(2)[@name]")); 1646 } 1647 1648 /** 1649 * Tests whether spaces are preserved when the xml:space attribute is set. 1650 */ 1651 @Test 1652 public void testPreserveSpace() 1653 { 1654 assertEquals("Wrong value of blanc", " ", conf.getString("space.blanc")); 1655 assertEquals("Wrong value of stars", " * * ", conf 1656 .getString("space.stars")); 1657 } 1658 1659 /** 1660 * Tests whether the xml:space attribute can be overridden in nested 1661 * elements. 1662 */ 1663 @Test 1664 public void testPreserveSpaceOverride() 1665 { 1666 assertEquals("Not trimmed", "Some text", conf 1667 .getString("space.description")); 1668 } 1669 1670 /** 1671 * Tests an xml:space attribute with an invalid value. This will be 1672 * interpreted as default. 1673 */ 1674 @Test 1675 public void testPreserveSpaceInvalid() 1676 { 1677 assertEquals("Invalid not trimmed", "Some other text", conf 1678 .getString("space.testInvalid")); 1679 } 1680 1681 /** 1682 * Tests whether attribute splitting can be disabled. 1683 */ 1684 @Test 1685 public void testAttributeSplittingDisabled() throws ConfigurationException 1686 { 1687 List<Object> values = conf.getList("expressions[@value2]"); 1688 assertEquals("Wrong number of attribute values", 2, values.size()); 1689 assertEquals("Wrong value 1", "a", values.get(0)); 1690 assertEquals("Wrong value 2", "b|c", values.get(1)); 1691 XMLConfiguration conf2 = new XMLConfiguration(); 1692 conf2.setAttributeSplittingDisabled(true); 1693 conf2.setFile(conf.getFile()); 1694 conf2.load(); 1695 assertEquals("Attribute was split", "a,b|c", conf2 1696 .getString("expressions[@value2]")); 1697 } 1698 1699 /** 1700 * Tests disabling both delimiter parsing and attribute splitting. 1701 */ 1702 @Test 1703 public void testAttributeSplittingAndDelimiterParsingDisabled() 1704 throws ConfigurationException 1705 { 1706 conf.clear(); 1707 conf.setDelimiterParsingDisabled(true); 1708 conf.load(); 1709 List<Object> values = conf.getList("expressions[@value2]"); 1710 assertEquals("Wrong number of attribute values", 2, values.size()); 1711 assertEquals("Wrong value 1", "a,b", values.get(0)); 1712 assertEquals("Wrong value 2", "c", values.get(1)); 1713 XMLConfiguration conf2 = new XMLConfiguration(); 1714 conf2.setAttributeSplittingDisabled(true); 1715 conf2.setDelimiterParsingDisabled(true); 1716 conf2.setFile(conf.getFile()); 1717 conf2.load(); 1718 assertEquals("Attribute was split", "a,b|c", conf2 1719 .getString("expressions[@value2]")); 1720 } 1721 1722 /** 1723 * Tests modifying an XML document and saving it with schema validation enabled. 1724 */ 1725 @Test 1726 public void testSaveWithValidation() throws Exception 1727 { 1728 CatalogResolver resolver = new CatalogResolver(); 1729 resolver.setCatalogFiles(CATALOG_FILES); 1730 conf = new XMLConfiguration(); 1731 conf.setEntityResolver(resolver); 1732 conf.setFileName(testFile2); 1733 conf.setSchemaValidation(true); 1734 conf.load(); 1735 conf.setProperty("Employee.SSN", "123456789"); 1736 conf.validate(); 1737 conf.save(testSaveConf); 1738 conf = new XMLConfiguration(testSaveConf); 1739 assertEquals("123456789", conf.getString("Employee.SSN")); 1740 } 1741 1742 /** 1743 * Tests modifying an XML document and validating it against the schema. 1744 */ 1745 @Test 1746 public void testSaveWithValidationFailure() throws Exception 1747 { 1748 CatalogResolver resolver = new CatalogResolver(); 1749 resolver.setCatalogFiles(CATALOG_FILES); 1750 conf = new XMLConfiguration(); 1751 conf.setEntityResolver(resolver); 1752 conf.setFileName(testFile2); 1753 conf.setSchemaValidation(true); 1754 conf.load(); 1755 conf.setProperty("Employee.Email", "JohnDoe@apache.org"); 1756 try 1757 { 1758 conf.validate(); 1759 fail("No validation failure on save"); 1760 } 1761 catch (Exception e) 1762 { 1763 Throwable cause = e.getCause(); 1764 assertNotNull("No cause for exception on save", cause); 1765 assertTrue("Incorrect exception on save", cause instanceof SAXParseException); 1766 } 1767 } 1768 1769 @Test 1770 public void testConcurrentGetAndReload() throws Exception 1771 { 1772 //final FileConfiguration config = new PropertiesConfiguration("test.properties"); 1773 final FileConfiguration config = new XMLConfiguration("test.xml"); 1774 config.setReloadingStrategy(new FileAlwaysReloadingStrategy()); 1775 1776 assertTrue("Property not found", config.getProperty("test.short") != null); 1777 1778 Thread testThreads[] = new Thread[THREAD_COUNT]; 1779 1780 for (int i = 0; i < testThreads.length; ++i) 1781 { 1782 testThreads[i] = new ReloadThread(config); 1783 testThreads[i].start(); 1784 } 1785 1786 for (int i = 0; i < LOOP_COUNT; i++) 1787 { 1788 assertTrue("Property not found", config.getProperty("test.short") != null); 1789 } 1790 1791 for (int i = 0; i < testThreads.length; ++i) 1792 { 1793 testThreads[i].join(); 1794 } 1795 } 1796 1797 /** 1798 * Tests whether a windows path can be saved correctly. This test is related 1799 * to CONFIGURATION-428. 1800 */ 1801 @Test 1802 public void testSaveWindowsPath() throws ConfigurationException 1803 { 1804 conf.clear(); 1805 conf.addProperty("path", "C:\\Temp"); 1806 StringWriter writer = new StringWriter(); 1807 conf.save(writer); 1808 String content = writer.toString(); 1809 assertTrue("Path not found: " + content, 1810 content.indexOf("<path>C:\\Temp</path>") >= 0); 1811 conf.save(testSaveFile); 1812 XMLConfiguration conf2 = new XMLConfiguration(testSaveFile); 1813 assertEquals("Wrong windows path", "C:\\Temp", 1814 conf2.getString("path")); 1815 } 1816 1817 /** 1818 * Tests whether an attribute can be set to an empty string. This test is 1819 * related to CONFIGURATION-446. 1820 */ 1821 @Test 1822 public void testEmptyAttribute() throws ConfigurationException 1823 { 1824 String key = "element3[@value]"; 1825 conf.setProperty(key, ""); 1826 assertTrue("Key not found", conf.containsKey(key)); 1827 assertEquals("Wrong value", "", conf.getString(key)); 1828 conf.save(testSaveConf); 1829 conf = new XMLConfiguration(); 1830 conf.load(testSaveConf); 1831 assertTrue("Key not found after save", conf.containsKey(key)); 1832 assertEquals("Wrong value after save", "", conf.getString(key)); 1833 } 1834 1835 /** 1836 * Tests whether it is possible to add nodes to a XMLConfiguration through a 1837 * SubnodeConfiguration and whether these nodes have the correct type. This 1838 * test is related to CONFIGURATION-472. 1839 */ 1840 @Test 1841 public void testAddNodesToSubnodeConfiguration() throws Exception 1842 { 1843 SubnodeConfiguration sub = conf.configurationAt("element2"); 1844 sub.addProperty("newKey", "newvalue"); 1845 ConfigurationNode root = conf.getRootNode(); 1846 ConfigurationNode elem = root.getChildren("element2").get(0); 1847 ConfigurationNode newNode = elem.getChildren("newKey").get(0); 1848 assertTrue("Wrong node type: " + newNode, 1849 newNode instanceof XMLConfiguration.XMLNode); 1850 } 1851 1852 /** 1853 * Tests whether list properties are set correctly if delimiter 1854 * parsing is disabled. This test is related to CONFIGURATION-495. 1855 */ 1856 @Test 1857 public void testSetPropertyListWithDelimiterParsingDisabled() 1858 throws ConfigurationException 1859 { 1860 String prop = "delimiterListProp"; 1861 conf.setDelimiterParsingDisabled(true); 1862 List<String> list = Arrays.asList("val", "val2", "val3"); 1863 conf.setProperty(prop, list); 1864 conf.setFile(testSaveFile); 1865 conf.save(); 1866 conf.clear(); 1867 conf.load(); 1868 assertEquals("Wrong list property", list, conf.getProperty(prop)); 1869 } 1870 1871 /** 1872 * Tests whether list properties are added correctly if delimiter parsing is 1873 * disabled. This test is related to CONFIGURATION-495. 1874 */ 1875 @Test 1876 public void testAddPropertyListWithDelimiterParsingDisabled() 1877 throws ConfigurationException 1878 { 1879 String prop = "delimiterListProp"; 1880 conf.setDelimiterParsingDisabled(true); 1881 List<String> list = Arrays.asList("val", "val2", "val3"); 1882 conf.addProperty(prop, list); 1883 conf.setFile(testSaveFile); 1884 conf.save(); 1885 conf.clear(); 1886 conf.load(); 1887 assertEquals("Wrong list property", list, conf.getProperty(prop)); 1888 } 1889 1890 /** 1891 * Prepares a configuration object for testing a reload operation. 1892 * 1893 * @return the initialized configuration 1894 * @throws ConfigurationException if an error occurs 1895 */ 1896 private XMLConfiguration setUpReloadTest() throws ConfigurationException 1897 { 1898 removeTestFile(); 1899 conf.save(testSaveConf); 1900 XMLConfiguration c = new XMLConfiguration(testSaveConf); 1901 c.setReloadingStrategy(new FileAlwaysReloadingStrategy()); 1902 conf.setProperty("test(0).entity", "newValue"); 1903 conf.save(testSaveConf); 1904 return c; 1905 } 1906 1907 /** 1908 * Removes the test output file if it exists. 1909 */ 1910 private void removeTestFile() 1911 { 1912 if (testSaveConf.exists()) 1913 { 1914 assertTrue(testSaveConf.delete()); 1915 } 1916 } 1917 1918 /** 1919 * Helper method for checking if a save operation was successful. Loads a 1920 * saved configuration and then tests against a reference configuration. 1921 * @param checkConfig the configuration to check 1922 * @throws ConfigurationException if an error occurs 1923 */ 1924 private void checkSavedConfig(FileConfiguration checkConfig) throws ConfigurationException 1925 { 1926 checkConfig.load(); 1927 ConfigurationAssert.assertEquals(conf, checkConfig); 1928 } 1929 1930 private class ReloadThread extends Thread 1931 { 1932 FileConfiguration config; 1933 1934 ReloadThread(FileConfiguration config) 1935 { 1936 this.config = config; 1937 } 1938 @Override 1939 public void run() 1940 { 1941 for (int i = 0; i < LOOP_COUNT; i++) 1942 { 1943 config.reload(); 1944 } 1945 } 1946 } 1947 }