    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.Iterator;
    30  import java.util.List;
    31
    32  import javax.xml.parsers.DocumentBuilder;
    33  import javax.xml.parsers.DocumentBuilderFactory;
    34
    35  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
    36  import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
    37  import org.xml.sax.SAXException;
    38  import org.xml.sax.SAXParseException;
    39  import org.xml.sax.helpers.DefaultHandler;
    40
    41  import junit.framework.TestCase;
    42
    43  /***
    44   * test for loading and saving xml properties files
    45   *
    46   * @version $Id: TestXMLConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
    47   */
    48  public class TestXMLConfiguration extends TestCase
    49  {
    50      /*** Constant for the used encoding.*/
    51      static final String ENCODING = "ISO-8859-1";
    52
    53      /*** Constant for the test system ID.*/
    54      static final String SYSTEM_ID = "properties.dtd";
    55
    56      /*** Constant for the test public ID.*/
    57      static final String PUBLIC_ID = "-//Commons Configuration//DTD Test Configuration 1.3//EN";
    58
    59      /*** Constant for the DOCTYPE declaration.*/
    60      static final String DOCTYPE_DECL = " PUBLIC \"" + PUBLIC_ID + "\" \"" + SYSTEM_ID + "\">";
    61
    62      /*** Constant for the DOCTYPE prefix.*/
    63      static final String DOCTYPE = "<!DOCTYPE ";
    64
    65      /*** Constant for the transformer factory property.*/
    66      static final String PROP_FACTORY = "javax.xml.transform.TransformerFactory";
    67
    68      /*** The File that we test with */
    69      private String testProperties = new File("conf/test.xml").getAbsolutePath();
    70      private String testProperties2 = new File("conf/testDigesterConfigurationInclude1.xml").getAbsolutePath();
    71      private String testBasePath = new File("conf").getAbsolutePath();
    72      private File testSaveConf = new File("target/testsave.xml");
    73
    74      private XMLConfiguration conf;
    75
    76      protected void setUp() throws Exception
    77      {
    78          conf = new XMLConfiguration();
    79          conf.setFile(new File(testProperties));
    80          conf.load();
    81          removeTestFile();
    82      }
    83
    84      public void testGetProperty()
    85      {
    86          assertEquals("value", conf.getProperty("element"));
    87      }
    88
    89      public void testGetCommentedProperty()
    90      {
    91          assertEquals("", conf.getProperty("test.comment"));
    92      }
    93
    94      public void testGetPropertyWithXMLEntity()
    95      {
    96          assertEquals("1<2", conf.getProperty("test.entity"));
    97      }
    98
    99      public void testClearProperty() throws ConfigurationException, IOException
    100     {
    101         // test non-existent element
    102         String key = "clearly";
    103         conf.clearProperty(key);
    104         assertNull(key, conf.getProperty(key));
    105         assertNull(key, conf.getProperty(key));
    106
    107         // test single element
    108         conf.load();
    109         key = "clear.element";
    110         conf.clearProperty(key);
    111         assertNull(key, conf.getProperty(key));
    112         assertNull(key, conf.getProperty(key));
    113
    114         // test single element with attribute
    115         conf.load();
    116         key = "clear.element2";
    117         conf.clearProperty(key);
    118         assertNull(key, conf.getProperty(key));
    119         assertNull(key, conf.getProperty(key));
    120         key = "clear.element2[@id]";
    121         assertNotNull(key, conf.getProperty(key));
    122         assertNotNull(key, conf.getProperty(key));
    123
    124         // test non-text/cdata element
    125         conf.load();
    126         key = "clear.comment";
    127         conf.clearProperty(key);
    128         assertNull(key, conf.getProperty(key));
    129         assertNull(key, conf.getProperty(key));
    130
    131         // test cdata element
    132         conf.load();
    133         key = "clear.cdata";
    134         conf.clearProperty(key);
    135         assertNull(key, conf.getProperty(key));
    136         assertNull(key, conf.getProperty(key));
    137
    138         // test multiple sibling elements
    139         conf.load();
    140         key = "clear.list.item";
    141         conf.clearProperty(key);
    142         assertNull(key, conf.getProperty(key));
    143         assertNull(key, conf.getProperty(key));
    144         key = "clear.list.item[@id]";
    145         assertNotNull(key, conf.getProperty(key));
    146         assertNotNull(key, conf.getProperty(key));
    147
    148         // test multiple, disjoined elements
    149         conf.load();
    150         key = "list.item";
    151         conf.clearProperty(key);
    152         assertNull(key, conf.getProperty(key));
    153         assertNull(key, conf.getProperty(key));
    154     }
    155
    156     public void testgetProperty() {
    157         // test non-leaf element
    158         Object property = conf.getProperty("clear");
    159         assertNull(property);
    160
    161         // test non-existent element
    162         property = conf.getProperty("e");
    163         assertNull(property);
    164
    165         // test non-existent element
    166         property = conf.getProperty("element3[@n]");
    167         assertNull(property);
    168
    169         // test single element
    170         property = conf.getProperty("element");
    171         assertNotNull(property);
    172         assertTrue(property instanceof String);
    173         assertEquals("value", property);
    174
    175         // test single attribute
    176         property = conf.getProperty("element3[@name]");
    177         assertNotNull(property);
    178         assertTrue(property instanceof String);
    179         assertEquals("foo", property);
    180
    181         // test non-text/cdata element
    182         property = conf.getProperty("test.comment");
    183         assertEquals("", property);
    184
    185         // test cdata element
    186         property = conf.getProperty("test.cdata");
    187         assertNotNull(property);
    188         assertTrue(property instanceof String);
    189         assertEquals("<cdata value>", property);
    190
    191         // test multiple sibling elements
    192         property = conf.getProperty("list.sublist.item");
    193         assertNotNull(property);
    194         assertTrue(property instanceof List);
    195         List list = (List)property;
    196         assertEquals(2, list.size());
    197         assertEquals("five", list.get(0));
    198         assertEquals("six", list.get(1));
    199
    200         // test multiple, disjoined elements
    201         property = conf.getProperty("list.item");
    202         assertNotNull(property);
    203         assertTrue(property instanceof List);
    204         list = (List)property;
    205         assertEquals(4, list.size());
    206         assertEquals("one", list.get(0));
    207         assertEquals("two", list.get(1));
    208         assertEquals("three", list.get(2));
    209         assertEquals("four", list.get(3));
    210
    211         // test multiple, disjoined attributes
    212         property = conf.getProperty("list.item[@name]");
    213         assertNotNull(property);
    214         assertTrue(property instanceof List);
    215         list = (List)property;
    216         assertEquals(2, list.size());
    217         assertEquals("one", list.get(0));
    218         assertEquals("three", list.get(1));
    219     }
    220
    221     public void testGetAttribute()
    222     {
    223         assertEquals("element3[@name]", "foo", conf.getProperty("element3[@name]"));
    224     }
    225
    226     public void testClearAttribute() throws Exception
    227     {
    228         // test non-existent attribute
    229         String key = "clear[@id]";
    230         conf.clearProperty(key);
    231         assertNull(key, conf.getProperty(key));
    232         assertNull(key, conf.getProperty(key));
    233
    234         // test single attribute
    235         conf.load();
    236         key = "clear.element2[@id]";
    237         conf.clearProperty(key);
    238         assertNull(key, conf.getProperty(key));
    239         assertNull(key, conf.getProperty(key));
    240         key = "clear.element2";
    241         assertNotNull(key, conf.getProperty(key));
    242         assertNotNull(key, conf.getProperty(key));
    243
    244         // test multiple, disjoined attributes
    245         conf.load();
    246         key = "clear.list.item[@id]";
    247         conf.clearProperty(key);
    248         assertNull(key, conf.getProperty(key));
    249         assertNull(key, conf.getProperty(key));
    250         key = "clear.list.item";
    251         assertNotNull(key, conf.getProperty(key));
    252         assertNotNull(key, conf.getProperty(key));
    253     }
    254
    255     public void testSetAttribute()
    256     {
    257         // replace an existing attribute
    258         conf.setProperty("element3[@name]", "bar");
    259         assertEquals("element3[@name]", "bar", conf.getProperty("element3[@name]"));
    260
    261         // set a new attribute
    262         conf.setProperty("foo[@bar]", "value");
    263         assertEquals("foo[@bar]", "value", conf.getProperty("foo[@bar]"));
    264
    265         conf.setProperty("name1","value1");
    266         assertEquals("value1",conf.getProperty("name1"));
    267     }
    268
    269     public void testAddAttribute()
    270     {
    271         conf.addProperty("element3[@name]", "bar");
    272
    273         List list = conf.getList("element3[@name]");
    274         assertNotNull("null list", list);
    275         assertTrue("'foo' element missing", list.contains("foo"));
    276         assertTrue("'bar' element missing", list.contains("bar"));
    277         assertEquals("list size", 2, list.size());
    278     }
    279
    280     public void testAddObjectAttribute()
    281     {
    282         conf.addProperty("test.boolean[@value]", Boolean.TRUE);
    283         assertTrue("test.boolean[@value]", conf.getBoolean("test.boolean[@value]"));
    284     }
    285
    286     public void testAddList()
    287     {
    288         conf.addProperty("test.array", "value1");
    289         conf.addProperty("test.array", "value2");
    290
    291         List list = conf.getList("test.array");
    292         assertNotNull("null list", list);
    293         assertTrue("'value1' element missing", list.contains("value1"));
    294         assertTrue("'value2' element missing", list.contains("value2"));
    295         assertEquals("list size", 2, list.size());
    296     }
    297
    298     public void testGetComplexProperty()
    299     {
    300         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    301     }
    302
    303     public void testSettingFileNames()
    304     {
    305         conf = new XMLConfiguration();
    306         conf.setFileName(testProperties);
    307         assertEquals(testProperties.toString(), conf.getFileName());
    308
    309         conf.setBasePath(testBasePath);
    310         conf.setFileName("hello.xml");
    311         assertEquals("hello.xml", conf.getFileName());
    312         assertEquals(testBasePath.toString(), conf.getBasePath());
    313         assertEquals(new File(testBasePath, "hello.xml"), conf.getFile());
    314
    315         conf.setBasePath(testBasePath);
    316         conf.setFileName("subdir/hello.xml");
    317         assertEquals("subdir/hello.xml", conf.getFileName());
    318         assertEquals(testBasePath.toString(), conf.getBasePath());
    319         assertEquals(new File(testBasePath, "subdir/hello.xml"), conf.getFile());
    320     }
    321
    322     public void testLoad() throws Exception
    323     {
    324         conf = new XMLConfiguration();
    325         conf.setFileName(testProperties);
    326         conf.load();
    327
    328         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    329     }
    330
    331     public void testLoadWithBasePath() throws Exception
    332     {
    333         conf = new XMLConfiguration();
    334
    335         conf.setFileName("test.xml");
    336         conf.setBasePath(testBasePath);
    337         conf.load();
    338
    339         assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement"));
    340     }
    341
    342     /***
    343      * Tests constructing an XMLConfiguration from a non existing file and
    344      * later saving to this file.
    345      */
    346     public void testLoadAndSaveFromFile() throws Exception
    347     {
    348         // If the file does not exist, an empty config is created
    349         conf = new XMLConfiguration(testSaveConf);
    350         assertTrue(conf.isEmpty());
    351         conf.addProperty("test", "yes");
    352         conf.save();
    353
    354         conf = new XMLConfiguration(testSaveConf);
    355         assertEquals("yes", conf.getString("test"));
    356     }
    357
    358     /***
    359      * Tests loading a configuration from a URL.
    360      */
    361     public void testLoadFromURL() throws Exception
    362     {
    363         URL url = new File(testProperties).toURL();
    364         conf = new XMLConfiguration(url);
    365         assertEquals("value", conf.getProperty("element"));
    366         assertEquals(url, conf.getURL());
    367     }
    368
    369     /***
    370      * Tests loading from a stream.
    371      */
    372     public void testLoadFromStream() throws Exception
    373     {
    374         String xml = "<?xml version=\"1.0\"?><config><test>1</test></config>";
    375         conf = new XMLConfiguration();
    376         conf.load(new ByteArrayInputStream(xml.getBytes()));
    377         assertEquals(1, conf.getInt("test"));
    378
    379         conf = new XMLConfiguration();
    380         conf.load(new ByteArrayInputStream(xml.getBytes()), "UTF8");
    381         assertEquals(1, conf.getInt("test"));
    382     }
    383
    384     /***
    385      * Tests loading a non well formed XML from a string.
    386      */
    387     public void testLoadInvalidXML() throws Exception
    388     {
    389         String xml = "<?xml version=\"1.0\"?><config><test>1</rest></config>";
    390         conf = new XMLConfiguration();
    391         try
    392         {
    393             conf.load(new StringReader(xml));
    394             fail("Could load invalid XML!");
    395         }
    396         catch(ConfigurationException cex)
    397         {
    398             //ok
    399         }
    400     }
    401
    402     public void testSetProperty() throws Exception
    403     {
    404         conf.setProperty("element.string", "hello");
    405
    406         assertEquals("'element.string'", "hello", conf.getString("element.string"));
    407         assertEquals("XML value of element.string", "hello", conf.getProperty("element.string"));
    408     }
    409
    410     public void testAddProperty()
    411     {
    412         // add a property to a non initialized xml configuration
    413         XMLConfiguration config = new XMLConfiguration();
    414         config.addProperty("test.string", "hello");
    415
    416         assertEquals("'test.string'", "hello", config.getString("test.string"));
    417     }
    418
    419     public void testAddObjectProperty()
    420     {
    421         // add a non string property
    422         conf.addProperty("test.boolean", Boolean.TRUE);
    423         assertTrue("'test.boolean'", conf.getBoolean("test.boolean"));
    424     }
    425
    426     public void testSave() throws Exception
    427     {
    428         // add an array of strings to the configuration
    429         conf.addProperty("string", "value1");
    430         for (int i = 1; i < 5; i++)
    431         {
    432             conf.addProperty("test.array", "value" + i);
    433         }
    434
    435         // add an array of strings in an attribute
    436         for (int i = 1; i < 5; i++)
    437         {
    438            conf.addProperty("test.attribute[@array]", "value" + i);
    439         }
    440
    441         // add comma delimited lists with escaped delimiters
    442         conf.addProperty("split.list5", "a//,b//,c");
    443         conf.setProperty("element3", "value//,value1//,value2");
    444         conf.setProperty("element3[@name]", "foo//,bar");
    445
    446         // save the configuration
    447         conf.save(testSaveConf.getAbsolutePath());
    448
    449         // read the configuration and compare the properties
    450         XMLConfiguration checkConfig = new XMLConfiguration();
    451         checkConfig.setFileName(testSaveConf.getAbsolutePath());
    452         checkSavedConfig(checkConfig);
    453     }
    454
    455     /***
    456      * Tests saving to a URL.
    457      */
    458     public void testSaveToURL() throws Exception
    459     {
    460         conf.save(testSaveConf.toURL());
    461         XMLConfiguration checkConfig = new XMLConfiguration();
    462         checkConfig.setFile(testSaveConf);
    463         checkSavedConfig(checkConfig);
    464     }
    465
    466     /***
    467      * Tests saving to a stream.
    468      */
    469     public void testSaveToStream() throws Exception
    470     {
    471         assertNull(conf.getEncoding());
    472         conf.setEncoding("UTF8");
    473         FileOutputStream out = null;
    474         try
    475         {
    476             out = new FileOutputStream(testSaveConf);
    477             conf.save(out);
    478         }
    479         finally
    480         {
    481             if(out != null)
    482             {
    483                 out.close();
    484             }
    485         }
    486
    487         XMLConfiguration checkConfig = new XMLConfiguration();
    488         checkConfig.setFile(testSaveConf);
    489         checkSavedConfig(checkConfig);
    490
    491         try
    492         {
    493             out = new FileOutputStream(testSaveConf);
    494             conf.save(out, "UTF8");
    495         }
    496         finally
    497         {
    498             if(out != null)
    499             {
    500                 out.close();
    501             }
    502         }
    503
    504         checkConfig.clear();
    505         checkSavedConfig(checkConfig);
    506     }
    507
    508     public void testAutoSave() throws Exception
    509     {
    510         conf.setFile(new File("target/testsave.xml"));
    511         assertFalse(conf.isAutoSave());
    512         conf.setAutoSave(true);
    513         assertTrue(conf.isAutoSave());
    514         conf.setProperty("autosave", "ok");
    515
    516         // reload the configuration
    517         XMLConfiguration conf2 = new XMLConfiguration(conf.getFile());
    518         assertEquals("'autosave' property", "ok", conf2.getString("autosave"));
    519
    520         conf.clearTree("clear");
    521         conf2 = new XMLConfiguration(conf.getFile());
    522         Configuration sub = conf2.subset("clear");
    523         assertTrue(sub.isEmpty());
    524     }
    525
    526     /***
    527      * Tests if a second file can be appended to a first.
    528      */
    529     public void testAppend() throws Exception
    530     {
    531         conf = new XMLConfiguration();
    532         conf.setFileName(testProperties);
    533         conf.load();
    534         conf.load(testProperties2);
    535         assertEquals("value", conf.getString("element"));
    536         assertEquals("tasks", conf.getString("table.name"));
    537
    538         conf.save(testSaveConf);
    539         conf = new XMLConfiguration(testSaveConf);
    540         assertEquals("value", conf.getString("element"));
    541         assertEquals("tasks", conf.getString("table.name"));
    542         assertEquals("application", conf.getString("table[@tableType]"));
    543     }
    544
    545     /***
    546      * Tests saving attributes (related to issue 34442).
    547      */
    548     public void testSaveAttributes() throws Exception
    549     {
    550         conf.clear();
    551         conf.load();
    552         conf.save(testSaveConf);
    553         conf = new XMLConfiguration();
    554         conf.load(testSaveConf);
    555         assertEquals("foo", conf.getString("element3[@name]"));
    556     }
    557
    558     /***
    559      * Tests collaboration between XMLConfiguration and a reloading strategy.
    560      */
    561     public void testReloading() throws Exception
    562     {
    563         assertNotNull(conf.getReloadingStrategy());
    564         assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy);
    565         PrintWriter out = null;
    566
    567         try
    568         {
    569             out = new PrintWriter(new FileWriter(testSaveConf));
    570             out.println("<?xml version=\"1.0\"?><config><test>1</test></config>");
    571             out.close();
    572             out = null;
    573             conf.setFile(testSaveConf);
    574             FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();
    575             strategy.setRefreshDelay(100);
    576             conf.setReloadingStrategy(strategy);
    577             assertEquals(strategy, conf.getReloadingStrategy());
    578             conf.load();
    579             assertEquals(1, conf.getInt("test"));
    580             Thread.sleep(1000);
    581
    582             out = new PrintWriter(new FileWriter(testSaveConf));
    583             out.println("<?xml version=\"1.0\"?><config><test>2</test></config>");
    584             out.close();
    585             out = null;
    586
    587             int trial = 0, value;
    588             // repeat multiple times because there are sometimes race conditions
    589             do
    590             {
    591                 Thread.sleep(1000);
    592                 value = conf.getInt("test");
    593             } while (value != 2 && ++trial <= 10);
    594             assertEquals(2, value);
    595         }
    596         finally
    597         {
    598             if (out != null)
    599             {
    600                 out.close();
    601             }
    602         }
    603     }
    604
    605     /***
    606      * Tests access to tag names with delimiter characters.
    607      */
    608     public void testComplexNames()
    609     {
    610         assertEquals("Name with dot", conf.getString("complexNames.my..elem"));
    611         assertEquals("Another dot", conf.getString("complexNames.my..elem.sub..elem"));
    612     }
    613
    614     /***
    615      * Tests setting a custom document builder.
    616      */
    617     public void testCustomDocBuilder() throws Exception
    618     {
    619         // Load an invalid XML file with the default (non validating)
    620         // doc builder. This should work...
    621         conf = new XMLConfiguration();
    622         conf.load(new File("conf/testValidateInvalid.xml"));
    623         assertEquals("customers", conf.getString("table.name"));
    624         assertFalse(conf.containsKey("table.fields.field(1).type"));
    625
    626         // Now create a validating doc builder and set it.
    627         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    628         factory.setValidating(true);
    629         DocumentBuilder builder = factory.newDocumentBuilder();
    630         builder.setErrorHandler(new DefaultHandler() {
    631             public void error(SAXParseException ex) throws SAXException
    632             {
    633                 throw ex;
    634             }
    635         });
    636         conf = new XMLConfiguration();
    637         conf.setDocumentBuilder(builder);
    638         try
    639         {
    640             conf.load(new File("conf/testValidateInvalid.xml"));
    641             fail("Could load invalid file with validating set to true!");
    642         }
    643         catch(ConfigurationException ex)
    644         {
    645             //ok
    646         }
    647
    648         // Try to load a valid document with a validating builder
    649         conf = new XMLConfiguration();
    650         conf.setDocumentBuilder(builder);
    651         conf.load(new File("conf/testValidateValid.xml"));
    652         assertTrue(conf.containsKey("table.fields.field(1).type"));
    653     }
    654
    655     /***
    656      * Tests the clone() method.
    657      */
    658     public void testClone()
    659     {
    660         Configuration c = (Configuration) conf.clone();
    661         assertTrue(c instanceof XMLConfiguration);
    662         XMLConfiguration copy = (XMLConfiguration) c;
    663         assertNotNull(conf.getDocument());
    664         assertNull(copy.getDocument());
    665         assertNotNull(conf.getFileName());
    666         assertNull(copy.getFileName());
    667
    668         copy.setProperty("element3", "clonedValue");
    669         assertEquals("value", conf.getString("element3"));
    670         conf.setProperty("element3[@name]", "originalFoo");
    671         assertEquals("foo", copy.getString("element3[@name]"));
    672     }
    673
    674     /***
    675      * Tests the subset() method. There was a bug that calling subset() had
    676      * undesired side effects.
    677      */
    678     public void testSubset() throws ConfigurationException
    679     {
    680         conf = new XMLConfiguration();
    681         conf.load(new File("conf/testHierarchicalXMLConfiguration.xml"));
    682         conf.subset("tables.table(0)");
    683         conf.save(testSaveConf);
    684
    685         conf = new XMLConfiguration(testSaveConf);
    686         assertEquals("users", conf.getString("tables.table(0).name"));
    687     }
    688
    689     /***
    690      * Tests string properties with list delimiters and escaped delimiters.
    691      */
    692     public void testSplitLists()
    693     {
    694         assertEquals("a", conf.getString("split.list3[@values]"));
    695         assertEquals(2, conf.getMaxIndex("split.list3[@values]"));
    696         assertEquals("a,b,c", conf.getString("split.list4[@values]"));
    697         assertEquals("a", conf.getString("split.list1"));
    698         assertEquals(2, conf.getMaxIndex("split.list1"));
    699         assertEquals("a,b,c", conf.getString("split.list2"));
    700     }
    701
    702     /***
    703      * Tests string properties with list delimiters when delimiter parsing
    704      * is disabled
    705      */
    706     public void testDelimiterParsingDisabled() throws ConfigurationException {
    707         XMLConfiguration conf2 = new XMLConfiguration();
    708         conf2.setDelimiterParsingDisabled(true);
    709         conf2.setFile(new File(testProperties));
    710         conf2.load();
    711
    712         assertEquals("a,b,c", conf2.getString("split.list3[@values]"));
    713         assertEquals(0, conf2.getMaxIndex("split.list3[@values]"));
    714         assertEquals("a//,b//,c", conf2.getString("split.list4[@values]"));
    715         assertEquals("a,b,c", conf2.getString("split.list1"));
    716         assertEquals(0, conf2.getMaxIndex("split.list1"));
    717         assertEquals("a//,b//,c", conf2.getString("split.list2"));
    718     }
    719
    720     /***
    721      * Tests whether a DTD can be accessed.
    722      */
    723     public void testDtd() throws ConfigurationException
    724     {
    725         conf = new XMLConfiguration("testDtd.xml");
    726         assertEquals("value1", conf.getString("entry(0)"));
    727         assertEquals("test2", conf.getString("entry(1)[@key]"));
    728     }
    729
    730     /***
    731      * Tests DTD validation using the setValidating() method.
    732      */
    733     public void testValidating() throws ConfigurationException
    734     {
    735         File nonValidFile = new File("conf/testValidateInvalid.xml");
    736         conf = new XMLConfiguration();
    737         assertFalse(conf.isValidating());
    738
    739         // Load a non valid XML document. Should work for isValidating() == false
    740         conf.load(nonValidFile);
    741         assertEquals("customers", conf.getString("table.name"));
    742         assertFalse(conf.containsKey("table.fields.field(1).type"));
    743
    744         // Now set the validating flag to true
    745         conf.setValidating(true);
    746         try
    747         {
    748             conf.load(nonValidFile);
    749             fail("Validation was not performed!");
    750         }
    751         catch(ConfigurationException cex)
    752         {
    753             //ok
    754         }
    755     }
    756
    757     /***
    758      * Tests handling of empty elements.
    759      */
    760     public void testEmptyElements() throws ConfigurationException
    761     {
    762         assertTrue(conf.containsKey("empty"));
    763         assertEquals("", conf.getString("empty"));
    764         conf.addProperty("empty2", "");
    765         conf.setProperty("empty", "no more empty");
    766         conf.save(testSaveConf);
    767
    768         conf = new XMLConfiguration(testSaveConf);
    769         assertEquals("no more empty", conf.getString("empty"));
    770         assertEquals("", conf.getProperty("empty2"));
    771     }
    772
    773     /***
    774      * Tests whether the encoding is correctly detected by the XML parser. This
    775      * is done by loading an XML file with the encoding "UTF-16". If this
    776      * encoding is not detected correctly, an exception will be thrown that
    777      * "Content is not allowed in prolog". This test case is related to issue
    778      * 34204.
    779      */
    780     public void testLoadWithEncoding() throws ConfigurationException
    781     {
    782         File file = new File("conf/testEncoding.xml");
    783         conf = new XMLConfiguration();
    784         conf.load(file);
    785         assertEquals("test3_yoge", conf.getString("yoge"));
    786     }
    787
    788     /***
    789      * Tests whether the encoding is written to the generated XML file.
    790      */
    791     public void testSaveWithEncoding() throws ConfigurationException
    792     {
    793         conf = new XMLConfiguration();
    794         conf.setProperty("test", "a value");
    795         conf.setEncoding(ENCODING);
    796
    797         StringWriter out = new StringWriter();
    798         conf.save(out);
    799         assertTrue("Encoding was not written to file", out.toString().indexOf(
    800                 "encoding=\"" + ENCODING + "\"") >= 0);
    801     }
    802
    803     /***
    804      * Tests whether a default encoding is used if no specific encoding is set.
    805      * According to the XSLT specification (http://www.w3.org/TR/xslt#output)
    806      * this should be either UTF-8 or UTF-16.
    807      */
    808     public void testSaveWithNullEncoding() throws ConfigurationException
    809     {
    810         conf = new XMLConfiguration();
    811         conf.setProperty("testNoEncoding", "yes");
    812         conf.setEncoding(null);
    813
    814         StringWriter out = new StringWriter();
    815         conf.save(out);
    816         assertTrue("Encoding was written to file", out.toString().indexOf(
    817                 "encoding=\"UTF-") >= 0);
    818     }
    819
    820     /***
    821      * Tests whether the DOCTYPE survives a save operation.
    822      */
    823     public void testSaveWithDoctype() throws ConfigurationException
    824     {
    825         String content = "<?xml  version=\"1.0\"?>"
    826                 + DOCTYPE
    827                 + "properties"
    828                 + DOCTYPE_DECL
    829                 + "<properties version=\"1.0\"><entry key=\"test\">value</entry></properties>";
    830         StringReader in = new StringReader(content);
    831         conf = new XMLConfiguration();
    832         conf.setFileName("conf/testDtd.xml");
    833         conf.load();
    834         conf.clear();
    835         conf.load(in);
    836
    837         assertEquals("Wrong public ID", PUBLIC_ID, conf.getPublicID());
    838         assertEquals("Wrong system ID", SYSTEM_ID, conf.getSystemID());
    839         StringWriter out = new StringWriter();
    840         conf.save(out);
    841         System.out.println(out.toString());
    842         assertTrue("Did not find DOCTYPE", out.toString().indexOf(DOCTYPE) >= 0);
    843     }
    844
    845     /***
    846      * Tests setting public and system IDs for the D'OCTYPE and then saving the
    847      * configuration. This should generate a DOCTYPE declaration.
    848      */
    849     public void testSaveWithDoctypeIDs() throws ConfigurationException
    850     {
    851         assertNull("A public ID was found", conf.getPublicID());
    852         assertNull("A system ID was found", conf.getSystemID());
    853         conf.setPublicID(PUBLIC_ID);
    854         conf.setSystemID(SYSTEM_ID);
    855         StringWriter out = new StringWriter();
    856         conf.save(out);
    857         assertTrue("Did not find DOCTYPE", out.toString().indexOf(
    858                 DOCTYPE + "testconfig" + DOCTYPE_DECL) >= 0);
    859     }
    860
    861     /***
    862      * Tests saving a configuration when an invalid transformer factory is
    863      * specified. In this case the error thrown by the TransformerFactory class
    864      * should be caught and re-thrown as a ConfigurationException.
    865      */
    866     public void testSaveWithInvalidTransformerFactory()
    867     {
    868         System.setProperty(PROP_FACTORY, "an.invalid.Class");
    869         try
    870         {
    871             conf.save(testSaveConf);
    872             fail("Could save with invalid TransformerFactory!");
    873         }
    874         catch (ConfigurationException cex)
    875         {
    876             // ok
    877         }
    878         finally
    879         {
    880             System.getProperties().remove(PROP_FACTORY);
    881         }
    882     }
    883
    884     /***
    885      * Removes the test output file if it exists.
    886      */
    887     private void removeTestFile()
    888     {
    889         if (testSaveConf.exists())
    890         {
    891             assertTrue(testSaveConf.delete());
    892         }
    893     }
    894
    895     /***
    896      * Helper method for checking if a save operation was successful. Loads a
    897      * saved configuration and then tests against a reference configuration.
    898      * @param checkConfig the configuration to check
    899      * @throws ConfigurationException if an error occurs
    900      */
    901     private void checkSavedConfig(FileConfiguration checkConfig) throws ConfigurationException
    902     {
    903         checkConfig.load();
    904
    905         for (Iterator i = conf.getKeys(); i.hasNext();)
    906         {
    907             String key = (String) i.next();
    908             assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key));
    909             assertEquals("Value of the '" + key + "' property", conf.getProperty(key), checkConfig.getProperty(key));
    910         }
    911     }
    912 }