001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.configuration;
019:
020: import java.io.ByteArrayInputStream;
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.io.FileWriter;
024: import java.io.IOException;
025: import java.io.PrintWriter;
026: import java.io.StringReader;
027: import java.io.StringWriter;
028: import java.net.URL;
029: import java.util.Iterator;
030: import java.util.List;
031:
032: import javax.xml.parsers.DocumentBuilder;
033: import javax.xml.parsers.DocumentBuilderFactory;
034:
035: import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
036: import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
037: import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
038: import org.apache.commons.configuration.tree.ConfigurationNode;
039: import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.SAXParseException;
042: import org.xml.sax.helpers.DefaultHandler;
043:
044: import junit.framework.TestCase;
045:
046: /**
047: * test for loading and saving xml properties files
048: *
049: * @version $Id: TestXMLConfiguration.java 513498 2007-03-01 21:15:07Z oheger $
050: */
051: public class TestXMLConfiguration extends TestCase {
052: /** Constant for the used encoding.*/
053: static final String ENCODING = "ISO-8859-1";
054:
055: /** Constant for the test system ID.*/
056: static final String SYSTEM_ID = "properties.dtd";
057:
058: /** Constant for the test public ID.*/
059: static final String PUBLIC_ID = "-//Commons Configuration//DTD Test Configuration 1.3//EN";
060:
061: /** Constant for the DOCTYPE declaration.*/
062: static final String DOCTYPE_DECL = " PUBLIC \"" + PUBLIC_ID
063: + "\" \"" + SYSTEM_ID + "\">";
064:
065: /** Constant for the DOCTYPE prefix.*/
066: static final String DOCTYPE = "<!DOCTYPE ";
067:
068: /** Constant for the transformer factory property.*/
069: static final String PROP_FACTORY = "javax.xml.transform.TransformerFactory";
070:
071: /** The File that we test with */
072: private String testProperties = new File("conf/test.xml")
073: .getAbsolutePath();
074: private String testProperties2 = new File(
075: "conf/testDigesterConfigurationInclude1.xml")
076: .getAbsolutePath();
077: private String testBasePath = new File("conf").getAbsolutePath();
078: private File testSaveConf = new File("target/testsave.xml");
079:
080: private XMLConfiguration conf;
081:
082: protected void setUp() throws Exception {
083: conf = new XMLConfiguration();
084: conf.setFile(new File(testProperties));
085: conf.load();
086: removeTestFile();
087: }
088:
089: public void testGetProperty() {
090: assertEquals("value", conf.getProperty("element"));
091: }
092:
093: public void testGetCommentedProperty() {
094: assertEquals("", conf.getProperty("test.comment"));
095: }
096:
097: public void testGetPropertyWithXMLEntity() {
098: assertEquals("1<2", conf.getProperty("test.entity"));
099: }
100:
101: public void testClearProperty() throws ConfigurationException,
102: IOException {
103: // test non-existent element
104: String key = "clearly";
105: conf.clearProperty(key);
106: assertNull(key, conf.getProperty(key));
107: assertNull(key, conf.getProperty(key));
108:
109: // test single element
110: conf.load();
111: key = "clear.element";
112: conf.clearProperty(key);
113: assertNull(key, conf.getProperty(key));
114: assertNull(key, conf.getProperty(key));
115:
116: // test single element with attribute
117: conf.load();
118: key = "clear.element2";
119: conf.clearProperty(key);
120: assertNull(key, conf.getProperty(key));
121: assertNull(key, conf.getProperty(key));
122: key = "clear.element2[@id]";
123: assertNotNull(key, conf.getProperty(key));
124: assertNotNull(key, conf.getProperty(key));
125:
126: // test non-text/cdata element
127: conf.load();
128: key = "clear.comment";
129: conf.clearProperty(key);
130: assertNull(key, conf.getProperty(key));
131: assertNull(key, conf.getProperty(key));
132:
133: // test cdata element
134: conf.load();
135: key = "clear.cdata";
136: conf.clearProperty(key);
137: assertNull(key, conf.getProperty(key));
138: assertNull(key, conf.getProperty(key));
139:
140: // test multiple sibling elements
141: conf.load();
142: key = "clear.list.item";
143: conf.clearProperty(key);
144: assertNull(key, conf.getProperty(key));
145: assertNull(key, conf.getProperty(key));
146: key = "clear.list.item[@id]";
147: assertNotNull(key, conf.getProperty(key));
148: assertNotNull(key, conf.getProperty(key));
149:
150: // test multiple, disjoined elements
151: conf.load();
152: key = "list.item";
153: conf.clearProperty(key);
154: assertNull(key, conf.getProperty(key));
155: assertNull(key, conf.getProperty(key));
156: }
157:
158: public void testgetProperty() {
159: // test non-leaf element
160: Object property = conf.getProperty("clear");
161: assertNull(property);
162:
163: // test non-existent element
164: property = conf.getProperty("e");
165: assertNull(property);
166:
167: // test non-existent element
168: property = conf.getProperty("element3[@n]");
169: assertNull(property);
170:
171: // test single element
172: property = conf.getProperty("element");
173: assertNotNull(property);
174: assertTrue(property instanceof String);
175: assertEquals("value", property);
176:
177: // test single attribute
178: property = conf.getProperty("element3[@name]");
179: assertNotNull(property);
180: assertTrue(property instanceof String);
181: assertEquals("foo", property);
182:
183: // test non-text/cdata element
184: property = conf.getProperty("test.comment");
185: assertEquals("", property);
186:
187: // test cdata element
188: property = conf.getProperty("test.cdata");
189: assertNotNull(property);
190: assertTrue(property instanceof String);
191: assertEquals("<cdata value>", property);
192:
193: // test multiple sibling elements
194: property = conf.getProperty("list.sublist.item");
195: assertNotNull(property);
196: assertTrue(property instanceof List);
197: List list = (List) property;
198: assertEquals(2, list.size());
199: assertEquals("five", list.get(0));
200: assertEquals("six", list.get(1));
201:
202: // test multiple, disjoined elements
203: property = conf.getProperty("list.item");
204: assertNotNull(property);
205: assertTrue(property instanceof List);
206: list = (List) property;
207: assertEquals(4, list.size());
208: assertEquals("one", list.get(0));
209: assertEquals("two", list.get(1));
210: assertEquals("three", list.get(2));
211: assertEquals("four", list.get(3));
212:
213: // test multiple, disjoined attributes
214: property = conf.getProperty("list.item[@name]");
215: assertNotNull(property);
216: assertTrue(property instanceof List);
217: list = (List) property;
218: assertEquals(2, list.size());
219: assertEquals("one", list.get(0));
220: assertEquals("three", list.get(1));
221: }
222:
223: public void testGetAttribute() {
224: assertEquals("element3[@name]", "foo", conf
225: .getProperty("element3[@name]"));
226: }
227:
228: public void testClearAttribute() throws Exception {
229: // test non-existent attribute
230: String key = "clear[@id]";
231: conf.clearProperty(key);
232: assertNull(key, conf.getProperty(key));
233: assertNull(key, conf.getProperty(key));
234:
235: // test single attribute
236: conf.load();
237: key = "clear.element2[@id]";
238: conf.clearProperty(key);
239: assertNull(key, conf.getProperty(key));
240: assertNull(key, conf.getProperty(key));
241: key = "clear.element2";
242: assertNotNull(key, conf.getProperty(key));
243: assertNotNull(key, conf.getProperty(key));
244:
245: // test multiple, disjoined attributes
246: conf.load();
247: key = "clear.list.item[@id]";
248: conf.clearProperty(key);
249: assertNull(key, conf.getProperty(key));
250: assertNull(key, conf.getProperty(key));
251: key = "clear.list.item";
252: assertNotNull(key, conf.getProperty(key));
253: assertNotNull(key, conf.getProperty(key));
254: }
255:
256: public void testSetAttribute() {
257: // replace an existing attribute
258: conf.setProperty("element3[@name]", "bar");
259: assertEquals("element3[@name]", "bar", conf
260: .getProperty("element3[@name]"));
261:
262: // set a new attribute
263: conf.setProperty("foo[@bar]", "value");
264: assertEquals("foo[@bar]", "value", conf
265: .getProperty("foo[@bar]"));
266:
267: conf.setProperty("name1", "value1");
268: assertEquals("value1", conf.getProperty("name1"));
269: }
270:
271: public void testAddAttribute() {
272: conf.addProperty("element3[@name]", "bar");
273:
274: List list = conf.getList("element3[@name]");
275: assertNotNull("null list", list);
276: assertTrue("'foo' element missing", list.contains("foo"));
277: assertTrue("'bar' element missing", list.contains("bar"));
278: assertEquals("list size", 2, list.size());
279: }
280:
281: public void testAddObjectAttribute() {
282: conf.addProperty("test.boolean[@value]", Boolean.TRUE);
283: assertTrue("test.boolean[@value]", conf
284: .getBoolean("test.boolean[@value]"));
285: }
286:
287: public void testAddList() {
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: assertEquals("I'm complex!", conf
300: .getProperty("element2.subelement.subsubelement"));
301: }
302:
303: public void testSettingFileNames() {
304: conf = new XMLConfiguration();
305: conf.setFileName(testProperties);
306: assertEquals(testProperties.toString(), conf.getFileName());
307:
308: conf.setBasePath(testBasePath);
309: conf.setFileName("hello.xml");
310: assertEquals("hello.xml", conf.getFileName());
311: assertEquals(testBasePath.toString(), conf.getBasePath());
312: assertEquals(new File(testBasePath, "hello.xml"), conf
313: .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
320: .getFile());
321: }
322:
323: public void testLoad() throws Exception {
324: conf = new XMLConfiguration();
325: conf.setFileName(testProperties);
326: conf.load();
327:
328: assertEquals("I'm complex!", conf
329: .getProperty("element2.subelement.subsubelement"));
330: }
331:
332: public void testLoadWithBasePath() throws Exception {
333: conf = new XMLConfiguration();
334:
335: conf.setFileName("test.xml");
336: conf.setBasePath(testBasePath);
337: conf.load();
338:
339: assertEquals("I'm complex!", conf
340: .getProperty("element2.subelement.subsubelement"));
341: }
342:
343: /**
344: * Tests constructing an XMLConfiguration from a non existing file and
345: * later saving to this file.
346: */
347: public void testLoadAndSaveFromFile() throws Exception {
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: URL url = new File(testProperties).toURL();
363: conf = new XMLConfiguration(url);
364: assertEquals("value", conf.getProperty("element"));
365: assertEquals(url, conf.getURL());
366: }
367:
368: /**
369: * Tests loading from a stream.
370: */
371: public void testLoadFromStream() throws Exception {
372: String xml = "<?xml version=\"1.0\"?><config><test>1</test></config>";
373: conf = new XMLConfiguration();
374: conf.load(new ByteArrayInputStream(xml.getBytes()));
375: assertEquals(1, conf.getInt("test"));
376:
377: conf = new XMLConfiguration();
378: conf.load(new ByteArrayInputStream(xml.getBytes()), "UTF8");
379: assertEquals(1, conf.getInt("test"));
380: }
381:
382: /**
383: * Tests loading a non well formed XML from a string.
384: */
385: public void testLoadInvalidXML() throws Exception {
386: String xml = "<?xml version=\"1.0\"?><config><test>1</rest></config>";
387: conf = new XMLConfiguration();
388: try {
389: conf.load(new StringReader(xml));
390: fail("Could load invalid XML!");
391: } catch (ConfigurationException cex) {
392: //ok
393: }
394: }
395:
396: public void testSetProperty() throws Exception {
397: conf.setProperty("element.string", "hello");
398:
399: assertEquals("'element.string'", "hello", conf
400: .getString("element.string"));
401: assertEquals("XML value of element.string", "hello", conf
402: .getProperty("element.string"));
403: }
404:
405: public void testAddProperty() {
406: // add a property to a non initialized xml configuration
407: XMLConfiguration config = new XMLConfiguration();
408: config.addProperty("test.string", "hello");
409:
410: assertEquals("'test.string'", "hello", config
411: .getString("test.string"));
412: }
413:
414: public void testAddObjectProperty() {
415: // add a non string property
416: conf.addProperty("test.boolean", Boolean.TRUE);
417: assertTrue("'test.boolean'", conf.getBoolean("test.boolean"));
418: }
419:
420: public void testSave() throws Exception {
421: // add an array of strings to the configuration
422: conf.addProperty("string", "value1");
423: for (int i = 1; i < 5; i++) {
424: conf.addProperty("test.array", "value" + i);
425: }
426:
427: // add an array of strings in an attribute
428: for (int i = 1; i < 5; i++) {
429: conf.addProperty("test.attribute[@array]", "value" + i);
430: }
431:
432: // add comma delimited lists with escaped delimiters
433: conf.addProperty("split.list5", "a\\,b\\,c");
434: conf.setProperty("element3", "value\\,value1\\,value2");
435: conf.setProperty("element3[@name]", "foo\\,bar");
436:
437: // save the configuration
438: conf.save(testSaveConf.getAbsolutePath());
439:
440: // read the configuration and compare the properties
441: XMLConfiguration checkConfig = new XMLConfiguration();
442: checkConfig.setFileName(testSaveConf.getAbsolutePath());
443: checkSavedConfig(checkConfig);
444: }
445:
446: /**
447: * Tests saving to a URL.
448: */
449: public void testSaveToURL() throws Exception {
450: conf.save(testSaveConf.toURL());
451: XMLConfiguration checkConfig = new XMLConfiguration();
452: checkConfig.setFile(testSaveConf);
453: checkSavedConfig(checkConfig);
454: }
455:
456: /**
457: * Tests saving to a stream.
458: */
459: public void testSaveToStream() throws Exception {
460: assertNull(conf.getEncoding());
461: conf.setEncoding("UTF8");
462: FileOutputStream out = null;
463: try {
464: out = new FileOutputStream(testSaveConf);
465: conf.save(out);
466: } finally {
467: if (out != null) {
468: out.close();
469: }
470: }
471:
472: XMLConfiguration checkConfig = new XMLConfiguration();
473: checkConfig.setFile(testSaveConf);
474: checkSavedConfig(checkConfig);
475:
476: try {
477: out = new FileOutputStream(testSaveConf);
478: conf.save(out, "UTF8");
479: } finally {
480: if (out != null) {
481: out.close();
482: }
483: }
484:
485: checkConfig.clear();
486: checkSavedConfig(checkConfig);
487: }
488:
489: public void testAutoSave() throws Exception {
490: conf.setFile(new File("target/testsave.xml"));
491: assertFalse(conf.isAutoSave());
492: conf.setAutoSave(true);
493: assertTrue(conf.isAutoSave());
494: conf.setProperty("autosave", "ok");
495:
496: // reload the configuration
497: XMLConfiguration conf2 = new XMLConfiguration(conf.getFile());
498: assertEquals("'autosave' property", "ok", conf2
499: .getString("autosave"));
500:
501: conf.clearTree("clear");
502: conf2 = new XMLConfiguration(conf.getFile());
503: Configuration sub = conf2.subset("clear");
504: assertTrue(sub.isEmpty());
505: }
506:
507: /**
508: * Tests if a second file can be appended to a first.
509: */
510: public void testAppend() throws Exception {
511: conf = new XMLConfiguration();
512: conf.setFileName(testProperties);
513: conf.load();
514: conf.load(testProperties2);
515: assertEquals("value", conf.getString("element"));
516: assertEquals("tasks", conf.getString("table.name"));
517:
518: conf.save(testSaveConf);
519: conf = new XMLConfiguration(testSaveConf);
520: assertEquals("value", conf.getString("element"));
521: assertEquals("tasks", conf.getString("table.name"));
522: assertEquals("application", conf.getString("table[@tableType]"));
523: }
524:
525: /**
526: * Tests saving attributes (related to issue 34442).
527: */
528: public void testSaveAttributes() throws Exception {
529: conf.clear();
530: conf.load();
531: conf.save(testSaveConf);
532: conf = new XMLConfiguration();
533: conf.load(testSaveConf);
534: assertEquals("foo", conf.getString("element3[@name]"));
535: }
536:
537: /**
538: * Tests collaboration between XMLConfiguration and a reloading strategy.
539: */
540: public void testReloading() throws Exception {
541: assertNotNull(conf.getReloadingStrategy());
542: assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy);
543: PrintWriter out = null;
544:
545: try {
546: out = new PrintWriter(new FileWriter(testSaveConf));
547: out
548: .println("<?xml version=\"1.0\"?><config><test>1</test></config>");
549: out.close();
550: out = null;
551: conf.setFile(testSaveConf);
552: FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy();
553: strategy.setRefreshDelay(100);
554: conf.setReloadingStrategy(strategy);
555: assertEquals(strategy, conf.getReloadingStrategy());
556: assertEquals("Wrong file monitored", testSaveConf
557: .getAbsolutePath(), strategy.getMonitoredFile()
558: .getAbsolutePath());
559: conf.load();
560: assertEquals(1, conf.getInt("test"));
561:
562: out = new PrintWriter(new FileWriter(testSaveConf));
563: out
564: .println("<?xml version=\"1.0\"?><config><test>2</test></config>");
565: out.close();
566: out = null;
567:
568: int value = conf.getInt("test");
569: assertEquals("No reloading performed", 2, value);
570: } finally {
571: if (out != null) {
572: out.close();
573: }
574: }
575: }
576:
577: /**
578: * Tests access to tag names with delimiter characters.
579: */
580: public void testComplexNames() {
581: assertEquals("Name with dot", conf
582: .getString("complexNames.my..elem"));
583: assertEquals("Another dot", conf
584: .getString("complexNames.my..elem.sub..elem"));
585: }
586:
587: /**
588: * Tests setting a custom document builder.
589: */
590: public void testCustomDocBuilder() throws Exception {
591: // Load an invalid XML file with the default (non validating)
592: // doc builder. This should work...
593: conf = new XMLConfiguration();
594: conf.load(new File("conf/testValidateInvalid.xml"));
595: assertEquals("customers", conf.getString("table.name"));
596: assertFalse(conf.containsKey("table.fields.field(1).type"));
597:
598: // Now create a validating doc builder and set it.
599: DocumentBuilderFactory factory = DocumentBuilderFactory
600: .newInstance();
601: factory.setValidating(true);
602: DocumentBuilder builder = factory.newDocumentBuilder();
603: builder.setErrorHandler(new DefaultHandler() {
604: public void error(SAXParseException ex) throws SAXException {
605: throw ex;
606: }
607: });
608: conf = new XMLConfiguration();
609: conf.setDocumentBuilder(builder);
610: try {
611: conf.load(new File("conf/testValidateInvalid.xml"));
612: fail("Could load invalid file with validating set to true!");
613: } catch (ConfigurationException ex) {
614: //ok
615: }
616:
617: // Try to load a valid document with a validating builder
618: conf = new XMLConfiguration();
619: conf.setDocumentBuilder(builder);
620: conf.load(new File("conf/testValidateValid.xml"));
621: assertTrue(conf.containsKey("table.fields.field(1).type"));
622: }
623:
624: /**
625: * Tests the clone() method.
626: */
627: public void testClone() {
628: Configuration c = (Configuration) conf.clone();
629: assertTrue(c instanceof XMLConfiguration);
630: XMLConfiguration copy = (XMLConfiguration) c;
631: assertNotNull(conf.getDocument());
632: assertNull(copy.getDocument());
633: assertNotNull(conf.getFileName());
634: assertNull(copy.getFileName());
635:
636: copy.setProperty("element3", "clonedValue");
637: assertEquals("value", conf.getString("element3"));
638: conf.setProperty("element3[@name]", "originalFoo");
639: assertEquals("foo", copy.getString("element3[@name]"));
640: }
641:
642: /**
643: * Tests saving a configuration after cloning to ensure that the clone and
644: * the original are completely detachted.
645: */
646: public void testCloneWithSave() throws ConfigurationException {
647: XMLConfiguration c = (XMLConfiguration) conf.clone();
648: c.addProperty("test.newProperty", Boolean.TRUE);
649: conf.addProperty("test.orgProperty", Boolean.TRUE);
650: c.save(testSaveConf);
651: XMLConfiguration c2 = new XMLConfiguration(testSaveConf);
652: assertTrue("New property after clone() was not saved", c2
653: .getBoolean("test.newProperty"));
654: assertFalse("Property of original config was saved", c2
655: .containsKey("test.orgProperty"));
656: }
657:
658: /**
659: * Tests the subset() method. There was a bug that calling subset() had
660: * undesired side effects.
661: */
662: public void testSubset() throws ConfigurationException {
663: conf = new XMLConfiguration();
664: conf
665: .load(new File(
666: "conf/testHierarchicalXMLConfiguration.xml"));
667: conf.subset("tables.table(0)");
668: conf.save(testSaveConf);
669:
670: conf = new XMLConfiguration(testSaveConf);
671: assertEquals("users", conf.getString("tables.table(0).name"));
672: }
673:
674: /**
675: * Tests string properties with list delimiters and escaped delimiters.
676: */
677: public void testSplitLists() {
678: assertEquals("a", conf.getString("split.list3[@values]"));
679: assertEquals(2, conf.getMaxIndex("split.list3[@values]"));
680: assertEquals("a,b,c", conf.getString("split.list4[@values]"));
681: assertEquals("a", conf.getString("split.list1"));
682: assertEquals(2, conf.getMaxIndex("split.list1"));
683: assertEquals("a,b,c", conf.getString("split.list2"));
684: }
685:
686: /**
687: * Tests string properties with list delimiters when delimiter parsing
688: * is disabled
689: */
690: public void testDelimiterParsingDisabled()
691: throws ConfigurationException {
692: XMLConfiguration conf2 = new XMLConfiguration();
693: conf2.setDelimiterParsingDisabled(true);
694: conf2.setFile(new File(testProperties));
695: conf2.load();
696:
697: assertEquals("a,b,c", conf2.getString("split.list3[@values]"));
698: assertEquals(0, conf2.getMaxIndex("split.list3[@values]"));
699: assertEquals("a\\,b\\,c", conf2
700: .getString("split.list4[@values]"));
701: assertEquals("a,b,c", conf2.getString("split.list1"));
702: assertEquals(0, conf2.getMaxIndex("split.list1"));
703: assertEquals("a\\,b\\,c", conf2.getString("split.list2"));
704: }
705:
706: /**
707: * Tests whether a DTD can be accessed.
708: */
709: public void testDtd() throws ConfigurationException {
710: conf = new XMLConfiguration("testDtd.xml");
711: assertEquals("value1", conf.getString("entry(0)"));
712: assertEquals("test2", conf.getString("entry(1)[@key]"));
713: }
714:
715: /**
716: * Tests DTD validation using the setValidating() method.
717: */
718: public void testValidating() throws ConfigurationException {
719: File nonValidFile = new File("conf/testValidateInvalid.xml");
720: conf = new XMLConfiguration();
721: assertFalse(conf.isValidating());
722:
723: // Load a non valid XML document. Should work for isValidating() == false
724: conf.load(nonValidFile);
725: assertEquals("customers", conf.getString("table.name"));
726: assertFalse(conf.containsKey("table.fields.field(1).type"));
727:
728: // Now set the validating flag to true
729: conf.setValidating(true);
730: try {
731: conf.load(nonValidFile);
732: fail("Validation was not performed!");
733: } catch (ConfigurationException cex) {
734: //ok
735: }
736: }
737:
738: /**
739: * Tests handling of empty elements.
740: */
741: public void testEmptyElements() throws ConfigurationException {
742: assertTrue(conf.containsKey("empty"));
743: assertEquals("", conf.getString("empty"));
744: conf.addProperty("empty2", "");
745: conf.setProperty("empty", "no more empty");
746: conf.save(testSaveConf);
747:
748: conf = new XMLConfiguration(testSaveConf);
749: assertEquals("no more empty", conf.getString("empty"));
750: assertEquals("", conf.getProperty("empty2"));
751: }
752:
753: /**
754: * Tests whether the encoding is correctly detected by the XML parser. This
755: * is done by loading an XML file with the encoding "UTF-16". If this
756: * encoding is not detected correctly, an exception will be thrown that
757: * "Content is not allowed in prolog". This test case is related to issue
758: * 34204.
759: */
760: public void testLoadWithEncoding() throws ConfigurationException {
761: File file = new File("conf/testEncoding.xml");
762: conf = new XMLConfiguration();
763: conf.load(file);
764: assertEquals("test3_yoge", conf.getString("yoge"));
765: }
766:
767: /**
768: * Tests whether the encoding is written to the generated XML file.
769: */
770: public void testSaveWithEncoding() throws ConfigurationException {
771: conf = new XMLConfiguration();
772: conf.setProperty("test", "a value");
773: conf.setEncoding(ENCODING);
774:
775: StringWriter out = new StringWriter();
776: conf.save(out);
777: assertTrue("Encoding was not written to file", out.toString()
778: .indexOf("encoding=\"" + ENCODING + "\"") >= 0);
779: }
780:
781: /**
782: * Tests whether a default encoding is used if no specific encoding is set.
783: * According to the XSLT specification (http://www.w3.org/TR/xslt#output)
784: * this should be either UTF-8 or UTF-16.
785: */
786: public void testSaveWithNullEncoding()
787: throws ConfigurationException {
788: conf = new XMLConfiguration();
789: conf.setProperty("testNoEncoding", "yes");
790: conf.setEncoding(null);
791:
792: StringWriter out = new StringWriter();
793: conf.save(out);
794: assertTrue("Encoding was written to file", out.toString()
795: .indexOf("encoding=\"UTF-") >= 0);
796: }
797:
798: /**
799: * Tests whether the DOCTYPE survives a save operation.
800: */
801: public void testSaveWithDoctype() throws ConfigurationException {
802: String content = "<?xml version=\"1.0\"?>"
803: + DOCTYPE
804: + "properties"
805: + DOCTYPE_DECL
806: + "<properties version=\"1.0\"><entry key=\"test\">value</entry></properties>";
807: StringReader in = new StringReader(content);
808: conf = new XMLConfiguration();
809: conf.setFileName("conf/testDtd.xml");
810: conf.load();
811: conf.clear();
812: conf.load(in);
813:
814: assertEquals("Wrong public ID", PUBLIC_ID, conf.getPublicID());
815: assertEquals("Wrong system ID", SYSTEM_ID, conf.getSystemID());
816: StringWriter out = new StringWriter();
817: conf.save(out);
818: System.out.println(out.toString());
819: assertTrue("Did not find DOCTYPE", out.toString().indexOf(
820: DOCTYPE) >= 0);
821: }
822:
823: /**
824: * Tests setting public and system IDs for the D'OCTYPE and then saving the
825: * configuration. This should generate a DOCTYPE declaration.
826: */
827: public void testSaveWithDoctypeIDs() throws ConfigurationException {
828: assertNull("A public ID was found", conf.getPublicID());
829: assertNull("A system ID was found", conf.getSystemID());
830: conf.setPublicID(PUBLIC_ID);
831: conf.setSystemID(SYSTEM_ID);
832: StringWriter out = new StringWriter();
833: conf.save(out);
834: assertTrue("Did not find DOCTYPE", out.toString().indexOf(
835: DOCTYPE + "testconfig" + DOCTYPE_DECL) >= 0);
836: }
837:
838: /**
839: * Tests saving a configuration when an invalid transformer factory is
840: * specified. In this case the error thrown by the TransformerFactory class
841: * should be caught and re-thrown as a ConfigurationException.
842: */
843: public void testSaveWithInvalidTransformerFactory() {
844: System.setProperty(PROP_FACTORY, "an.invalid.Class");
845: try {
846: conf.save(testSaveConf);
847: fail("Could save with invalid TransformerFactory!");
848: } catch (ConfigurationException cex) {
849: // ok
850: } finally {
851: System.getProperties().remove(PROP_FACTORY);
852: }
853: }
854:
855: /**
856: * Tests if reloads are recognized by subset().
857: */
858: public void testSubsetWithReload() throws ConfigurationException {
859: XMLConfiguration c = setUpReloadTest();
860: Configuration sub = c.subset("test");
861: assertEquals("New value not read", "newValue", sub
862: .getString("entity"));
863: }
864:
865: /**
866: * Tests if reloads are recognized by configurationAt().
867: */
868: public void testConfigurationAtWithReload()
869: throws ConfigurationException {
870: XMLConfiguration c = setUpReloadTest();
871: HierarchicalConfiguration sub = c.configurationAt("test(0)");
872: assertEquals("New value not read", "newValue", sub
873: .getString("entity"));
874: }
875:
876: /**
877: * Tests if reloads are recognized by configurationsAt().
878: */
879: public void testConfigurationsAtWithReload()
880: throws ConfigurationException {
881: XMLConfiguration c = setUpReloadTest();
882: List configs = c.configurationsAt("test");
883: assertEquals("New value not read", "newValue",
884: ((HierarchicalConfiguration) configs.get(0))
885: .getString("entity"));
886: }
887:
888: /**
889: * Tests accessing properties when the XPATH expression engine is set.
890: */
891: public void testXPathExpressionEngine() {
892: conf.setExpressionEngine(new XPathExpressionEngine());
893: assertEquals("Wrong attribute value", "foo\"bar", conf
894: .getString("test[1]/entity/@name"));
895: conf.clear();
896: assertNull(conf.getString("test[1]/entity/@name"));
897: }
898:
899: /**
900: * Tests the copy constructor.
901: */
902: public void testInitCopy() throws ConfigurationException {
903: XMLConfiguration copy = new XMLConfiguration(conf);
904: assertEquals("value", copy.getProperty("element"));
905: assertNull("Document was copied, too", copy.getDocument());
906: ConfigurationNode root = copy.getRootNode();
907: for (Iterator it = root.getChildren().iterator(); it.hasNext();) {
908: ConfigurationNode node = (ConfigurationNode) it.next();
909: assertNull("Reference was not cleared", node.getReference());
910: }
911:
912: removeTestFile();
913: copy.setFile(testSaveConf);
914: copy.save();
915: copy.clear();
916: checkSavedConfig(copy);
917: }
918:
919: /**
920: * Prepares a configuration object for testing a reload operation.
921: *
922: * @return the initialized configuration
923: * @throws ConfigurationException if an error occurs
924: */
925: private XMLConfiguration setUpReloadTest()
926: throws ConfigurationException {
927: removeTestFile();
928: conf.save(testSaveConf);
929: XMLConfiguration c = new XMLConfiguration(testSaveConf);
930: c.setReloadingStrategy(new FileChangedReloadingStrategy() {
931: // Report always a change
932: protected boolean hasChanged() {
933: return true;
934: }
935: });
936: conf.setProperty("test(0).entity", "newValue");
937: conf.save(testSaveConf);
938: return c;
939: }
940:
941: /**
942: * Removes the test output file if it exists.
943: */
944: private void removeTestFile() {
945: if (testSaveConf.exists()) {
946: assertTrue(testSaveConf.delete());
947: }
948: }
949:
950: /**
951: * Helper method for checking if a save operation was successful. Loads a
952: * saved configuration and then tests against a reference configuration.
953: * @param checkConfig the configuration to check
954: * @throws ConfigurationException if an error occurs
955: */
956: private void checkSavedConfig(FileConfiguration checkConfig)
957: throws ConfigurationException {
958: checkConfig.load();
959:
960: for (Iterator i = conf.getKeys(); i.hasNext();) {
961: String key = (String) i.next();
962: assertTrue(
963: "The saved configuration doesn't contain the key '"
964: + key + "'", checkConfig.containsKey(key));
965: assertEquals("Value of the '" + key + "' property", conf
966: .getProperty(key), checkConfig.getProperty(key));
967: }
968: }
969: }
|