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  package org.apache.commons.configuration;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.util.Collection;
22  import java.util.Set;
23  
24  import org.apache.commons.configuration.beanutils.BeanHelper;
25  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
26  import org.apache.commons.configuration.tree.DefaultConfigurationNode;
27  import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
28  
29  import junit.framework.TestCase;
30  
31  /***
32   * Test class for DefaultConfigurationBuilder.
33   *
34   * @author Oliver Heger
35   * @version $Id: TestDefaultConfigurationBuilder.java 578455 2007-09-22 15:12:16Z oheger $
36   */
37  public class TestDefaultConfigurationBuilder extends TestCase
38  {
39      /*** Test configuration definition file. */
40      private static final File TEST_FILE = new File(
41              "conf/testDigesterConfiguration.xml");
42  
43      private static final File ADDITIONAL_FILE = new File(
44              "conf/testDigesterConfiguration2.xml");
45  
46      private static final File OPTIONAL_FILE = new File(
47              "conf/testDigesterOptionalConfiguration.xml");
48  
49      private static final File OPTIONALEX_FILE = new File(
50              "conf/testDigesterOptionalConfigurationEx.xml");
51  
52      private static final File MULTI_FILE = new File(
53              "conf/testDigesterConfiguration3.xml");
54  
55      private static final File INIT_FILE = new File(
56              "conf/testComplexInitialization.xml");
57  
58      /*** Constant for the name of an optional configuration.*/
59      private static final String OPTIONAL_NAME = "optionalConfig";
60  
61      /*** Stores the object to be tested. */
62      DefaultConfigurationBuilder factory;
63  
64      protected void setUp() throws Exception
65      {
66          super.setUp();
67          System
68                  .setProperty("java.naming.factory.initial",
69                          "org.apache.commons.configuration.MockInitialContextFactory");
70          System.setProperty("test_file_xml", "test.xml");
71          System.setProperty("test_file_combine", "testcombine1.xml");
72          factory = new DefaultConfigurationBuilder();
73          factory.clearErrorListeners();  // avoid exception messages
74      }
75  
76      /***
77       * Tests the isReservedNode() method of ConfigurationDeclaration.
78       */
79      public void testConfigurationDeclarationIsReserved()
80      {
81          DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
82                  factory, factory);
83          DefaultConfigurationNode parent = new DefaultConfigurationNode();
84          DefaultConfigurationNode nd = new DefaultConfigurationNode("at");
85          parent.addAttribute(nd);
86          assertTrue("Attribute at not recognized", decl.isReservedNode(nd));
87          nd = new DefaultConfigurationNode("optional");
88          parent.addAttribute(nd);
89          assertTrue("Attribute optional not recognized", decl.isReservedNode(nd));
90          nd = new DefaultConfigurationNode("config-class");
91          parent.addAttribute(nd);
92          assertTrue("Inherited attribute not recognized", decl
93                  .isReservedNode(nd));
94          nd = new DefaultConfigurationNode("different");
95          parent.addAttribute(nd);
96          assertFalse("Wrong reserved attribute", decl.isReservedNode(nd));
97          nd = new DefaultConfigurationNode("at");
98          parent.addChild(nd);
99          assertFalse("Node type not evaluated", decl.isReservedNode(nd));
100     }
101 
102     /***
103      * Tests if the at attribute is correctly detected as reserved attribute.
104      */
105     public void testConfigurationDeclarationIsReservedAt()
106     {
107         checkOldReservedAttribute("at");
108     }
109 
110     /***
111      * Tests if the optional attribute is correctly detected as reserved
112      * attribute.
113      */
114     public void testConfigurationDeclarationIsReservedOptional()
115     {
116         checkOldReservedAttribute("optional");
117     }
118 
119     /***
120      * Tests if special reserved attributes are recognized by the
121      * isReservedNode() method. For compatibility reasons the attributes "at"
122      * and "optional" are also treated as reserved attributes, but only if there
123      * are no corresponding attributes with the "config-" prefix.
124      *
125      * @param name the attribute name
126      */
127     private void checkOldReservedAttribute(String name)
128     {
129         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
130                 factory, factory);
131         DefaultConfigurationNode parent = new DefaultConfigurationNode();
132         DefaultConfigurationNode nd = new DefaultConfigurationNode("config-"
133                 + name);
134         parent.addAttribute(nd);
135         assertTrue("config-" + name + " attribute not recognized", decl
136                 .isReservedNode(nd));
137         DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name);
138         parent.addAttribute(nd2);
139         assertFalse(name + " is reserved though config- exists", decl
140                 .isReservedNode(nd2));
141         assertTrue("config- attribute not recognized when " + name + " exists",
142                 decl.isReservedNode(nd));
143     }
144 
145     /***
146      * Tests access to certain reserved attributes of a
147      * ConfigurationDeclaration.
148      */
149     public void testConfigurationDeclarationGetAttributes()
150     {
151         factory.addProperty("xml.fileName", "test.xml");
152         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
153                 factory, factory.configurationAt("xml"));
154         assertNull("Found an at attribute", decl.getAt());
155         assertFalse("Found an optional attribute", decl.isOptional());
156         factory.addProperty("xml[@config-at]", "test1");
157         assertEquals("Wrong value of at attribute", "test1", decl.getAt());
158         factory.addProperty("xml[@at]", "test2");
159         assertEquals("Wrong value of config-at attribute", "test1", decl.getAt());
160         factory.clearProperty("xml[@config-at]");
161         assertEquals("Old at attribute not detected", "test2", decl.getAt());
162         factory.addProperty("xml[@config-optional]", "true");
163         assertTrue("Wrong value of optional attribute", decl.isOptional());
164         factory.addProperty("xml[@optional]", "false");
165         assertTrue("Wrong value of config-optional attribute", decl.isOptional());
166         factory.clearProperty("xml[@config-optional]");
167         factory.setProperty("xml[@optional]", Boolean.TRUE);
168         assertTrue("Old optional attribute not detected", decl.isOptional());
169         factory.setProperty("xml[@optional]", "invalid value");
170         try
171         {
172             decl.isOptional();
173             fail("Invalid optional attribute was not detected!");
174         }
175         catch (ConfigurationRuntimeException crex)
176         {
177             // ok
178         }
179     }
180 
181     /***
182      * Tests adding a new configuration provider.
183      */
184     public void testAddConfigurationProvider()
185     {
186         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
187         assertNull("Provider already registered", factory
188                 .providerForTag("test"));
189         factory.addConfigurationProvider("test", provider);
190         assertSame("Provider not registered", provider, factory
191                 .providerForTag("test"));
192     }
193 
194     /***
195      * Tries to register a null configuration provider. This should cause an
196      * exception.
197      */
198     public void testAddConfigurationProviderNull()
199     {
200         try
201         {
202             factory.addConfigurationProvider("test", null);
203             fail("Could register null provider");
204         }
205         catch (IllegalArgumentException iex)
206         {
207             // ok
208         }
209     }
210 
211     /***
212      * Tries to register a configuration provider for a null tag. This should
213      * cause an exception to be thrown.
214      */
215     public void testAddConfigurationProviderNullTag()
216     {
217         try
218         {
219             factory.addConfigurationProvider(null,
220                     new DefaultConfigurationBuilder.ConfigurationProvider());
221             fail("Could register provider for null tag!");
222         }
223         catch (IllegalArgumentException iex)
224         {
225             // ok
226         }
227     }
228 
229     /***
230      * Tests removing configuration providers.
231      */
232     public void testRemoveConfigurationProvider()
233     {
234         assertNull("Removing unknown provider", factory
235                 .removeConfigurationProvider("test"));
236         assertNull("Removing provider for null tag", factory
237                 .removeConfigurationProvider(null));
238         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
239         factory.addConfigurationProvider("test", provider);
240         assertSame("Failed to remove provider", provider, factory
241                 .removeConfigurationProvider("test"));
242         assertNull("Provider still registered", factory.providerForTag("test"));
243     }
244 
245     /***
246      * Tests creating a configuration object from a configuration declaration.
247      */
248     public void testConfigurationBeanFactoryCreateBean()
249     {
250         factory.addConfigurationProvider("test",
251                 new DefaultConfigurationBuilder.ConfigurationProvider(
252                         PropertiesConfiguration.class));
253         factory.addProperty("test[@throwExceptionOnMissing]", "true");
254         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
255                 factory, factory.configurationAt("test"));
256         PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper
257                 .createBean(decl);
258         assertTrue("Property was not initialized", conf
259                 .isThrowExceptionOnMissing());
260     }
261 
262     /***
263      * Tests creating a configuration object from an unknown tag. This should
264      * cause an exception.
265      */
266     public void testConfigurationBeanFactoryCreateUnknownTag()
267     {
268         factory.addProperty("test[@throwExceptionOnMissing]", "true");
269         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
270                 factory, factory.configurationAt("test"));
271         try
272         {
273             BeanHelper.createBean(decl);
274             fail("Could create configuration from unknown tag!");
275         }
276         catch (ConfigurationRuntimeException crex)
277         {
278             // ok
279         }
280     }
281 
282     /***
283      * Tests loading a simple configuration definition file.
284      */
285     public void testLoadConfiguration() throws ConfigurationException
286     {
287         factory.setFile(TEST_FILE);
288         checkConfiguration();
289     }
290 
291     /***
292      * Tests the file constructor.
293      */
294     public void testLoadConfigurationFromFile() throws ConfigurationException
295     {
296         factory = new DefaultConfigurationBuilder(TEST_FILE);
297         checkConfiguration();
298     }
299 
300     /***
301      * Tests the file name constructor.
302      */
303     public void testLoadConfigurationFromFileName()
304             throws ConfigurationException
305     {
306         factory = new DefaultConfigurationBuilder(TEST_FILE.getAbsolutePath());
307         checkConfiguration();
308     }
309 
310     /***
311      * Tests the URL constructor.
312      */
313     public void testLoadConfigurationFromURL() throws Exception
314     {
315         factory = new DefaultConfigurationBuilder(TEST_FILE.toURL());
316         checkConfiguration();
317     }
318 
319     /***
320      * Tests if the configuration was correctly created by the factory.
321      */
322     private void checkConfiguration() throws ConfigurationException
323     {
324         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
325                 .getConfiguration();
326 
327         assertEquals("Number of configurations", 3, compositeConfiguration
328                 .getNumberOfConfigurations());
329         assertEquals(PropertiesConfiguration.class, compositeConfiguration
330                 .getConfiguration(0).getClass());
331         assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration
332                 .getConfiguration(1).getClass());
333         assertEquals(XMLConfiguration.class, compositeConfiguration
334                 .getConfiguration(2).getClass());
335 
336         // check the first configuration
337         PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration
338                 .getConfiguration(0);
339         assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc
340                 .getFileName());
341 
342         // check some properties
343         checkProperties(compositeConfiguration);
344     }
345 
346     /***
347      * Checks if the passed in configuration contains the expected properties.
348      *
349      * @param compositeConfiguration the configuration to check
350      */
351     private void checkProperties(Configuration compositeConfiguration)
352     {
353         assertTrue("Make sure we have loaded our key", compositeConfiguration
354                 .getBoolean("test.boolean"));
355         assertEquals("I'm complex!", compositeConfiguration
356                 .getProperty("element2.subelement.subsubelement"));
357         assertEquals("property in the XMLPropertiesConfiguration", "value1",
358                 compositeConfiguration.getProperty("key1"));
359     }
360 
361     /***
362      * Tests loading a configuration definition file with an additional section.
363      */
364     public void testLoadAdditional() throws ConfigurationException
365     {
366         factory.setFile(ADDITIONAL_FILE);
367         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
368                 .getConfiguration();
369         assertEquals("Verify how many configs", 2, compositeConfiguration
370                 .getNumberOfConfigurations());
371 
372         // Test if union was constructed correctly
373         Object prop = compositeConfiguration.getProperty("tables.table.name");
374         assertTrue(prop instanceof Collection);
375         assertEquals(3, ((Collection) prop).size());
376         assertEquals("users", compositeConfiguration
377                 .getProperty("tables.table(0).name"));
378         assertEquals("documents", compositeConfiguration
379                 .getProperty("tables.table(1).name"));
380         assertEquals("tasks", compositeConfiguration
381                 .getProperty("tables.table(2).name"));
382 
383         prop = compositeConfiguration
384                 .getProperty("tables.table.fields.field.name");
385         assertTrue(prop instanceof Collection);
386         assertEquals(17, ((Collection) prop).size());
387 
388         assertEquals("smtp.mydomain.org", compositeConfiguration
389                 .getString("mail.host.smtp"));
390         assertEquals("pop3.mydomain.org", compositeConfiguration
391                 .getString("mail.host.pop"));
392 
393         // This was overriden
394         assertEquals("masterOfPost", compositeConfiguration
395                 .getString("mail.account.user"));
396         assertEquals("topsecret", compositeConfiguration
397                 .getString("mail.account.psswd"));
398 
399         // This was overriden, too, but not in additional section
400         assertEquals("enhanced factory", compositeConfiguration
401                 .getString("test.configuration"));
402     }
403 
404     /***
405      * Tests whether a default log error listener is registered at the builder
406      * instance.
407      */
408     public void testLogErrorListener()
409     {
410         assertEquals("No default error listener registered", 1,
411                 new DefaultConfigurationBuilder().getErrorListeners().size());
412     }
413 
414     /***
415      * Tests loading a definition file that contains optional configurations.
416      */
417     public void testLoadOptional() throws Exception
418     {
419         factory.setURL(OPTIONAL_FILE.toURL());
420         Configuration config = factory.getConfiguration();
421         assertTrue(config.getBoolean("test.boolean"));
422         assertEquals("value", config.getProperty("element"));
423     }
424 
425     /***
426      * Tests whether loading a failing optional configuration causes an error
427      * event.
428      */
429     public void testLoadOptionalErrorEvent() throws Exception
430     {
431         factory.clearErrorListeners();
432         ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl();
433         factory.addErrorListener(listener);
434         prepareOptionalTest("configuration", false);
435         listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL,
436                 OPTIONAL_NAME, null);
437     }
438 
439     /***
440      * Tests loading a definition file with optional and non optional
441      * configuration sources. One non optional does not exist, so this should
442      * cause an exception.
443      */
444     public void testLoadOptionalWithException()
445     {
446         factory.setFile(OPTIONALEX_FILE);
447         try
448         {
449             factory.getConfiguration();
450             fail("Non existing source did not cause an exception!");
451         }
452         catch (ConfigurationException cex)
453         {
454             // ok
455         }
456     }
457 
458     /***
459      * Tries to load a configuration file with an optional, non file-based
460      * configuration. The optional attribute should work for other configuration
461      * classes, too.
462      */
463     public void testLoadOptionalNonFileBased() throws ConfigurationException
464     {
465         CombinedConfiguration config = prepareOptionalTest("configuration", false);
466         assertTrue("Configuration not empty", config.isEmpty());
467         assertEquals("Wrong number of configurations", 0, config
468                 .getNumberOfConfigurations());
469     }
470 
471     /***
472      * Tests an optional, non existing configuration with the forceCreate
473      * attribute. This configuration should be added to the resulting
474      * configuration.
475      */
476     public void testLoadOptionalForceCreate() throws ConfigurationException
477     {
478         factory.setBasePath(TEST_FILE.getParent());
479         CombinedConfiguration config = prepareOptionalTest("xml", true);
480         assertEquals("Wrong number of configurations", 1, config
481                 .getNumberOfConfigurations());
482         FileConfiguration fc = (FileConfiguration) config
483                 .getConfiguration(OPTIONAL_NAME);
484         assertNotNull("Optional config not found", fc);
485         assertEquals("File name was not set", "nonExisting.xml", fc
486                 .getFileName());
487         assertNotNull("Base path was not set", fc.getBasePath());
488     }
489 
490     /***
491      * Tests loading an embedded optional configuration builder with the force
492      * create attribute.
493      */
494     public void testLoadOptionalBuilderForceCreate()
495             throws ConfigurationException
496     {
497         CombinedConfiguration config = prepareOptionalTest("configuration",
498                 true);
499         assertEquals("Wrong number of configurations", 1, config
500                 .getNumberOfConfigurations());
501         assertTrue(
502                 "Wrong optional configuration type",
503                 config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration);
504     }
505 
506     /***
507      * Tests loading an optional configuration with the force create attribute
508      * set. The provider will always throw an exception. In this case the
509      * configuration will not be added to the resulting combined configuration.
510      */
511     public void testLoadOptionalForceCreateWithException()
512             throws ConfigurationException
513     {
514         factory.addConfigurationProvider("test",
515                 new DefaultConfigurationBuilder.ConfigurationBuilderProvider()
516                 {
517                     // Throw an exception here, too
518                     public AbstractConfiguration getEmptyConfiguration(
519                             DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception
520                     {
521                         throw new Exception("Unable to create configuration!");
522                     }
523                 });
524         CombinedConfiguration config = prepareOptionalTest("test", true);
525         assertEquals("Optional configuration could be created", 0, config
526                 .getNumberOfConfigurations());
527     }
528 
529     /***
530      * Prepares a test for loading a configuration definition file with an
531      * optional configuration declaration.
532      *
533      * @param tag the tag name with the optional configuration
534      * @param force the forceCreate attribute
535      * @return the combined configuration obtained from the builder
536      * @throws ConfigurationException if an error occurs
537      */
538     private CombinedConfiguration prepareOptionalTest(String tag, boolean force)
539             throws ConfigurationException
540     {
541         String prefix = "override." + tag;
542         factory.addProperty(prefix + "[@fileName]", "nonExisting.xml");
543         factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE);
544         factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME);
545         if (force)
546         {
547             factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE);
548         }
549         return factory.getConfiguration(false);
550     }
551 
552     /***
553      * Tests loading a definition file with multiple different sources.
554      */
555     public void testLoadDifferentSources() throws ConfigurationException
556     {
557         factory.setFile(MULTI_FILE);
558         Configuration config = factory.getConfiguration();
559         assertFalse(config.isEmpty());
560         assertTrue(config instanceof CombinedConfiguration);
561         CombinedConfiguration cc = (CombinedConfiguration) config;
562         assertEquals("Wrong number of configurations", 1, cc
563                 .getNumberOfConfigurations());
564 
565         assertNotNull(config
566                 .getProperty("tables.table(0).fields.field(2).name"));
567         assertNotNull(config.getProperty("element2.subelement.subsubelement"));
568         assertEquals("value", config.getProperty("element3"));
569         assertEquals("foo", config.getProperty("element3[@name]"));
570         assertNotNull(config.getProperty("mail.account.user"));
571 
572         // test JNDIConfiguration
573         assertNotNull(config.getProperty("test.onlyinjndi"));
574         assertTrue(config.getBoolean("test.onlyinjndi"));
575 
576         Configuration subset = config.subset("test");
577         assertNotNull(subset.getProperty("onlyinjndi"));
578         assertTrue(subset.getBoolean("onlyinjndi"));
579 
580         // test SystemConfiguration
581         assertNotNull(config.getProperty("java.version"));
582         assertEquals(System.getProperty("java.version"), config
583                 .getString("java.version"));
584     }
585 
586     /***
587      * Tests if the base path is correctly evaluated.
588      */
589     public void testSetConfigurationBasePath() throws ConfigurationException
590     {
591         factory.addProperty("properties[@fileName]", "test.properties");
592         File deepDir = new File("conf/config/deep");
593         factory.setConfigurationBasePath(deepDir.getAbsolutePath());
594 
595         Configuration config = factory.getConfiguration(false);
596         assertEquals("Wrong property value", "somevalue", config
597                 .getString("somekey"));
598     }
599 
600     /***
601      * Tests reading a configuration definition file that contains complex
602      * initialization of properties of the declared configuration sources.
603      */
604     public void testComplexInitialization() throws ConfigurationException
605     {
606         factory.setFile(INIT_FILE);
607         CombinedConfiguration cc = (CombinedConfiguration) factory
608                 .getConfiguration();
609 
610         assertEquals("System property not found", "test.xml",
611                 cc.getString("test_file_xml"));
612         PropertiesConfiguration c1 = (PropertiesConfiguration) cc
613                 .getConfiguration(1);
614         assertTrue(
615                 "Reloading strategy was not set",
616                 c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy);
617         assertEquals("Refresh delay was not set", 10000,
618                 ((FileChangedReloadingStrategy) c1.getReloadingStrategy())
619                         .getRefreshDelay());
620 
621         Configuration xmlConf = cc.getConfiguration("xml");
622         assertEquals("Property not found", "I'm complex!", xmlConf
623                 .getString("element2/subelement/subsubelement"));
624         assertEquals("List index not found", "two", xmlConf
625                 .getString("list[0]/item[1]"));
626         assertEquals("Property in combiner file not found", "yellow", cc
627                 .getString("/gui/selcolor"));
628 
629         assertTrue("Delimiter flag was not set", cc
630                 .isDelimiterParsingDisabled());
631         assertTrue("Expression engine was not set",
632                 cc.getExpressionEngine() instanceof XPathExpressionEngine);
633     }
634 
635     /***
636      * Tests if the returned combined configuration has the expected structure.
637      */
638     public void testCombinedConfiguration() throws ConfigurationException
639     {
640         factory.setFile(INIT_FILE);
641         CombinedConfiguration cc = (CombinedConfiguration) factory
642                 .getConfiguration();
643         assertNotNull("Properties configuration not found", cc
644                 .getConfiguration("properties"));
645         assertNotNull("XML configuration not found", cc.getConfiguration("xml"));
646         assertEquals("Wrong number of contained configs", 4, cc
647                 .getNumberOfConfigurations());
648 
649         CombinedConfiguration cc2 = (CombinedConfiguration) cc
650                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
651         assertNotNull("No additional configuration found", cc2);
652         Set names = cc2.getConfigurationNames();
653         assertEquals("Wrong number of contained additional configs", 2, names
654                 .size());
655         assertTrue("Config 1 not contained", names.contains("combiner1"));
656         assertTrue("Config 2 not contained", names.contains("combiner2"));
657     }
658 
659     /***
660      * Tests the structure of the returned combined configuration if there is no
661      * additional section.
662      */
663     public void testCombinedConfigurationNoAdditional()
664             throws ConfigurationException
665     {
666         factory.setFile(TEST_FILE);
667         CombinedConfiguration cc = factory.getConfiguration(true);
668         assertNull("Additional configuration was found", cc
669                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME));
670     }
671 
672     /***
673      * Tests whether the list node definition was correctly processed.
674      */
675     public void testCombinedConfigurationListNodes()
676             throws ConfigurationException
677     {
678         factory.setFile(INIT_FILE);
679         CombinedConfiguration cc = factory.getConfiguration(true);
680         Set listNodes = cc.getNodeCombiner().getListNodes();
681         assertEquals("Wrong number of list nodes", 2, listNodes.size());
682         assertTrue("table node not a list node", listNodes.contains("table"));
683         assertTrue("list node not a list node", listNodes.contains("list"));
684 
685         CombinedConfiguration cca = (CombinedConfiguration) cc
686                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
687         listNodes = cca.getNodeCombiner().getListNodes();
688         assertTrue("Found list nodes for additional combiner", listNodes
689                 .isEmpty());
690     }
691 
692     /***
693      * Tests whether a configuration builder can itself be declared in a
694      * configuration definition file.
695      */
696     public void testConfigurationBuilderProvider()
697             throws ConfigurationException
698     {
699         factory.addProperty("override.configuration[@fileName]", TEST_FILE
700                 .getAbsolutePath());
701         CombinedConfiguration cc = factory.getConfiguration(false);
702         assertEquals("Wrong number of configurations", 1, cc
703                 .getNumberOfConfigurations());
704         checkProperties(cc);
705     }
706 
707     /***
708      * Tests whether XML settings can be inherited.
709      */
710     public void testLoadXMLWithSettings() throws ConfigurationException,
711             IOException
712     {
713         File confDir = new File("conf");
714         File targetDir = new File("target");
715         File testXMLSource = new File(confDir, "testDtd.xml");
716         File testXMLValidationSource = new File(confDir,
717                 "testValidateInvalid.xml");
718         File testSavedXML = new File(targetDir, "testSave.xml");
719         File testSavedFactory = new File(targetDir, "testSaveFactory.xml");
720         File dtdFile = new File(confDir, "properties.dtd");
721         final String publicId = "http://commons.apache.org/test.dtd";
722 
723         XMLConfiguration config = new XMLConfiguration(testXMLSource);
724         config.setPublicID(publicId);
725         config.save(testSavedXML);
726         factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath());
727         factory.addProperty("xml(0)[@validating]", "true");
728         factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource
729                 .getAbsolutePath());
730         factory.addProperty("xml(1)[@config-optional]", "true");
731         factory.addProperty("xml(1)[@validating]", "true");
732         factory.save(testSavedFactory);
733 
734         factory = new DefaultConfigurationBuilder();
735         factory.setFile(testSavedFactory);
736         factory.registerEntityId(publicId, dtdFile.toURL());
737         factory.clearErrorListeners();
738         Configuration c = factory.getConfiguration();
739         assertEquals("Wrong property value", "value1", c.getString("entry(0)"));
740         assertFalse("Invalid XML source was loaded", c
741                 .containsKey("table.name"));
742 
743         testSavedXML.delete();
744         testSavedFactory.delete();
745     }
746 }