    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.commons.configuration;
    19
    20  import java.io.ByteArrayInputStream;
    21  import java.io.File;
    22  import java.io.FileOutputStream;
    23  import java.io.FileWriter;
    24  import java.io.IOException;
    25  import java.io.PrintWriter;
    26  import java.io.StringReader;
    27  import java.io.StringWriter;
    28  import java.net.URL;
    29  import java.util.ArrayList;
    30  import java.util.Collection;
    31  import java.util.Iterator;
    32  import java.util.List;
    33
    34  import javax.xml.parsers.DocumentBuilder;
    35  import javax.xml.parsers.DocumentBuilderFactory;
    36
    37  import junit.framework.TestCase;
    38
    39  import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
    40  import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
    41  import org.apache.commons.configuration.tree.ConfigurationNode;
    42  import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
    43  import org.xml.sax.SAXException;
    44  import org.xml.sax.SAXParseException;
    45  import org.xml.sax.helpers.DefaultHandler;
    46
    47  /***
    48   * test for loading and saving xml properties files
    49   *
    50   * @version $Id: TestXMLConfiguration.java 721895 2008-11-30 21:08:42Z oheger $
    51   */
    52  public class TestXMLConfiguration extends TestCase
    53  {
    54      /*** Constant for the used encoding.*/
    55      static final String ENCODING = "ISO-8859-1";
    56
    57      /*** Constant for the test system ID.*/
    58      static final String SYSTEM_ID = "properties.dtd";
    59
    60      /*** Constant for the test public ID.*/
    61      static final String PUBLIC_ID = "-//Commons Configuration//DTD Test Configuration 1.3//EN";
    62
    63      /*** Constant for the DOCTYPE declaration.*/
    64      static final String DOCTYPE_DECL = " PUBLIC \"" + PUBLIC_ID + "\" \"" + SYSTEM_ID + "\">";
    65
    66      /*** Constant for the DOCTYPE prefix.*/
    67      static final String DOCTYPE = "<!DOCTYPE ";
    68
    69      /*** Constant for the transformer factory property.*/
    70      static final String PROP_FACTORY = "javax.xml.transform.TransformerFactory";
    71
    72      /*** The File that we test with */
    73      private String testProperties = new File("conf/test.xml").getAbsolutePath();
    74      private String testProperties2 = new File("conf/testDigesterConfigurationInclude1.xml").getAbsolutePath();
    75      private String testBasePath = new File("conf").getAbsolutePath();
    76      private File testSaveConf = new File("target/testsave.xml");
    77
    78      private XMLConfiguration conf;
    79
    80      protected void setUp() throws Exception
    81      {
    82          conf = new XMLConfiguration();
    83          conf.setFile(new File(testProperties));
    84          conf.load();
    85          removeTestFile();
    86      }
    87
    88      public void testGetProperty()
    89      {
    90          assertEquals("value", conf.getProperty("element"));
    91      }
    92
    93      public void testGetCommentedProperty()
    94      {
    95          assertEquals("", conf.getProperty("test.comment"));
    96      }
    97
    98      public void testGetPropertyWithXMLEntity()
    99      {
    100         assertEquals("1<2", conf.getProperty("test.entity"));
    101     }
    102
    103     public void testClearProperty() throws ConfigurationException, IOException
    104     {
    105         // test non-existent element
    106         String key = "clearly";
    107         conf.clearProperty(key);
    108         assertNull(key, conf.getProperty(key));
    109         assertNull(key, conf.getProperty(key));
    110
    111         // test single element
    112         conf.load();
    113         key = "clear.element";
    114         conf.clearProperty(key);
    115         assertNull(key, conf.getProperty(key));
    116         assertNull(key, conf.getProperty(key));
    117
    118         // test single element with attribute
    119         conf.load();
    120         key = "clear.element2";
    121         conf.clearProperty(key);
    122         assertNull(key, conf.getProperty(key));
    123         assertNull(key, conf.getProperty(key));
    124         key = "clear.element2[@id]";
    125         assertNotNull(key, conf.getProperty(key));
    126         assertNotNull(key, conf.getProperty(key));
    127
    128         // test non-text/cdata element
    129         conf.load();
    130         key = "clear.comment";
    131         conf.clearProperty(key);
    132         assertNull(key, conf.getProperty(key));
    133         assertNull(key, conf.getProperty(key));
    134
    135         // test cdata element
    136         conf.load();
    137         key = "clear.cdata";
    138         conf.clearProperty(key);
    139         assertNull(key, conf.getProperty(key));
    140         assertNull(key, conf.getProperty(key));
    141
    142         // test multiple sibling elements
    143         conf.load();
    144         key = "clear.list.item";
    145         conf.clearProperty(key);
    146         assertNull(key, conf.getProperty(key));
    147         assertNull(key, conf.getProperty(key));
    148         key = "clear.list.item[@id]";
    149         assertNotNull(key, conf.getProperty(key));
    150         assertNotNull(key, conf.getProperty(key));
    151
    152         // test multiple, disjoined elements
    153         conf.load();
    154         key = "list.item";
    155         conf.clearProperty(key);
    156         assertNull(key, conf.getProperty(key));
    157         assertNull(key, conf.getProperty(key));
    158     }
    159
    160     public void testgetProperty() {
    161         // test non-leaf element
    162         Object property = conf.getProperty("clear");
    163         assertNull(property);
    164
    165         // test non-existent element
    166         property = conf.getProperty("e");
    167         assertNull(property);
    168
    169         // test non-existent element
    170         property = conf.getProperty("element3[@n]");
    171         assertNull(property);
    172
    173         // test single element
    174         property = conf.getProperty("element");
    175         assertNotNull(property);
    176         assertTrue(property instanceof String);
    177         assertEquals("value", property);
    178
    179         // test single attribute
    180         property = conf.getProperty("element3[@name]");
    181         assertNotNull(property);
    182         assertTrue(property instanceof String);
    183         assertEquals("foo", property);
    184
    185         // test non-text/cdata element
    186         property = conf.getProperty("test.comment");
    187         assertEquals("", property);
    188
    189         // test cdata element
    190         property = conf.getProperty("test.cdata");
    191         assertNotNull(property);
    192         assertTrue(property instanceof String);
    193         assertEquals("<cdata value>", property);
    194
    195         // test multiple sibling elements
    196         property = conf.getProperty("list.sublist.item");
    197         assertNotNull(property);
    198         assertTrue(property instanceof List);
    199         List list = (List)property;
    200         assertEquals(2, list.size());
    201         assertEquals("five", list.get(0));
    202         assertEquals("six", list.get(1));
    203
    204         // test multiple, disjoined elements
    205         property = conf.getProperty("list.item");
    206         assertNotNull(property);
    207         assertTrue(property instanceof List);
    208         list = (List)property;
    209         assertEquals(4, list.size());
    210         assertEquals("one", list.get(0));
    211         assertEquals("two", list.get(1));
    212         assertEquals("three", list.get(2));
    213         assertEquals("four", list.get(3));
    214
    215         // test multiple, disjoined attributes
    216         property = conf.getProperty("list.item[@name]");
    217         assertNotNull(property);
    218         assertTrue(property instanceof List);
    219         list = (List)property;
    220         assertEquals(2, list.size());
    221         assertEquals("one", list.get(0));
    222         assertEquals("three", list.get(1));
    223     }
    224
    225     public void testGetAttribute()
    226     {
    227         assertEquals("element3[@name]", "foo", conf.getProperty("element3[@name]"));
    228     }
    229
    230     public void testClearAttribute() throws Exception
    231     {
    232         // test non-existent attribute
    233         String key = "clear[@id]";
    234         conf.clearProperty(key);
    235         assertNull(key, conf.getProperty(key));
    236         assertNull(key, conf.getProperty(key));
    237
    238         // test single attribute
    239         conf.load();
    240         key = "clear.element2[@id]";
    241         conf.clearProperty(key);
    242         assertNull(key, conf.getProperty(key));
    243         assertNull(key, conf.getProperty(key));
    244         key = "clear.element2";
    245         assertNotNull(key, conf.getProperty(key));
    246         assertNotNull(key, conf.getProperty(key));
    247
    248         // test multiple, disjoined attributes
    249         conf.load();
    250         key = "clear.list.item[@id]";
    251         conf.clearProperty(key);
    252         assertNull(key, conf.getProperty(key));
    253         assertNull(key, conf.getProperty(key));
    254         key = "clear.list.item";
    255         assertNotNull(key, conf.getProperty(key));
    256         assertNotNull(key, conf.getProperty(key));
    257     }
    258
    259     public void testSetAttribute()
    260     {
    261         // replace an existing attribute
    262         conf.setProperty("element3[@name]", "bar");
    263         assertEquals("element3[@name]", "bar", conf.getProperty("element3[@name]"));
    264
    265         // set a new attribute
    266         conf.setProperty("foo[@bar]", "value");
    267         assertEquals("foo[@bar]", "value", conf.getProperty("foo[@bar]"));
    268
    269         conf.setProperty("name1","value1");
    270         assertEquals("value1",conf.getProperty("name1"));
    271     }
    272
    273     public void testAddAttribute()
    274     {
    275         conf.addProperty("element3[@name]", "bar");
    276
    277         List list = conf.getList("element3[@name]");
    278         assertNotNull("null list", list);
    279         assertTrue("'foo' element missing", list.contains("foo"));
    280         assertTrue("'bar' element missing", list.contains("bar"));
    281         assertEquals("list size", 2, list.size());
    282     }
    283
    284     public void testAddObjectAttribute()
    285     {
    286         conf.addProperty("test.boolean[@value]", Boolean.TRUE);
    287         assertTrue("test.boolean[@value]", conf.getBoolean("test.boolean[@value]"));
    288     }
    289
    290     /***
    291      * Tests setting an attribute on the root element.
    292      */
    293     public void testSetRootAttribute() throws ConfigurationException
    294     {
    295         conf.setProperty("[@test]", "true");
    296         assertEquals("Root attribute not set", "true", conf
    297                 .getString("[@test]"));
    298         conf.save(testSaveConf);
    299         XMLConfiguration checkConf = new XMLConfiguration();
    300         checkConf.setFile(testSaveConf);
    301         checkSavedConfig(checkConf);
    302         assertTrue("Attribute not found after save", checkConf
    303                 .containsKey("[@test]"));
    304         checkConf.setProperty("[@test]", "newValue");
    305         checkConf.save();
    306         conf = checkConf;
    307         checkConf = new XMLConfiguration();
    308         checkConf.setFile(testSaveConf);
    309         checkSavedConfig(checkConf);
    310         assertEquals("Attribute not modified after save", "newValue", checkConf
    311                 .getString("[@test]"));
    312     }
    313
    314     /***
    315      * Tests whether the configuration's root node is initialized with a
    316      * reference to the corresponding XML element.
    317      */
    318     public void testGetRootReference()
    319     {
    320         assertNotNull("Root node has no reference", conf.getRootNode()
    321                 .getReference());
    322     }
    323
    324     public void testAddList()
    325     {
    326         conf.addProperty("test.array", "value1");
    327         conf.addProperty("test.array", "value2");
    328
    329         List list = conf.getList("test.array");
    330         assertNotNull("null list", list);
    331         assertTrue("'value1' element missing", list.contains("value1"));
    332         assertTrue("'value2' element missing", list.contains("value2"));
    333         assertEquals("list size", 2, list.size());
    334     }
    335
    336     public void testGetComplexProperty()
    337     {
    338         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    339     }
    340
    341     public void testSettingFileNames()
    342     {
    343         conf = new XMLConfiguration();
    344         conf.setFileName(testProperties);
    345         assertEquals(testProperties.toString(), conf.getFileName());
    346
    347         conf.setBasePath(testBasePath);
    348         conf.setFileName("hello.xml");
    349         assertEquals("hello.xml", conf.getFileName());
    350         assertEquals(testBasePath.toString(), conf.getBasePath());
    351         assertEquals(new File(testBasePath, "hello.xml"), conf.getFile());
    352
    353         conf.setBasePath(testBasePath);
    354         conf.setFileName("subdir/hello.xml");
    355         assertEquals("subdir/hello.xml", conf.getFileName());
    356         assertEquals(testBasePath.toString(), conf.getBasePath());
    357         assertEquals(new File(testBasePath, "subdir/hello.xml"), conf.getFile());
    358     }
    359
    360     public void testLoad() throws Exception
    361     {
    362         conf = new XMLConfiguration();
    363         conf.setFileName(testProperties);
    364         conf.load();
    365
    366         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    367     }
    368
    369     public void testLoadWithBasePath() throws Exception
    370     {
    371         conf = new XMLConfiguration();
    372
    373         conf.setFileName("test.xml");
    374         conf.setBasePath(testBasePath);
    375         conf.load();
    376
    377         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    378     }
    379
    380     /***
    381      * Tests constructing an XMLConfiguration from a non existing file and
    382      * later saving to this file.
    383      */
    384     public void testLoadAndSaveFromFile() throws Exception
    385     {
    386         // If the file does not exist, an empty config is created
    387         conf = new XMLConfiguration(testSaveConf);
    388         assertTrue(conf.isEmpty());
    389         conf.addProperty("test", "yes");
    390         conf.save();
    391
    392         conf = new XMLConfiguration(testSaveConf);
    393         assertEquals("yes", conf.getString("test"));
    394     }
    395
    396     /***
    397      * Tests loading a configuration from a URL.
    398      */
    399     public void testLoadFromURL() throws Exception
    400     {
    401         URL url = new File(testProperties).toURL();
    402         conf = new XMLConfiguration(url);
    403         assertEquals("value", conf.getProperty("element"));
    404         assertEquals(url, conf.getURL());
    405     }
    406
    407     /***
    408      * Tests loading from a stream.
    409      */
    410     public void testLoadFromStream() throws Exception
    411     {
    412         String xml = "<?xml version=\"1.0\"?><config><test>1</test></config>";
    413         conf = new XMLConfiguration();
    414         conf.load(new ByteArrayInputStream(xml.getBytes()));
    415         assertEquals(1, conf.getInt("test"));
    416
    417         conf = new XMLConfiguration();
    418         conf.load(new ByteArrayInputStream(xml.getBytes()), "UTF8");
    419         assertEquals(1, conf.getInt("test"));
    420     }
    421
    422     /***
    423      * Tests loading a non well formed XML from a string.
    424      */
    425     public void testLoadInvalidXML() throws Exception
    426     {
    427         String xml = "<?xml version=\"1.0\"?><config><test>1</rest></config>";
    428         conf = new XMLConfiguration();
    429         try
    430         {
    431             conf.load(new StringReader(xml));
    432             fail("Could load invalid XML!");
    433         }
    434         catch(ConfigurationException cex)
    435         {
    436             //ok
    437         }
    438     }
    439
    440     public void testSetProperty() throws Exception
    441     {
    442         conf.setProperty("element.string", "hello");
    443
    444         assertEquals("'element.string'", "hello", conf.getString("element.string"));
    445         assertEquals("XML value of element.string", "hello", conf.getProperty("element.string"));
    446     }
    447
    448     public void testAddProperty()
    449     {
    450         // add a property to a non initialized xml configuration
    451         XMLConfiguration config = new XMLConfiguration();
    452         config.addProperty("test.string", "hello");
    453
    454         assertEquals("'test.string'", "hello", config.getString("test.string"));
    455     }
    456
    457     public void testAddObjectProperty()
    458     {
    459         // add a non string property
    460         conf.addProperty("test.boolean", Boolean.TRUE);
    461         assertTrue("'test.boolean'", conf.getBoolean("test.boolean"));
    462     }
    463
    464     public void testSave() throws Exception
    465     {
    466         // add an array of strings to the configuration
    467         conf.addProperty("string", "value1");
    468         for (int i = 1; i < 5; i++)
    469         {
    470             conf.addProperty("test.array", "value" + i);
    471         }
    472
    473         // add an array of strings in an attribute
    474         for (int i = 1; i < 5; i++)
    475         {
    476            conf.addProperty("test.attribute[@array]", "value" + i);
    477         }
    478
    479         // add comma delimited lists with escaped delimiters
    480         conf.addProperty("split.list5", "a//,b//,c");
    481         conf.setProperty("element3", "value//,value1//,value2");
    482         conf.setProperty("element3[@name]", "foo//,bar");
    483
    484         // save the configuration
    485         conf.save(testSaveConf.getAbsolutePath());
    486
    487         // read the configuration and compare the properties
    488         XMLConfiguration checkConfig = new XMLConfiguration();
    489         checkConfig.setFileName(testSaveConf.getAbsolutePath());
    490         checkSavedConfig(checkConfig);
    491     }
    492
    493     /***
    494      * Tests saving to a URL.
    495      */
    496     public void testSaveToURL() throws Exception
    497     {
    498         conf.save(testSaveConf.toURL());
    499         XMLConfiguration checkConfig = new XMLConfiguration();
    500         checkConfig.setFile(testSaveConf);
    501         checkSavedConfig(checkConfig);
    502     }
    503
    504     /***
    505      * Tests saving to a stream.
    506      */
    507     public void testSaveToStream() throws Exception
    508     {
    509         assertNull(conf.getEncoding());
    510         conf.setEncoding("UTF8");
    511         FileOutputStream out = null;
    512         try
    513         {
    514             out = new FileOutputStream(testSaveConf);
    515             conf.save(out);
    516         }
    517         finally
    518         {
    519             if(out != null)
    520             {
    521                 out.close();
    522             }
    523         }
    524
    525         XMLConfiguration checkConfig = new XMLConfiguration();
    526         checkConfig.setFile(testSaveConf);
    527         checkSavedConfig(checkConfig);
    528
    529         try
    530         {
    531             out = new FileOutputStream(testSaveConf);
    532             conf.save(out, "UTF8");
    533         }
    534         finally
    535         {
    536             if(out != null)
    537             {
    538                 out.close();
    539             }
    540         }
    541
    542         checkConfig.clear();
    543         checkSavedConfig(checkConfig);
    544     }
    545
    546     public void testAutoSave() throws Exception
    547     {
    548         conf.setFile(testSaveConf);
    549         assertFalse(conf.isAutoSave());
    550         conf.setAutoSave(true);
    551         assertTrue(conf.isAutoSave());
    552         conf.setProperty("autosave", "ok");
    553
    554         // reload the configuration
    555         XMLConfiguration conf2 = new XMLConfiguration(conf.getFile());
    556         assertEquals("'autosave' property", "ok", conf2.getString("autosave"));
    557
    558         conf.clearTree("clear");
    559         conf2 = new XMLConfiguration(conf.getFile());
    560         Configuration sub = conf2.subset("clear");
    561         assertTrue(sub.isEmpty());
    562     }
    563
    564     /***
    565      * Tests if a second file can be appended to a first.
    566      */
    567     public void testAppend() throws Exception
    568     {
    569         conf = new XMLConfiguration();
    570         conf.setFileName(testProperties);
    571         conf.load();
    572         conf.load(testProperties2);
    573         assertEquals("value", conf.getString("element"));
    574         assertEquals("tasks", conf.getString("table.name"));
    575
    576         conf.save(testSaveConf);
    577         conf = new XMLConfiguration(testSaveConf);
    578         assertEquals("value", conf.getString("element"));
    579         assertEquals("tasks", conf.getString("table.name"));
    580         assertEquals("application", conf.getString("table[@tableType]"));
    581     }
    582
    583     /***
    584      * Tests saving attributes (related to issue 34442).
    585      */
    586     public void testSaveAttributes() throws Exception
    587     {
    588         conf.clear();
    589         conf.load();
    590         conf.save(testSaveConf);
    591         conf = new XMLConfiguration();
    592         conf.load(testSaveConf);
    593         assertEquals("foo", conf.getString("element3[@name]"));
    594     }
    595
    596     /***
    597      * Tests collaboration between XMLConfiguration and a reloading strategy.
    598      */
    599     public void testReloading() throws Exception
    600     {
    601         assertNotNull(conf.getReloadingStrategy());
    602         assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy);
    603         PrintWriter out = null;
    604
    605         try
    606         {
    607             out = new PrintWriter(new FileWriter(testSaveConf));
    608             out.println("<?xml version=\"1.0\"?><config><test>1</test></config>");
    609             out.close();
    610             out = null;
    611             conf.setFile(testSaveConf);
    612             FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy();
    613             strategy.setRefreshDelay(100);
    614             conf.setReloadingStrategy(strategy);
    615             assertEquals(strategy, conf.getReloadingStrategy());
    616             assertEquals("Wrong file monitored", testSaveConf.getAbsolutePath(),
    617                     strategy.getMonitoredFile().getAbsolutePath());
    618             conf.load();
    619             assertEquals(1, conf.getInt("test"));
    620
    621             out = new PrintWriter(new FileWriter(testSaveConf));
    622             out.println("<?xml version=\"1.0\"?><config><test>2</test></config>");
    623             out.close();
    624             out = null;
    625
    626             int value = conf.getInt("test");
    627             assertEquals("No reloading performed", 2, value);
    628         }
    629         finally
    630         {
    631             if (out != null)
    632             {
    633                 out.close();
    634             }
    635         }
    636     }
    637
    638     /***
    639      * Tests access to tag names with delimiter characters.
    640      */
    641     public void testComplexNames()
    642     {
    643         assertEquals("Name with dot", conf.getString("complexNames.my..elem"));
    644         assertEquals("Another dot", conf.getString("complexNames.my..elem.sub..elem"));
    645     }
    646
    647     /***
    648      * Tests setting a custom document builder.
    649      */
    650     public void testCustomDocBuilder() throws Exception
    651     {
    652         // Load an invalid XML file with the default (non validating)
    653         // doc builder. This should work...
    654         conf = new XMLConfiguration();
    655         conf.load(new File("conf/testValidateInvalid.xml"));
    656         assertEquals("customers", conf.getString("table.name"));
    657         assertFalse(conf.containsKey("table.fields.field(1).type"));
    658
    659         // Now create a validating doc builder and set it.
    660         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    661         factory.setValidating(true);
    662         DocumentBuilder builder = factory.newDocumentBuilder();
    663         builder.setErrorHandler(new DefaultHandler() {
    664             public void error(SAXParseException ex) throws SAXException
    665             {
    666                 throw ex;
    667             }
    668         });
    669         conf = new XMLConfiguration();
    670         conf.setDocumentBuilder(builder);
    671         try
    672         {
    673             conf.load(new File("conf/testValidateInvalid.xml"));
    674             fail("Could load invalid file with validating set to true!");
    675         }
    676         catch(ConfigurationException ex)
    677         {
    678             //ok
    679         }
    680
    681         // Try to load a valid document with a validating builder
    682         conf = new XMLConfiguration();
    683         conf.setDocumentBuilder(builder);
    684         conf.load(new File("conf/testValidateValid.xml"));
    685         assertTrue(conf.containsKey("table.fields.field(1).type"));
    686     }
    687
    688     /***
    689      * Tests the clone() method.
    690      */
    691     public void testClone()
    692     {
    693         Configuration c = (Configuration) conf.clone();
    694         assertTrue(c instanceof XMLConfiguration);
    695         XMLConfiguration copy = (XMLConfiguration) c;
    696         assertNotNull(conf.getDocument());
    697         assertNull(copy.getDocument());
    698         assertNotNull(conf.getFileName());
    699         assertNull(copy.getFileName());
    700
    701         copy.setProperty("element3", "clonedValue");
    702         assertEquals("value", conf.getString("element3"));
    703         conf.setProperty("element3[@name]", "originalFoo");
    704         assertEquals("foo", copy.getString("element3[@name]"));
    705     }
    706
    707     /***
    708      * Tests saving a configuration after cloning to ensure that the clone and
    709      * the original are completely detachted.
    710      */
    711     public void testCloneWithSave() throws ConfigurationException
    712     {
    713         XMLConfiguration c = (XMLConfiguration) conf.clone();
    714         c.addProperty("test.newProperty", Boolean.TRUE);
    715         conf.addProperty("test.orgProperty", Boolean.TRUE);
    716         c.save(testSaveConf);
    717         XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
    718         assertTrue("New property after clone() was not saved", c2
    719                 .getBoolean("test.newProperty"));
    720         assertFalse("Property of original config was saved", c2
    721                 .containsKey("test.orgProperty"));
    722     }
    723
    724     /***
    725      * Tests the subset() method. There was a bug that calling subset() had
    726      * undesired side effects.
    727      */
    728     public void testSubset() throws ConfigurationException
    729     {
    730         conf = new XMLConfiguration();
    731         conf.load(new File("conf/testHierarchicalXMLConfiguration.xml"));
    732         conf.subset("tables.table(0)");
    733         conf.save(testSaveConf);
    734
    735         conf = new XMLConfiguration(testSaveConf);
    736         assertEquals("users", conf.getString("tables.table(0).name"));
    737     }
    738
    739     /***
    740      * Tests string properties with list delimiters and escaped delimiters.
    741      */
    742     public void testSplitLists()
    743     {
    744         assertEquals("a", conf.getString("split.list3[@values]"));
    745         assertEquals(2, conf.getMaxIndex("split.list3[@values]"));
    746         assertEquals("a,b,c", conf.getString("split.list4[@values]"));
    747         assertEquals("a", conf.getString("split.list1"));
    748         assertEquals(2, conf.getMaxIndex("split.list1"));
    749         assertEquals("a,b,c", conf.getString("split.list2"));
    750     }
    751
    752     /***
    753      * Tests string properties with list delimiters when delimiter parsing
    754      * is disabled
    755      */
    756     public void testDelimiterParsingDisabled() throws ConfigurationException {
    757         XMLConfiguration conf2 = new XMLConfiguration();
    758         conf2.setDelimiterParsingDisabled(true);
    759         conf2.setFile(new File(testProperties));
    760         conf2.load();
    761
    762         assertEquals("a,b,c", conf2.getString("split.list3[@values]"));
    763         assertEquals(0, conf2.getMaxIndex("split.list3[@values]"));
    764         assertEquals("a//,b//,c", conf2.getString("split.list4[@values]"));
    765         assertEquals("a,b,c", conf2.getString("split.list1"));
    766         assertEquals(0, conf2.getMaxIndex("split.list1"));
    767         assertEquals("a//,b//,c", conf2.getString("split.list2"));
    768     }
    769
    770     /***
    771      * Tests whether a DTD can be accessed.
    772      */
    773     public void testDtd() throws ConfigurationException
    774     {
    775         conf = new XMLConfiguration("testDtd.xml");
    776         assertEquals("value1", conf.getString("entry(0)"));
    777         assertEquals("test2", conf.getString("entry(1)[@key]"));
    778     }
    779
    780     /***
    781      * Tests DTD validation using the setValidating() method.
    782      */
    783     public void testValidating() throws ConfigurationException
    784     {
    785         File nonValidFile = new File("conf/testValidateInvalid.xml");
    786         conf = new XMLConfiguration();
    787         assertFalse(conf.isValidating());
    788
    789         // Load a non valid XML document. Should work for isValidating() == false
    790         conf.load(nonValidFile);
    791         assertEquals("customers", conf.getString("table.name"));
    792         assertFalse(conf.containsKey("table.fields.field(1).type"));
    793
    794         // Now set the validating flag to true
    795         conf.setValidating(true);
    796         try
    797         {
    798             conf.load(nonValidFile);
    799             fail("Validation was not performed!");
    800         }
    801         catch(ConfigurationException cex)
    802         {
    803             //ok
    804         }
    805     }
    806
    807     /***
    808      * Tests handling of empty elements.
    809      */
    810     public void testEmptyElements() throws ConfigurationException
    811     {
    812         assertTrue(conf.containsKey("empty"));
    813         assertEquals("", conf.getString("empty"));
    814         conf.addProperty("empty2", "");
    815         conf.setProperty("empty", "no more empty");
    816         conf.save(testSaveConf);
    817
    818         conf = new XMLConfiguration(testSaveConf);
    819         assertEquals("no more empty", conf.getString("empty"));
    820         assertEquals("", conf.getProperty("empty2"));
    821     }
    822
    823     /***
    824      * Tests whether the encoding is correctly detected by the XML parser. This
    825      * is done by loading an XML file with the encoding "UTF-16". If this
    826      * encoding is not detected correctly, an exception will be thrown that
    827      * "Content is not allowed in prolog". This test case is related to issue
    828      * 34204.
    829      */
    830     public void testLoadWithEncoding() throws ConfigurationException
    831     {
    832         File file = new File("conf/testEncoding.xml");
    833         conf = new XMLConfiguration();
    834         conf.load(file);
    835         assertEquals("test3_yoge", conf.getString("yoge"));
    836     }
    837
    838     /***
    839      * Tests whether the encoding is written to the generated XML file.
    840      */
    841     public void testSaveWithEncoding() throws ConfigurationException
    842     {
    843         conf = new XMLConfiguration();
    844         conf.setProperty("test", "a value");
    845         conf.setEncoding(ENCODING);
    846
    847         StringWriter out = new StringWriter();
    848         conf.save(out);
    849         assertTrue("Encoding was not written to file", out.toString().indexOf(
    850                 "encoding=\"" + ENCODING + "\"") >= 0);
    851     }
    852
    853     /***
    854      * Tests whether a default encoding is used if no specific encoding is set.
    855      * According to the XSLT specification (http://www.w3.org/TR/xslt#output)
    856      * this should be either UTF-8 or UTF-16.
    857      */
    858     public void testSaveWithNullEncoding() throws ConfigurationException
    859     {
    860         conf = new XMLConfiguration();
    861         conf.setProperty("testNoEncoding", "yes");
    862         conf.setEncoding(null);
    863
    864         StringWriter out = new StringWriter();
    865         conf.save(out);
    866         assertTrue("Encoding was written to file", out.toString().indexOf(
    867                 "encoding=\"UTF-") >= 0);
    868     }
    869
    870     /***
    871      * Tests whether the DOCTYPE survives a save operation.
    872      */
    873     public void testSaveWithDoctype() throws ConfigurationException
    874     {
    875         String content = "<?xml  version=\"1.0\"?>"
    876                 + DOCTYPE
    877                 + "properties"
    878                 + DOCTYPE_DECL
    879                 + "<properties version=\"1.0\"><entry key=\"test\">value</entry></properties>";
    880         StringReader in = new StringReader(content);
    881         conf = new XMLConfiguration();
    882         conf.setFileName("conf/testDtd.xml");
    883         conf.load();
    884         conf.clear();
    885         conf.load(in);
    886
    887         assertEquals("Wrong public ID", PUBLIC_ID, conf.getPublicID());
    888         assertEquals("Wrong system ID", SYSTEM_ID, conf.getSystemID());
    889         StringWriter out = new StringWriter();
    890         conf.save(out);
    891         System.out.println(out.toString());
    892         assertTrue("Did not find DOCTYPE", out.toString().indexOf(DOCTYPE) >= 0);
    893     }
    894
    895     /***
    896      * Tests setting public and system IDs for the D'OCTYPE and then saving the
    897      * configuration. This should generate a DOCTYPE declaration.
    898      */
    899     public void testSaveWithDoctypeIDs() throws ConfigurationException
    900     {
    901         assertNull("A public ID was found", conf.getPublicID());
    902         assertNull("A system ID was found", conf.getSystemID());
    903         conf.setPublicID(PUBLIC_ID);
    904         conf.setSystemID(SYSTEM_ID);
    905         StringWriter out = new StringWriter();
    906         conf.save(out);
    907         assertTrue("Did not find DOCTYPE", out.toString().indexOf(
    908                 DOCTYPE + "testconfig" + DOCTYPE_DECL) >= 0);
    909     }
    910
    911     /***
    912      * Tests saving a configuration when an invalid transformer factory is
    913      * specified. In this case the error thrown by the TransformerFactory class
    914      * should be caught and re-thrown as a ConfigurationException.
    915      */
    916     public void testSaveWithInvalidTransformerFactory()
    917     {
    918         System.setProperty(PROP_FACTORY, "an.invalid.Class");
    919         try
    920         {
    921             conf.save(testSaveConf);
    922             fail("Could save with invalid TransformerFactory!");
    923         }
    924         catch (ConfigurationException cex)
    925         {
    926             // ok
    927         }
    928         finally
    929         {
    930             System.getProperties().remove(PROP_FACTORY);
    931         }
    932     }
    933
    934     /***
    935      * Tests if reloads are recognized by subset().
    936      */
    937     public void testSubsetWithReload() throws ConfigurationException
    938     {
    939         XMLConfiguration c = setUpReloadTest();
    940         Configuration sub = c.subset("test");
    941         assertEquals("New value not read", "newValue", sub.getString("entity"));
    942     }
    943
    944     /***
    945      * Tests if reloads are recognized by configurationAt().
    946      */
    947     public void testConfigurationAtWithReload() throws ConfigurationException
    948     {
    949         XMLConfiguration c = setUpReloadTest();
    950         HierarchicalConfiguration sub = c.configurationAt("test(0)");
    951         assertEquals("New value not read", "newValue", sub.getString("entity"));
    952     }
    953
    954     /***
    955      * Tests if reloads are recognized by configurationsAt().
    956      */
    957     public void testConfigurationsAtWithReload() throws ConfigurationException
    958     {
    959         XMLConfiguration c = setUpReloadTest();
    960         List configs = c.configurationsAt("test");
    961         assertEquals("New value not read", "newValue",
    962                 ((HierarchicalConfiguration) configs.get(0))
    963                         .getString("entity"));
    964     }
    965
    966     /***
    967      * Tests whether reloads are recognized when querying the configuration's
    968      * keys.
    969      */
    970     public void testGetKeysWithReload() throws ConfigurationException
    971     {
    972         XMLConfiguration c = setUpReloadTest();
    973         conf.addProperty("aNewKey", "aNewValue");
    974         conf.save(testSaveConf);
    975         boolean found = false;
    976         for (Iterator it = c.getKeys(); it.hasNext();)
    977         {
    978             if ("aNewKey".equals(it.next()))
    979             {
    980                 found = true;
    981             }
    982         }
    983         assertTrue("Reload not performed", found);
    984     }
    985
    986     /***
    987      * Tests accessing properties when the XPATH expression engine is set.
    988      */
    989     public void testXPathExpressionEngine()
    990     {
    991         conf.setExpressionEngine(new XPathExpressionEngine());
    992         assertEquals("Wrong attribute value", "foo\"bar", conf
    993                 .getString("test[1]/entity/@name"));
    994         conf.clear();
    995         assertNull(conf.getString("test[1]/entity/@name"));
    996     }
    997
    998     /***
    999      * Tests the copy constructor.
    1000      */
    1001     public void testInitCopy() throws ConfigurationException
    1002     {
    1003     	XMLConfiguration copy = new XMLConfiguration(conf);
    1004         assertEquals("value", copy.getProperty("element"));
    1005         assertNull("Document was copied, too", copy.getDocument());
    1006         ConfigurationNode root = copy.getRootNode();
    1007         for(Iterator it = root.getChildren().iterator(); it.hasNext();)
    1008         {
    1009         	ConfigurationNode node = (ConfigurationNode) it.next();
    1010         	assertNull("Reference was not cleared", node.getReference());
    1011         }
    1012
    1013         removeTestFile();
    1014         copy.setFile(testSaveConf);
    1015         copy.save();
    1016         copy.clear();
    1017         checkSavedConfig(copy);
    1018     }
    1019
    1020     /***
    1021      * Tests setting text of the root element.
    1022      */
    1023     public void testSetTextRootElement() throws ConfigurationException
    1024     {
    1025         conf.setProperty("", "Root text");
    1026         conf.save(testSaveConf);
    1027         XMLConfiguration copy = new XMLConfiguration();
    1028         copy.setFile(testSaveConf);
    1029         checkSavedConfig(copy);
    1030     }
    1031
    1032     /***
    1033      * Tests removing the text of the root element.
    1034      */
    1035     public void testClearTextRootElement() throws ConfigurationException
    1036     {
    1037         final String xml = "<e a=\"v\">text</e>";
    1038         conf.clear();
    1039         StringReader in = new StringReader(xml);
    1040         conf.load(in);
    1041         assertEquals("Wrong text of root", "text", conf.getString(""));
    1042
    1043         conf.clearProperty("");
    1044         conf.save(testSaveConf);
    1045         XMLConfiguration copy = new XMLConfiguration();
    1046         copy.setFile(testSaveConf);
    1047         checkSavedConfig(copy);
    1048     }
    1049
    1050     /***
    1051      * Tests list nodes with multiple values and attributes.
    1052      */
    1053     public void testListWithAttributes()
    1054     {
    1055         assertEquals("Wrong number of <a> elements", 6, conf.getList(
    1056                 "attrList.a").size());
    1057         assertEquals("Wrong value of first element", "ABC", conf
    1058                 .getString("attrList.a(0)"));
    1059         assertEquals("Wrong value of first name attribute", "x", conf
    1060                 .getString("attrList.a(0)[@name]"));
    1061         assertEquals("Wrong number of name attributes", 5, conf.getList(
    1062                 "attrList.a[@name]").size());
    1063     }
    1064
    1065     /***
    1066      * Tests a list node with attributes that has multiple values separated by
    1067      * the list delimiter. In this scenario the attribute should be added to the
    1068      * node with the first value.
    1069      */
    1070     public void testListWithAttributesMultiValue()
    1071     {
    1072         assertEquals("Wrong value of 2nd element", "1", conf
    1073                 .getString("attrList.a(1)"));
    1074         assertEquals("Wrong value of 2nd name attribute", "y", conf
    1075                 .getString("attrList.a(1)[@name]"));
    1076         for (int i = 2; i <= 3; i++)
    1077         {
    1078             assertEquals("Wrong value of element " + (i + 1), i, conf
    1079                     .getInt("attrList.a(" + i + ")"));
    1080             assertFalse("element " + (i + 1) + " has attribute", conf
    1081                     .containsKey("attrList.a(2)[@name]"));
    1082         }
    1083     }
    1084
    1085     /***
    1086      * Tests a list node with a multi-value attribute and multiple values. All
    1087      * attribute values should be assigned to the node with the first value.
    1088      */
    1089     public void testListWithMultiAttributesMultiValue()
    1090     {
    1091         for (int i = 1; i <= 2; i++)
    1092         {
    1093             assertEquals("Wrong value of multi-valued node", "value" + i, conf
    1094                     .getString("attrList.a(" + (i + 3) + ")"));
    1095         }
    1096         List attrs = conf.getList("attrList.a(4)[@name]");
    1097         final String attrVal = "uvw";
    1098         assertEquals("Wrong number of name attributes", attrVal.length(), attrs
    1099                 .size());
    1100         for (int i = 0; i < attrVal.length(); i++)
    1101         {
    1102             assertEquals("Wrong value for attribute " + i, String
    1103                     .valueOf(attrVal.charAt(i)), attrs.get(i));
    1104         }
    1105         assertEquals("Wrong value of test attribute", "yes", conf
    1106                 .getString("attrList.a(4)[@test]"));
    1107         assertFalse("Name attribute for 2nd value", conf
    1108                 .containsKey("attrList.a(5)[@name]"));
    1109         assertFalse("Test attribute for 2nd value", conf
    1110                 .containsKey("attrList.a(5)[@test]"));
    1111     }
    1112
    1113     /***
    1114      * Tests whether the auto save mechanism is triggered by changes at a
    1115      * subnode configuration.
    1116      */
    1117     public void testAutoSaveWithSubnodeConfig() throws ConfigurationException
    1118     {
    1119         final String newValue = "I am autosaved";
    1120         conf.setFile(testSaveConf);
    1121         conf.setAutoSave(true);
    1122         Configuration sub = conf.configurationAt("element2.subelement");
    1123         sub.setProperty("subsubelement", newValue);
    1124         assertEquals("Change not visible to parent", newValue, conf
    1125                 .getString("element2.subelement.subsubelement"));
    1126         XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
    1127         assertEquals("Change was not saved", newValue, conf2
    1128                 .getString("element2.subelement.subsubelement"));
    1129     }
    1130
    1131     /***
    1132      * Tests whether a subnode configuration created from another subnode
    1133      * configuration of a XMLConfiguration can trigger the auto save mechanism.
    1134      */
    1135     public void testAutoSaveWithSubSubnodeConfig() throws ConfigurationException
    1136     {
    1137         final String newValue = "I am autosaved";
    1138         conf.setFile(testSaveConf);
    1139         conf.setAutoSave(true);
    1140         SubnodeConfiguration sub1 = conf.configurationAt("element2");
    1141         SubnodeConfiguration sub2 = sub1.configurationAt("subelement");
    1142         sub2.setProperty("subsubelement", newValue);
    1143         assertEquals("Change not visible to parent", newValue, conf
    1144                 .getString("element2.subelement.subsubelement"));
    1145         XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
    1146         assertEquals("Change was not saved", newValue, conf2
    1147                 .getString("element2.subelement.subsubelement"));
    1148     }
    1149
    1150     /***
    1151      * Tests saving and loading a configuration when delimiter parsing is
    1152      * disabled.
    1153      */
    1154     public void testSaveDelimiterParsingDisabled()
    1155             throws ConfigurationException
    1156     {
    1157         checkSaveDelimiterParsingDisabled("list.delimiter.test");
    1158     }
    1159
    1160     /***
    1161      * Tests saving and loading a configuration when delimiter parsing is
    1162      * disabled and attributes are involved.
    1163      */
    1164     public void testSaveDelimiterParsingDisabledAttrs()
    1165             throws ConfigurationException
    1166     {
    1167         checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]");
    1168     }
    1169
    1170     /***
    1171      * Helper method for testing saving and loading a configuration when
    1172      * delimiter parsing is disabled.
    1173      *
    1174      * @param key the key to be checked
    1175      * @throws ConfigurationException if an error occurs
    1176      */
    1177     private void checkSaveDelimiterParsingDisabled(String key)
    1178             throws ConfigurationException
    1179     {
    1180         conf.clear();
    1181         conf.setDelimiterParsingDisabled(true);
    1182         conf.load();
    1183         conf.setProperty(key, "C://Temp//,C://Data//");
    1184         conf.addProperty(key, "a,b,c");
    1185         conf.save(testSaveConf);
    1186         XMLConfiguration checkConf = new XMLConfiguration();
    1187         checkConf.setDelimiterParsingDisabled(true);
    1188         checkConf.setFile(testSaveConf);
    1189         checkSavedConfig(checkConf);
    1190     }
    1191
    1192     /***
    1193      * Tests multiple attribute values in delimiter parsing disabled mode.
    1194      */
    1195     public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException
    1196     {
    1197         conf.clear();
    1198         conf.setDelimiterParsingDisabled(true);
    1199         conf.load();
    1200         List expr = conf.getList("expressions[@value]");
    1201         assertEquals("Wrong list size", 2, expr.size());
    1202         assertEquals("Wrong element 1", "a || (b && c)", expr.get(0));
    1203         assertEquals("Wrong element 2", "!d", expr.get(1));
    1204     }
    1205
    1206     /***
    1207      * Tests using multiple attribute values, which are partly escaped when
    1208      * delimiter parsing is not disabled.
    1209      */
    1210     public void testMultipleAttrValuesEscaped() throws ConfigurationException
    1211     {
    1212         conf.addProperty("test.dir[@name]", "C://Temp//");
    1213         conf.addProperty("test.dir[@name]", "C://Data//");
    1214         conf.save(testSaveConf);
    1215         XMLConfiguration checkConf = new XMLConfiguration();
    1216         checkConf.setFile(testSaveConf);
    1217         checkSavedConfig(checkConf);
    1218     }
    1219
    1220     /***
    1221      * Tests a combination of auto save = true and an associated reloading
    1222      * strategy.
    1223      */
    1224     public void testAutoSaveWithReloadingStrategy() throws ConfigurationException
    1225     {
    1226         conf.setFile(testSaveConf);
    1227         conf.save();
    1228         conf.setReloadingStrategy(new FileAlwaysReloadingStrategy());
    1229         conf.setAutoSave(true);
    1230         assertEquals("Value not found", "value", conf.getProperty("element"));
    1231     }
    1232
    1233     /***
    1234      * Tests adding nodes from another configuration.
    1235      */
    1236     public void testAddNodesCopy() throws ConfigurationException
    1237     {
    1238         XMLConfiguration c2 = new XMLConfiguration(testProperties2);
    1239         conf.addNodes("copiedProperties", c2.getRootNode().getChildren());
    1240         conf.save(testSaveConf);
    1241         XMLConfiguration checkConf = new XMLConfiguration();
    1242         checkConf.setFile(testSaveConf);
    1243         checkSavedConfig(checkConf);
    1244     }
    1245
    1246     /***
    1247      * Tests whether the addNodes() method triggers an auto save.
    1248      */
    1249     public void testAutoSaveAddNodes() throws ConfigurationException
    1250     {
    1251         conf.setFile(testSaveConf);
    1252         conf.setAutoSave(true);
    1253         HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(
    1254                 "addNodesTest", Boolean.TRUE);
    1255         Collection nodes = new ArrayList(1);
    1256         nodes.add(node);
    1257         conf.addNodes("test.autosave", nodes);
    1258         XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
    1259         assertTrue("Added nodes are not saved", c2
    1260                 .getBoolean("test.autosave.addNodesTest"));
    1261     }
    1262
    1263     /***
    1264      * Tests saving a configuration after a node was added. Test for
    1265      * CONFIGURATION-294.
    1266      */
    1267     public void testAddNodesAndSave() throws ConfigurationException
    1268     {
    1269         ConfigurationNode node = new HierarchicalConfiguration.Node("test");
    1270         ConfigurationNode child = new HierarchicalConfiguration.Node("child");
    1271         node.addChild(child);
    1272         ConfigurationNode attr = new HierarchicalConfiguration.Node("attr");
    1273         node.addAttribute(attr);
    1274         ConfigurationNode node2 = conf.createNode("test2");
    1275         Collection nodes = new ArrayList(2);
    1276         nodes.add(node);
    1277         nodes.add(node2);
    1278         conf.addNodes("add.nodes", nodes);
    1279         conf.setFile(testSaveConf);
    1280         conf.save();
    1281         conf.setProperty("add.nodes.test", "true");
    1282         conf.setProperty("add.nodes.test.child", "yes");
    1283         conf.setProperty("add.nodes.test[@attr]", "existing");
    1284         conf.setProperty("add.nodes.test2", "anotherValue");
    1285         conf.save();
    1286         XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
    1287         assertEquals("Value was not saved", "true", c2
    1288                 .getString("add.nodes.test"));
    1289         assertEquals("Child value was not saved", "yes", c2
    1290                 .getString("add.nodes.test.child"));
    1291         assertEquals("Attr value was not saved", "existing", c2
    1292                 .getString("add.nodes.test[@attr]"));
    1293         assertEquals("Node2 not saved", "anotherValue", c2
    1294                 .getString("add.nodes.test2"));
    1295     }
    1296
    1297     /***
    1298      * Tests registering the publicId of a DTD.
    1299      */
    1300     public void testRegisterEntityId() throws ConfigurationException,
    1301             IOException
    1302     {
    1303         File dtdFile = new File("conf/properties.dtd");
    1304         final String publicId = "http://commons.apache.org/test/properties.dtd";
    1305         conf = new XMLConfiguration("testDtd.xml");
    1306         conf.setPublicID(publicId);
    1307         conf.save(testSaveConf);
    1308         XMLConfiguration checkConfig = new XMLConfiguration();
    1309         checkConfig.setFile(testSaveConf);
    1310         checkConfig.registerEntityId(publicId, dtdFile.toURL());
    1311         checkConfig.setValidating(true);
    1312         checkSavedConfig(checkConfig);
    1313     }
    1314
    1315     /***
    1316      * Tries to register a null public ID. This should cause an exception.
    1317      */
    1318     public void testRegisterEntityIdNull() throws IOException
    1319     {
    1320         try
    1321         {
    1322             conf.registerEntityId(null, new URL("http://commons.apache.org"));
    1323             fail("Could register null public ID!");
    1324         }
    1325         catch (IllegalArgumentException iex)
    1326         {
    1327             // ok
    1328         }
    1329     }
    1330
    1331     /***
    1332      * Tests saving a configuration that was created from a hierarchical
    1333      * configuration. This test exposes bug CONFIGURATION-301.
    1334      */
    1335     public void testSaveAfterCreateWithCopyConstructor()
    1336             throws ConfigurationException
    1337     {
    1338         HierarchicalConfiguration hc = conf.configurationAt("element2");
    1339         conf = new XMLConfiguration(hc);
    1340         conf.save(testSaveConf);
    1341         XMLConfiguration checkConfig = new XMLConfiguration();
    1342         checkConfig.setFile(testSaveConf);
    1343         checkSavedConfig(checkConfig);
    1344         assertEquals("Wrong name of root element", "element2", checkConfig
    1345                 .getRootElementName());
    1346     }
    1347
    1348     /***
    1349      * Tests whether the name of the root element is copied when a configuration
    1350      * is created using the copy constructor.
    1351      */
    1352     public void testCopyRootName() throws ConfigurationException
    1353     {
    1354         final String rootName = "rootElement";
    1355         final String xml = "<" + rootName + "><test>true</test></" + rootName
    1356                 + ">";
    1357         conf.clear();
    1358         conf.load(new StringReader(xml));
    1359         XMLConfiguration copy = new XMLConfiguration(conf);
    1360         assertEquals("Wrong name of root element", rootName, copy
    1361                 .getRootElementName());
    1362         copy.save(testSaveConf);
    1363         copy = new XMLConfiguration(testSaveConf);
    1364         assertEquals("Wrong name of root element after save", rootName, copy
    1365                 .getRootElementName());
    1366     }
    1367
    1368     /***
    1369      * Tests whether the name of the root element is copied for a configuration
    1370      * for which not yet a document exists.
    1371      */
    1372     public void testCopyRootNameNoDocument() throws ConfigurationException
    1373     {
    1374         final String rootName = "rootElement";
    1375         conf = new XMLConfiguration();
    1376         conf.setRootElementName(rootName);
    1377         conf.setProperty("test", Boolean.TRUE);
    1378         XMLConfiguration copy = new XMLConfiguration(conf);
    1379         assertEquals("Wrong name of root element", rootName, copy
    1380                 .getRootElementName());
    1381         copy.save(testSaveConf);
    1382         copy = new XMLConfiguration(testSaveConf);
    1383         assertEquals("Wrong name of root element after save", rootName, copy
    1384                 .getRootElementName());
    1385     }
    1386
    1387     /***
    1388      * Tests adding an attribute node using the addNodes() method.
    1389      */
    1390     public void testAddNodesAttributeNode()
    1391     {
    1392         conf.addProperty("testAddNodes.property[@name]", "prop1");
    1393         conf.addProperty("testAddNodes.property(0).value", "value1");
    1394         conf.addProperty("testAddNodes.property(-1)[@name]", "prop2");
    1395         conf.addProperty("testAddNodes.property(1).value", "value2");
    1396         Collection nodes = new ArrayList();
    1397         nodes.add(new HierarchicalConfiguration.Node("property"));
    1398         conf.addNodes("testAddNodes", nodes);
    1399         nodes.clear();
    1400         ConfigurationNode nd = new HierarchicalConfiguration.Node("name",
    1401                 "prop3");
    1402         nd.setAttribute(true);
    1403         nodes.add(nd);
    1404         conf.addNodes("testAddNodes.property(2)", nodes);
    1405         assertEquals("Attribute not added", "prop3", conf
    1406                 .getString("testAddNodes.property(2)[@name]"));
    1407     }
    1408
    1409     /***
    1410      * Tests whether spaces are preserved when the xml:space attribute is set.
    1411      */
    1412     public void testPreserveSpace()
    1413     {
    1414         assertEquals("Wrong value of blanc", " ", conf.getString("space.blanc"));
    1415         assertEquals("Wrong value of stars", " * * ", conf
    1416                 .getString("space.stars"));
    1417     }
    1418
    1419     /***
    1420      * Tests whether the xml:space attribute can be overridden in nested
    1421      * elements.
    1422      */
    1423     public void testPreserveSpaceOverride()
    1424     {
    1425         assertEquals("Not trimmed", "Some text", conf
    1426                 .getString("space.description"));
    1427     }
    1428
    1429     /***
    1430      * Tests an xml:space attribute with an invalid value. This will be
    1431      * interpreted as default.
    1432      */
    1433     public void testPreserveSpaceInvalid()
    1434     {
    1435         assertEquals("Invalid not trimmed", "Some other text", conf
    1436                 .getString("space.testInvalid"));
    1437     }
    1438
    1439     /***
    1440      * Tests whether attribute splitting can be disabled.
    1441      */
    1442     public void testAttributeSplittingDisabled() throws ConfigurationException
    1443     {
    1444         List values = conf.getList("expressions[@value2]");
    1445         assertEquals("Wrong number of attribute values", 2, values.size());
    1446         assertEquals("Wrong value 1", "a", values.get(0));
    1447         assertEquals("Wrong value 2", "b|c", values.get(1));
    1448         XMLConfiguration conf2 = new XMLConfiguration();
    1449         conf2.setAttributeSplittingDisabled(true);
    1450         conf2.setFile(conf.getFile());
    1451         conf2.load();
    1452         assertEquals("Attribute was split", "a,b|c", conf2
    1453                 .getString("expressions[@value2]"));
    1454     }
    1455
    1456     /***
    1457      * Tests disabling both delimiter parsing and attribute splitting.
    1458      */
    1459     public void testAttributeSplittingAndDelimiterParsingDisabled()
    1460             throws ConfigurationException
    1461     {
    1462         conf.clear();
    1463         conf.setDelimiterParsingDisabled(true);
    1464         conf.load();
    1465         List values = conf.getList("expressions[@value2]");
    1466         assertEquals("Wrong number of attribute values", 2, values.size());
    1467         assertEquals("Wrong value 1", "a,b", values.get(0));
    1468         assertEquals("Wrong value 2", "c", values.get(1));
    1469         XMLConfiguration conf2 = new XMLConfiguration();
    1470         conf2.setAttributeSplittingDisabled(true);
    1471         conf2.setDelimiterParsingDisabled(true);
    1472         conf2.setFile(conf.getFile());
    1473         conf2.load();
    1474         assertEquals("Attribute was split", "a,b|c", conf2
    1475                 .getString("expressions[@value2]"));
    1476     }
    1477
    1478     /***
    1479      * Prepares a configuration object for testing a reload operation.
    1480      *
    1481      * @return the initialized configuration
    1482      * @throws ConfigurationException if an error occurs
    1483      */
    1484     private XMLConfiguration setUpReloadTest() throws ConfigurationException
    1485     {
    1486         removeTestFile();
    1487         conf.save(testSaveConf);
    1488         XMLConfiguration c = new XMLConfiguration(testSaveConf);
    1489         c.setReloadingStrategy(new FileAlwaysReloadingStrategy());
    1490         conf.setProperty("test(0).entity", "newValue");
    1491         conf.save(testSaveConf);
    1492         return c;
    1493     }
    1494
    1495     /***
    1496      * Removes the test output file if it exists.
    1497      */
    1498     private void removeTestFile()
    1499     {
    1500         if (testSaveConf.exists())
    1501         {
    1502             assertTrue(testSaveConf.delete());
    1503         }
    1504     }
    1505
    1506     /***
    1507      * Helper method for checking if a save operation was successful. Loads a
    1508      * saved configuration and then tests against a reference configuration.
    1509      * @param checkConfig the configuration to check
    1510      * @throws ConfigurationException if an error occurs
    1511      */
    1512     private void checkSavedConfig(FileConfiguration checkConfig) throws ConfigurationException
    1513     {
    1514         checkConfig.load();
    1515         ConfigurationAssert.assertEquals(conf, checkConfig);
    1516     }
    1517 }