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.File;
21 import java.io.FileWriter;
22 import java.io.IOException;
23 import java.io.PrintWriter;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.io.StringWriter;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30
31 import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
32
33 import junit.framework.TestCase;
34
35 /***
36 * Test for loading and saving properties files.
37 *
38 * @version $Id: TestPropertiesConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
39 */
40 public class TestPropertiesConfiguration extends TestCase
41 {
42 private PropertiesConfiguration conf;
43
44 /*** The File that we test with */
45 private String testProperties = new File("conf/test.properties").getAbsolutePath();
46
47 private String testBasePath = new File("conf").getAbsolutePath();
48 private String testBasePath2 = new File("conf").getAbsoluteFile().getParentFile().getAbsolutePath();
49 private File testSavePropertiesFile = new File("target/testsave.properties");
50
51 protected void setUp() throws Exception
52 {
53 conf = new PropertiesConfiguration(testProperties);
54 }
55
56 public void testLoad() throws Exception
57 {
58 String loaded = conf.getString("configuration.loaded");
59 assertEquals("true", loaded);
60 }
61
62 /***
63 * Tests if properties can be appended by simply calling load() another
64 * time.
65 */
66 public void testAppend() throws Exception
67 {
68 File file2 = new File("conf/threesome.properties");
69 conf.load(file2);
70 assertEquals("aaa", conf.getString("test.threesome.one"));
71 assertEquals("true", conf.getString("configuration.loaded"));
72 }
73
74 /***
75 * Tests that empty properties are treated as the empty string
76 * (rather than as null).
77 */
78 public void testEmpty() throws Exception
79 {
80 String empty = conf.getString("test.empty");
81 assertNotNull(empty);
82 assertEquals("", empty);
83 }
84
85 /***
86 * Tests that references to other properties work
87 */
88 public void testReference() throws Exception
89 {
90 assertEquals("baseextra", conf.getString("base.reference"));
91 }
92
93 /***
94 * test if includes properties get loaded too
95 */
96 public void testLoadInclude() throws Exception
97 {
98 String loaded = conf.getString("include.loaded");
99 assertEquals("true", loaded);
100 }
101
102 public void testSetInclude() throws Exception
103 {
104
105 PropertiesConfiguration.setInclude("import");
106
107
108 PropertiesConfiguration conf = new PropertiesConfiguration();
109 conf.load("conf/test.properties");
110
111
112 PropertiesConfiguration.setInclude("include");
113
114 assertNull(conf.getString("include.loaded"));
115 }
116
117 /***
118 * Tests <code>List</code> parsing.
119 */
120 public void testList() throws Exception
121 {
122 List packages = conf.getList("packages");
123
124 assertEquals(3, packages.size());
125 }
126
127 public void testSave() throws Exception
128 {
129
130 if (testSavePropertiesFile.exists())
131 {
132 assertTrue(testSavePropertiesFile.delete());
133 }
134
135
136 conf.addProperty("string", "value1");
137 List list = new ArrayList();
138 for (int i = 1; i < 5; i++)
139 {
140 list.add("value" + i);
141 }
142 conf.addProperty("array", list);
143
144
145 String filename = testSavePropertiesFile.getAbsolutePath();
146 conf.save(filename);
147
148 assertTrue("The saved file doesn't exist", testSavePropertiesFile.exists());
149
150
151 PropertiesConfiguration checkConfig = new PropertiesConfiguration(filename);
152 for (Iterator i = conf.getKeys(); i.hasNext();)
153 {
154 String key = (String) i.next();
155 assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key));
156 assertEquals("Value of the '" + key + "' property", conf.getProperty(key), checkConfig.getProperty(key));
157 }
158
159
160 checkConfig.save();
161 }
162
163 public void testInMemoryCreatedSave() throws Exception
164 {
165
166 if (testSavePropertiesFile.exists())
167 {
168 assertTrue(testSavePropertiesFile.delete());
169 }
170
171 PropertiesConfiguration pc = new PropertiesConfiguration();
172
173 pc.addProperty("string", "value1");
174 List list = new ArrayList();
175 for (int i = 1; i < 5; i++)
176 {
177 list.add("value" + i);
178 }
179 pc.addProperty("array", list);
180
181
182 String filename = testSavePropertiesFile.getAbsolutePath();
183 pc.save(filename);
184
185 assertTrue("The saved file doesn't exist", testSavePropertiesFile.exists());
186
187
188 PropertiesConfiguration checkConfig = new PropertiesConfiguration(filename);
189 for (Iterator i = pc.getKeys(); i.hasNext();)
190 {
191 String key = (String) i.next();
192 assertTrue("The saved configuration doesn't contain the key '" + key + "'",
193 checkConfig.containsKey(key));
194 assertEquals("Value of the '" + key + "' property",
195 pc.getProperty(key), checkConfig.getProperty(key));
196 }
197
198
199 checkConfig.save();
200 }
201
202 public void testSaveMissingFilename()
203 {
204 PropertiesConfiguration pc = new PropertiesConfiguration();
205 try
206 {
207 pc.save();
208 fail("Should have throw ConfigurationException");
209 }
210 catch (ConfigurationException ce)
211 {
212
213 }
214 }
215
216 /***
217 * Tests if the base path is taken into account by the save() method.
218 * @throws Exception if an error occurs
219 */
220 public void testSaveWithBasePath() throws Exception
221 {
222
223 if (testSavePropertiesFile.exists())
224 {
225 assertTrue(testSavePropertiesFile.delete());
226 }
227
228 conf.setProperty("test", "true");
229 conf.setBasePath(testSavePropertiesFile.getParentFile().toURL().toString());
230 conf.setFileName(testSavePropertiesFile.getName());
231 conf.save();
232 assertTrue(testSavePropertiesFile.exists());
233 }
234
235 public void testLoadViaProperty() throws Exception
236 {
237 PropertiesConfiguration pc = new PropertiesConfiguration();
238 pc.setFileName(testProperties);
239 pc.load();
240
241 assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean"));
242 }
243
244 public void testLoadViaPropertyWithBasePath() throws Exception
245 {
246 PropertiesConfiguration pc = new PropertiesConfiguration();
247 pc.setBasePath(testBasePath);
248 pc.setFileName("test.properties");
249 pc.load();
250
251 assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean"));
252 }
253
254 public void testLoadViaPropertyWithBasePath2() throws Exception
255 {
256 PropertiesConfiguration pc = new PropertiesConfiguration();
257 pc.setBasePath(testBasePath2);
258 pc.setFileName("conf/test.properties");
259 pc.load();
260
261 assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean"));
262
263 pc = new PropertiesConfiguration();
264 pc.setBasePath(testBasePath2);
265 pc.setFileName("conf/test.properties");
266 pc.load();
267
268 assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean"));
269 }
270
271 public void testLoadFromFile() throws Exception
272 {
273 File file = new File("conf/test.properties");
274 conf = new PropertiesConfiguration(file);
275
276 assertEquals("true", conf.getString("configuration.loaded"));
277 }
278
279 public void testLoadUnexistingFile()
280 {
281 try
282 {
283 conf = new PropertiesConfiguration("Unexisting file");
284 fail("Unexisting file was loaded.");
285 }
286 catch(ConfigurationException cex)
287 {
288
289 }
290 }
291
292 /***
293 * Tests to load a file with enabled auto save mode.
294 */
295 public void testLoadWithAutoSave() throws Exception
296 {
297 setUpSavedProperties();
298 }
299
300 /***
301 * Tests the auto save functionality when an existing property is modified.
302 */
303 public void testLoadWithAutoSaveAndSetExisting() throws Exception
304 {
305 setUpSavedProperties();
306 conf.setProperty("a", "moreThanOne");
307 checkSavedConfig();
308 }
309
310 /***
311 * Tests the auto save functionality when a new property is added using the
312 * setProperty() method.
313 */
314 public void testLoadWithAutoSaveAndSetNew() throws Exception
315 {
316 setUpSavedProperties();
317 conf.setProperty("d", "four");
318 checkSavedConfig();
319 }
320
321 /***
322 * Tests the auto save functionality when a new property is added using the
323 * addProperty() method.
324 */
325 public void testLoadWithAutoSaveAndAdd() throws Exception
326 {
327 setUpSavedProperties();
328 conf.addProperty("d", "four");
329 checkSavedConfig();
330 }
331
332 /***
333 * Tests the auto save functionality when a property is removed.
334 */
335 public void testLoadWithAutoSaveAndClear() throws Exception
336 {
337 setUpSavedProperties();
338 conf.clearProperty("c");
339 PropertiesConfiguration checkConfig = checkSavedConfig();
340 assertFalse("The saved configuration contain the key '" + "c" + "'",
341 checkConfig.containsKey("c"));
342 }
343
344 /***
345 * Creates a properties file on disk. Used for testing load and save
346 * operations.
347 *
348 * @throws IOException if an I/O error occurs
349 */
350 private void setUpSavedProperties() throws IOException,
351 ConfigurationException
352 {
353 PrintWriter out = null;
354
355 try
356 {
357 out = new PrintWriter(new FileWriter(testSavePropertiesFile));
358 out.println("a = one");
359 out.println("b = two");
360 out.println("c = three");
361 out.close();
362 out = null;
363
364 conf = new PropertiesConfiguration();
365 conf.setAutoSave(true);
366 conf.setFile(testSavePropertiesFile);
367 conf.load();
368 assertEquals("one", conf.getString("a"));
369 assertEquals("two", conf.getString("b"));
370 assertEquals("three", conf.getString("c"));
371 }
372 finally
373 {
374 if (out != null)
375 {
376 out.close();
377 }
378 }
379 }
380
381 /***
382 * Helper method for testing a saved configuration. Reads in the file using
383 * a new instance and compares this instance with the original one.
384 *
385 * @return the newly created configuration instance
386 * @throws ConfigurationException if an error occurs
387 */
388 private PropertiesConfiguration checkSavedConfig()
389 throws ConfigurationException
390 {
391 PropertiesConfiguration checkConfig = new PropertiesConfiguration(
392 testSavePropertiesFile);
393 for (Iterator i = conf.getKeys(); i.hasNext();)
394 {
395 String key = (String) i.next();
396 assertTrue("The saved configuration doesn't contain the key '"
397 + key + "'", checkConfig.containsKey(key));
398 assertEquals("Value of the '" + key + "' property", conf
399 .getProperty(key), checkConfig.getProperty(key));
400 }
401 return checkConfig;
402 }
403
404 public void testGetStringWithEscapedChars()
405 {
406 String property = conf.getString("test.unescape");
407 assertEquals("String with escaped characters", "This \n string \t contains \" escaped // characters", property);
408 }
409
410 public void testGetStringWithEscapedComma()
411 {
412 String property = conf.getString("test.unescape.list-separator");
413 assertEquals("String with an escaped list separator", "This string contains , an escaped list separator", property);
414 }
415
416 public void testUnescapeJava()
417 {
418 assertEquals("test//,test", PropertiesConfiguration.unescapeJava("test//,test", ','));
419 }
420
421 public void testEscapedKey() throws Exception
422 {
423 PropertiesConfiguration conf = new PropertiesConfiguration();
424 conf.load(new StringReader("//u0066//u006f//u006f=bar"));
425
426 assertEquals("value of the 'foo' property", "bar", conf.getString("foo"));
427 }
428
429 public void testMixedArray()
430 {
431 String[] array = conf.getStringArray("test.mixed.array");
432
433 assertEquals("array length", 4, array.length);
434 assertEquals("1st element", "a", array[0]);
435 assertEquals("2nd element", "b", array[1]);
436 assertEquals("3rd element", "c", array[2]);
437 assertEquals("4th element", "d", array[3]);
438 }
439
440 public void testMultilines()
441 {
442 String property = "This is a value spread out across several adjacent "
443 + "natural lines by escaping the line terminator with "
444 + "a backslash character.";
445
446 assertEquals("'test.multilines' property", property, conf.getString("test.multilines"));
447 }
448
449 public void testChangingDefaultListDelimiter() throws Exception
450 {
451 PropertiesConfiguration pc = new PropertiesConfiguration(testProperties);
452 assertEquals(4, pc.getList("test.mixed.array").size());
453
454 char delimiter = PropertiesConfiguration.getDefaultListDelimiter();
455 PropertiesConfiguration.setDefaultListDelimiter('^');
456 pc = new PropertiesConfiguration(testProperties);
457 assertEquals(2, pc.getList("test.mixed.array").size());
458 PropertiesConfiguration.setDefaultListDelimiter(delimiter);
459 }
460
461 public void testChangingListDelimiter() throws Exception
462 {
463 PropertiesConfiguration pc1 = new PropertiesConfiguration(testProperties);
464 assertEquals(4, pc1.getList("test.mixed.array").size());
465
466 PropertiesConfiguration pc2 = new PropertiesConfiguration();
467 pc2.setListDelimiter('^');
468 pc2.setFileName(testProperties);
469 pc2.load();
470 assertEquals("Should obtain the first value", "a", pc2.getString("test.mixed.array"));
471 assertEquals(2, pc2.getList("test.mixed.array").size());
472 }
473
474 public void testDisableListDelimiter() throws Exception
475 {
476 PropertiesConfiguration pc1 = new PropertiesConfiguration(testProperties);
477 assertEquals(4, pc1.getList("test.mixed.array").size());
478
479 PropertiesConfiguration pc2 = new PropertiesConfiguration();
480 pc2.setDelimiterParsingDisabled(true);
481 pc2.setFileName(testProperties);
482 pc2.load();
483 assertEquals(2, pc2.getList("test.mixed.array").size());
484 }
485
486 /***
487 * Tests escaping of an end of line with a backslash.
488 */
489 public void testNewLineEscaping()
490 {
491 List list = conf.getList("test.path");
492 assertEquals(3, list.size());
493 assertEquals("C://path1//", list.get(0));
494 assertEquals("C://path2//", list.get(1));
495 assertEquals("C://path3//complex//test//", list.get(2));
496 }
497
498 /***
499 * Tests if included files are loaded when the source lies in the class path.
500 */
501 public void testLoadIncludeFromClassPath() throws ConfigurationException
502 {
503 conf = new PropertiesConfiguration("test.properties");
504 assertEquals("true", conf.getString("include.loaded"));
505 }
506
507 /***
508 * Test if the lines starting with # or ! are properly ignored.
509 */
510 public void testComment() {
511 assertFalse("comment line starting with '#' parsed as a property", conf.containsKey("#comment"));
512 assertFalse("comment line starting with '!' parsed as a property", conf.containsKey("!comment"));
513 }
514
515 /***
516 * Check that key/value separators can be part of a key.
517 */
518 public void testEscapedKeyValueSeparator()
519 {
520 assertEquals("Escaped separator '=' not supported in keys", "foo", conf.getProperty("test.separator=in.key"));
521 assertEquals("Escaped separator ':' not supported in keys", "bar", conf.getProperty("test.separator:in.key"));
522 assertEquals("Escaped separator '//t' not supported in keys", "foo", conf.getProperty("test.separator\tin.key"));
523 assertEquals("Escaped separator '//f' not supported in keys", "bar", conf.getProperty("test.separator\fin.key"));
524 assertEquals("Escaped separator ' ' not supported in keys" , "foo", conf.getProperty("test.separator in.key"));
525 }
526
527 /***
528 * Test all acceptable key/value separators ('=', ':' or white spaces).
529 */
530 public void testKeyValueSeparators() {
531 assertEquals("equal separator not properly parsed", "foo", conf.getProperty("test.separator.equal"));
532 assertEquals("colon separator not properly parsed", "foo", conf.getProperty("test.separator.colon"));
533 assertEquals("tab separator not properly parsed", "foo", conf.getProperty("test.separator.tab"));
534 assertEquals("formfeed separator not properly parsed", "foo", conf.getProperty("test.separator.formfeed"));
535 assertEquals("whitespace separator not properly parsed", "foo", conf.getProperty("test.separator.whitespace"));
536 }
537
538 /***
539 * Tests including properties when they are loaded from a nested directory
540 * structure.
541 */
542 public void testIncludeInSubDir() throws ConfigurationException
543 {
544 ConfigurationFactory factory = new ConfigurationFactory("conf/testFactoryPropertiesInclude.xml");
545 Configuration config = factory.getConfiguration();
546 assertEquals(true, config.getBoolean("deeptest"));
547 assertEquals(true, config.getBoolean("deepinclude"));
548 assertFalse(config.containsKey("deeptestinvalid"));
549 }
550
551 /***
552 * Tests whether the correct line separator is used.
553 */
554 public void testLineSeparator() throws ConfigurationException
555 {
556 final String EOL = System.getProperty("line.separator");
557 conf = new PropertiesConfiguration();
558 conf.setHeader("My header");
559 conf.setProperty("prop", "value");
560
561 StringWriter out = new StringWriter();
562 conf.save(out);
563 String content = out.toString();
564 assertTrue("Header could not be found", content.indexOf("# My header"
565 + EOL + EOL) == 0);
566 assertTrue("Property could not be found", content
567 .indexOf("prop = value" + EOL) > 0);
568 }
569
570 /***
571 * Tests what happens if a reloading strategy's <code>reloadingRequired()</code>
572 * implementation accesses methods of the configuration that in turn cause a reload.
573 */
574 public void testReentrantReload()
575 {
576 conf.setProperty("shouldReload", Boolean.FALSE);
577 conf.setReloadingStrategy(new FileChangedReloadingStrategy()
578 {
579 public boolean reloadingRequired()
580 {
581 return configuration.getBoolean("shouldReload");
582 }
583 });
584 assertFalse("Property has wrong value", conf.getBoolean("shouldReload"));
585 }
586
587 /***
588 * Tests accessing the layout object.
589 */
590 public void testGetLayout()
591 {
592 PropertiesConfigurationLayout layout = conf.getLayout();
593 assertNotNull("Layout is null", layout);
594 assertSame("Different object returned", layout, conf.getLayout());
595 conf.setLayout(null);
596 PropertiesConfigurationLayout layout2 = conf.getLayout();
597 assertNotNull("Layout 2 is null", layout2);
598 assertNotSame("Same object returned", layout, layout2);
599 }
600
601 /***
602 * Tests the propertyLoaded() method for a simple property.
603 */
604 public void testPropertyLoaded() throws ConfigurationException
605 {
606 DummyLayout layout = new DummyLayout(conf);
607 conf.setLayout(layout);
608 conf.propertyLoaded("layoutLoadedProperty", "yes");
609 assertEquals("Layout's load() was called", 0, layout.loadCalls);
610 assertEquals("Property not added", "yes", conf
611 .getString("layoutLoadedProperty"));
612 }
613
614 /***
615 * Tests the propertyLoaded() method for an include property.
616 */
617 public void testPropertyLoadedInclude() throws ConfigurationException
618 {
619 DummyLayout layout = new DummyLayout(conf);
620 conf.setLayout(layout);
621 conf.propertyLoaded(PropertiesConfiguration.getInclude(),
622 "testClasspath.properties,testEqual.properties");
623 assertEquals("Layout's load() was not correctly called", 2,
624 layout.loadCalls);
625 assertFalse("Property was added", conf
626 .containsKey(PropertiesConfiguration.getInclude()));
627 }
628
629 /***
630 * Tests propertyLoaded() for an include property, when includes are
631 * disabled.
632 */
633 public void testPropertyLoadedIncludeNotAllowed()
634 throws ConfigurationException
635 {
636 DummyLayout layout = new DummyLayout(conf);
637 conf.setLayout(layout);
638 conf.setIncludesAllowed(false);
639 conf.propertyLoaded(PropertiesConfiguration.getInclude(),
640 "testClassPath.properties,testEqual.properties");
641 assertEquals("Layout's load() was called", 0, layout.loadCalls);
642 assertFalse("Property was added", conf
643 .containsKey(PropertiesConfiguration.getInclude()));
644 }
645
646 /***
647 * Tests whether comment lines are correctly detected.
648 */
649 public void testIsCommentLine()
650 {
651 assertTrue("Comment not detected", PropertiesConfiguration
652 .isCommentLine("# a comment"));
653 assertTrue("Alternative comment not detected", PropertiesConfiguration
654 .isCommentLine("! a comment"));
655 assertTrue("Comment with no space not detected",
656 PropertiesConfiguration.isCommentLine("#a comment"));
657 assertTrue("Comment with leading space not detected",
658 PropertiesConfiguration.isCommentLine(" ! a comment"));
659 assertFalse("Wrong comment", PropertiesConfiguration
660 .isCommentLine(" a#comment"));
661 }
662
663 /***
664 * Tests whether a properties configuration can be successfully cloned. It
665 * is especially checked whether the layout object is taken into account.
666 */
667 public void testClone() throws ConfigurationException
668 {
669 PropertiesConfiguration copy = (PropertiesConfiguration) conf.clone();
670 assertNotSame("Copy has same layout object", conf.getLayout(), copy
671 .getLayout());
672 assertEquals("Wrong number of event listeners for original", 1, conf
673 .getConfigurationListeners().size());
674 assertEquals("Wrong number of event listeners for clone", 1, copy
675 .getConfigurationListeners().size());
676 assertSame("Wrong event listener for original", conf.getLayout(), conf
677 .getConfigurationListeners().iterator().next());
678 assertSame("Wrong event listener for clone", copy.getLayout(), copy
679 .getConfigurationListeners().iterator().next());
680 StringWriter outConf = new StringWriter();
681 conf.save(outConf);
682 StringWriter outCopy = new StringWriter();
683 copy.save(outCopy);
684 assertEquals("Output from copy is different", outConf.toString(),
685 outCopy.toString());
686 }
687
688 /***
689 * Tests the clone() method when no layout object exists yet.
690 */
691 public void testCloneNullLayout()
692 {
693 conf = new PropertiesConfiguration();
694 PropertiesConfiguration copy = (PropertiesConfiguration) conf.clone();
695 assertNotSame("Layout objects are the same", conf.getLayout(), copy
696 .getLayout());
697 }
698
699 /***
700 * A dummy layout implementation for checking whether certain methods are
701 * correctly called by the configuration.
702 */
703 static class DummyLayout extends PropertiesConfigurationLayout
704 {
705 /*** Stores the number how often load() was called. */
706 public int loadCalls;
707
708 public DummyLayout(PropertiesConfiguration config)
709 {
710 super(config);
711 }
712
713 public void load(Reader in) throws ConfigurationException
714 {
715 loadCalls++;
716 }
717 }
718 }