1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 578579 2007-09-23 16:20:24Z 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
106 String key = "clearly";
107 conf.clearProperty(key);
108 assertNull(key, conf.getProperty(key));
109 assertNull(key, conf.getProperty(key));
110
111
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
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
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
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
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
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
162 Object property = conf.getProperty("clear");
163 assertNull(property);
164
165
166 property = conf.getProperty("e");
167 assertNull(property);
168
169
170 property = conf.getProperty("element3[@n]");
171 assertNull(property);
172
173
174 property = conf.getProperty("element");
175 assertNotNull(property);
176 assertTrue(property instanceof String);
177 assertEquals("value", property);
178
179
180 property = conf.getProperty("element3[@name]");
181 assertNotNull(property);
182 assertTrue(property instanceof String);
183 assertEquals("foo", property);
184
185
186 property = conf.getProperty("test.comment");
187 assertEquals("", property);
188
189
190 property = conf.getProperty("test.cdata");
191 assertNotNull(property);
192 assertTrue(property instanceof String);
193 assertEquals("<cdata value>", property);
194
195
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
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
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
233 String key = "clear[@id]";
234 conf.clearProperty(key);
235 assertNull(key, conf.getProperty(key));
236 assertNull(key, conf.getProperty(key));
237
238
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
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
262 conf.setProperty("element3[@name]", "bar");
263 assertEquals("element3[@name]", "bar", conf.getProperty("element3[@name]"));
264
265
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
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
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
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
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
467 conf.addProperty("string", "value1");
468 for (int i = 1; i < 5; i++)
469 {
470 conf.addProperty("test.array", "value" + i);
471 }
472
473
474 for (int i = 1; i < 5; i++)
475 {
476 conf.addProperty("test.attribute[@array]", "value" + i);
477 }
478
479
480 conf.addProperty("split.list5", "a//,b//,c");
481 conf.setProperty("element3", "value//,value1//,value2");
482 conf.setProperty("element3[@name]", "foo//,bar");
483
484
485 conf.save(testSaveConf.getAbsolutePath());
486
487
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
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
653
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
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
679 }
680
681
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
790 conf.load(nonValidFile);
791 assertEquals("customers", conf.getString("table.name"));
792 assertFalse(conf.containsKey("table.fields.field(1).type"));
793
794
795 conf.setValidating(true);
796 try
797 {
798 conf.load(nonValidFile);
799 fail("Validation was not performed!");
800 }
801 catch(ConfigurationException cex)
802 {
803
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
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 accessing properties when the XPATH expression engine is set.
968 */
969 public void testXPathExpressionEngine()
970 {
971 conf.setExpressionEngine(new XPathExpressionEngine());
972 assertEquals("Wrong attribute value", "foo\"bar", conf
973 .getString("test[1]/entity/@name"));
974 conf.clear();
975 assertNull(conf.getString("test[1]/entity/@name"));
976 }
977
978 /***
979 * Tests the copy constructor.
980 */
981 public void testInitCopy() throws ConfigurationException
982 {
983 XMLConfiguration copy = new XMLConfiguration(conf);
984 assertEquals("value", copy.getProperty("element"));
985 assertNull("Document was copied, too", copy.getDocument());
986 ConfigurationNode root = copy.getRootNode();
987 for(Iterator it = root.getChildren().iterator(); it.hasNext();)
988 {
989 ConfigurationNode node = (ConfigurationNode) it.next();
990 assertNull("Reference was not cleared", node.getReference());
991 }
992
993 removeTestFile();
994 copy.setFile(testSaveConf);
995 copy.save();
996 copy.clear();
997 checkSavedConfig(copy);
998 }
999
1000 /***
1001 * Tests list nodes with multiple values and attributes.
1002 */
1003 public void testListWithAttributes()
1004 {
1005 assertEquals("Wrong number of <a> elements", 6, conf.getList(
1006 "attrList.a").size());
1007 assertEquals("Wrong value of first element", "ABC", conf
1008 .getString("attrList.a(0)"));
1009 assertEquals("Wrong value of first name attribute", "x", conf
1010 .getString("attrList.a(0)[@name]"));
1011 assertEquals("Wrong number of name attributes", 5, conf.getList(
1012 "attrList.a[@name]").size());
1013 }
1014
1015 /***
1016 * Tests a list node with attributes that has multiple values separated by
1017 * the list delimiter. In this scenario the attribute should be added to the
1018 * node with the first value.
1019 */
1020 public void testListWithAttributesMultiValue()
1021 {
1022 assertEquals("Wrong value of 2nd element", "1", conf
1023 .getString("attrList.a(1)"));
1024 assertEquals("Wrong value of 2nd name attribute", "y", conf
1025 .getString("attrList.a(1)[@name]"));
1026 for (int i = 2; i <= 3; i++)
1027 {
1028 assertEquals("Wrong value of element " + (i + 1), i, conf
1029 .getInt("attrList.a(" + i + ")"));
1030 assertFalse("element " + (i + 1) + " has attribute", conf
1031 .containsKey("attrList.a(2)[@name]"));
1032 }
1033 }
1034
1035 /***
1036 * Tests a list node with a multi-value attribute and multiple values. All
1037 * attribute values should be assigned to the node with the first value.
1038 */
1039 public void testListWithMultiAttributesMultiValue()
1040 {
1041 for (int i = 1; i <= 2; i++)
1042 {
1043 assertEquals("Wrong value of multi-valued node", "value" + i, conf
1044 .getString("attrList.a(" + (i + 3) + ")"));
1045 }
1046 List attrs = conf.getList("attrList.a(4)[@name]");
1047 final String attrVal = "uvw";
1048 assertEquals("Wrong number of name attributes", attrVal.length(), attrs
1049 .size());
1050 for (int i = 0; i < attrVal.length(); i++)
1051 {
1052 assertEquals("Wrong value for attribute " + i, String
1053 .valueOf(attrVal.charAt(i)), attrs.get(i));
1054 }
1055 assertEquals("Wrong value of test attribute", "yes", conf
1056 .getString("attrList.a(4)[@test]"));
1057 assertFalse("Name attribute for 2nd value", conf
1058 .containsKey("attrList.a(5)[@name]"));
1059 assertFalse("Test attribute for 2nd value", conf
1060 .containsKey("attrList.a(5)[@test]"));
1061 }
1062
1063 /***
1064 * Tests whether the auto save mechanism is triggered by changes at a
1065 * subnode configuration.
1066 */
1067 public void testAutoSaveWithSubnodeConfig() throws ConfigurationException
1068 {
1069 final String newValue = "I am autosaved";
1070 conf.setFile(testSaveConf);
1071 conf.setAutoSave(true);
1072 Configuration sub = conf.configurationAt("element2.subelement");
1073 sub.setProperty("subsubelement", newValue);
1074 assertEquals("Change not visible to parent", newValue, conf
1075 .getString("element2.subelement.subsubelement"));
1076 XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
1077 assertEquals("Change was not saved", newValue, conf2
1078 .getString("element2.subelement.subsubelement"));
1079 }
1080
1081 /***
1082 * Tests whether a subnode configuration created from another subnode
1083 * configuration of a XMLConfiguration can trigger the auto save mechanism.
1084 */
1085 public void testAutoSaveWithSubSubnodeConfig() throws ConfigurationException
1086 {
1087 final String newValue = "I am autosaved";
1088 conf.setFile(testSaveConf);
1089 conf.setAutoSave(true);
1090 SubnodeConfiguration sub1 = conf.configurationAt("element2");
1091 SubnodeConfiguration sub2 = sub1.configurationAt("subelement");
1092 sub2.setProperty("subsubelement", newValue);
1093 assertEquals("Change not visible to parent", newValue, conf
1094 .getString("element2.subelement.subsubelement"));
1095 XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
1096 assertEquals("Change was not saved", newValue, conf2
1097 .getString("element2.subelement.subsubelement"));
1098 }
1099
1100 /***
1101 * Tests saving and loading a configuration when delimiter parsing is
1102 * disabled.
1103 */
1104 public void testSaveDelimiterParsingDisabled()
1105 throws ConfigurationException
1106 {
1107 checkSaveDelimiterParsingDisabled("list.delimiter.test");
1108 }
1109
1110 /***
1111 * Tests saving and loading a configuration when delimiter parsing is
1112 * disabled and attributes are involved.
1113 */
1114 public void testSaveDelimiterParsingDisabledAttrs()
1115 throws ConfigurationException
1116 {
1117 checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]");
1118 }
1119
1120 /***
1121 * Helper method for testing saving and loading a configuration when
1122 * delimiter parsing is disabled.
1123 *
1124 * @param key the key to be checked
1125 * @throws ConfigurationException if an error occurs
1126 */
1127 private void checkSaveDelimiterParsingDisabled(String key)
1128 throws ConfigurationException
1129 {
1130 conf.clear();
1131 conf.setDelimiterParsingDisabled(true);
1132 conf.load();
1133 conf.setProperty(key, "C://Temp//,C://Data//");
1134 conf.addProperty(key, "a,b,c");
1135 conf.save(testSaveConf);
1136 XMLConfiguration checkConf = new XMLConfiguration();
1137 checkConf.setDelimiterParsingDisabled(true);
1138 checkConf.setFile(testSaveConf);
1139 checkSavedConfig(checkConf);
1140 }
1141
1142 /***
1143 * Tests multiple attribute values in delimiter parsing disabled mode.
1144 */
1145 public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException
1146 {
1147 conf.clear();
1148 conf.setDelimiterParsingDisabled(true);
1149 conf.load();
1150 List expr = conf.getList("expressions[@value]");
1151 assertEquals("Wrong list size", 2, expr.size());
1152 assertEquals("Wrong element 1", "a || (b && c)", expr.get(0));
1153 assertEquals("Wrong element 2", "!d", expr.get(1));
1154 }
1155
1156 /***
1157 * Tests using multiple attribute values, which are partly escaped when
1158 * delimiter parsing is not disabled.
1159 */
1160 public void testMultipleAttrValuesEscaped() throws ConfigurationException
1161 {
1162 conf.addProperty("test.dir[@name]", "C://Temp//");
1163 conf.addProperty("test.dir[@name]", "C://Data//");
1164 conf.save(testSaveConf);
1165 XMLConfiguration checkConf = new XMLConfiguration();
1166 checkConf.setFile(testSaveConf);
1167 checkSavedConfig(checkConf);
1168 }
1169
1170 /***
1171 * Tests a combination of auto save = true and an associated reloading
1172 * strategy.
1173 */
1174 public void testAutoSaveWithReloadingStrategy() throws ConfigurationException
1175 {
1176 conf.setFile(testSaveConf);
1177 conf.save();
1178 conf.setReloadingStrategy(new FileAlwaysReloadingStrategy());
1179 conf.setAutoSave(true);
1180 assertEquals("Value not found", "value", conf.getProperty("element"));
1181 }
1182
1183 /***
1184 * Tests adding nodes from another configuration.
1185 */
1186 public void testAddNodesCopy() throws ConfigurationException
1187 {
1188 XMLConfiguration c2 = new XMLConfiguration(testProperties2);
1189 conf.addNodes("copiedProperties", c2.getRootNode().getChildren());
1190 conf.save(testSaveConf);
1191 XMLConfiguration checkConf = new XMLConfiguration();
1192 checkConf.setFile(testSaveConf);
1193 checkSavedConfig(checkConf);
1194 }
1195
1196 /***
1197 * Tests whether the addNodes() method triggers an auto save.
1198 */
1199 public void testAutoSaveAddNodes() throws ConfigurationException
1200 {
1201 conf.setFile(testSaveConf);
1202 conf.setAutoSave(true);
1203 HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(
1204 "addNodesTest", Boolean.TRUE);
1205 Collection nodes = new ArrayList(1);
1206 nodes.add(node);
1207 conf.addNodes("test.autosave", nodes);
1208 XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
1209 assertTrue("Added nodes are not saved", c2
1210 .getBoolean("test.autosave.addNodesTest"));
1211 }
1212
1213 /***
1214 * Tests saving a configuration after a node was added. Test for
1215 * CONFIGURATION-294.
1216 */
1217 public void testAddNodesAndSave() throws ConfigurationException
1218 {
1219 ConfigurationNode node = new HierarchicalConfiguration.Node("test");
1220 ConfigurationNode child = new HierarchicalConfiguration.Node("child");
1221 node.addChild(child);
1222 ConfigurationNode attr = new HierarchicalConfiguration.Node("attr");
1223 node.addAttribute(attr);
1224 ConfigurationNode node2 = conf.createNode("test2");
1225 Collection nodes = new ArrayList(2);
1226 nodes.add(node);
1227 nodes.add(node2);
1228 conf.addNodes("add.nodes", nodes);
1229 conf.setFile(testSaveConf);
1230 conf.save();
1231 conf.setProperty("add.nodes.test", "true");
1232 conf.setProperty("add.nodes.test.child", "yes");
1233 conf.setProperty("add.nodes.test[@attr]", "existing");
1234 conf.setProperty("add.nodes.test2", "anotherValue");
1235 conf.save();
1236 XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
1237 assertEquals("Value was not saved", "true", c2
1238 .getString("add.nodes.test"));
1239 assertEquals("Child value was not saved", "yes", c2
1240 .getString("add.nodes.test.child"));
1241 assertEquals("Attr value was not saved", "existing", c2
1242 .getString("add.nodes.test[@attr]"));
1243 assertEquals("Node2 not saved", "anotherValue", c2
1244 .getString("add.nodes.test2"));
1245 }
1246
1247 /***
1248 * Tests registering the publicId of a DTD.
1249 */
1250 public void testRegisterEntityId() throws ConfigurationException,
1251 IOException
1252 {
1253 File dtdFile = new File("conf/properties.dtd");
1254 final String publicId = "http://commons.apache.org/test/properties.dtd";
1255 conf = new XMLConfiguration("testDtd.xml");
1256 conf.setPublicID(publicId);
1257 conf.save(testSaveConf);
1258 XMLConfiguration checkConfig = new XMLConfiguration();
1259 checkConfig.setFile(testSaveConf);
1260 checkConfig.registerEntityId(publicId, dtdFile.toURL());
1261 checkConfig.setValidating(true);
1262 checkSavedConfig(checkConfig);
1263 }
1264
1265 /***
1266 * Tries to register a null public ID. This should cause an exception.
1267 */
1268 public void testRegisterEntityIdNull() throws IOException
1269 {
1270 try
1271 {
1272 conf.registerEntityId(null, new URL("http://commons.apache.org"));
1273 fail("Could register null public ID!");
1274 }
1275 catch (IllegalArgumentException iex)
1276 {
1277
1278 }
1279 }
1280
1281 /***
1282 * Prepares a configuration object for testing a reload operation.
1283 *
1284 * @return the initialized configuration
1285 * @throws ConfigurationException if an error occurs
1286 */
1287 private XMLConfiguration setUpReloadTest() throws ConfigurationException
1288 {
1289 removeTestFile();
1290 conf.save(testSaveConf);
1291 XMLConfiguration c = new XMLConfiguration(testSaveConf);
1292 c.setReloadingStrategy(new FileAlwaysReloadingStrategy());
1293 conf.setProperty("test(0).entity", "newValue");
1294 conf.save(testSaveConf);
1295 return c;
1296 }
1297
1298 /***
1299 * Removes the test output file if it exists.
1300 */
1301 private void removeTestFile()
1302 {
1303 if (testSaveConf.exists())
1304 {
1305 assertTrue(testSaveConf.delete());
1306 }
1307 }
1308
1309 /***
1310 * Helper method for checking if a save operation was successful. Loads a
1311 * saved configuration and then tests against a reference configuration.
1312 * @param checkConfig the configuration to check
1313 * @throws ConfigurationException if an error occurs
1314 */
1315 private void checkSavedConfig(FileConfiguration checkConfig) throws ConfigurationException
1316 {
1317 checkConfig.load();
1318 ConfigurationAssert.assertEquals(conf, checkConfig);
1319 }
1320 }