1   package org.apache.commons.configuration;
2   
3   /*
4    * Copyright 2001-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.math.BigDecimal;
20  import java.math.BigInteger;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.NoSuchElementException;
24  import java.util.Properties;
25  import java.util.Vector;
26  
27  import junit.framework.TestCase;
28  import junitx.framework.ObjectAssert;
29  
30  /***
31   * Tests some basic functions of the BaseConfiguration class. Missing keys will
32   * throw Exceptions
33   *
34   * @version $Id: TestBaseConfiguration.java,v 1.15 2004/09/19 22:01:50 henning Exp $
35   */
36  public class TestBaseConfiguration extends TestCase
37  {
38          protected BaseConfiguration config = null;
39  
40  	protected static Class missingElementException = NoSuchElementException.class;
41  	protected static Class incompatibleElementException = ConversionException.class;
42  
43          protected void setUp()
44              throws Exception
45          {
46              config = new BaseConfiguration();
47              config.setThrowExceptionOnMissing(true);
48          }
49  
50          public void testThrowExceptionOnMissing()
51          {
52              assertTrue("Throw Exception Property is not set!", config.isThrowExceptionOnMissing());
53          }
54  
55  	public void testGetProperty()
56  	{
57  		/* should be empty and return null */
58  		assertEquals("This returns null", config.getProperty("foo"), null);
59  
60  		/* add a real value, and get it two different ways */
61  		config.setProperty("number", "1");
62  		assertEquals("This returns '1'", config.getProperty("number"), "1");
63  		assertEquals("This returns '1'", config.getString("number"), "1");
64  	}
65  
66  	public void testGetByte()
67  	{
68  		config.setProperty("number", "1");
69  		byte oneB = 1;
70  		byte twoB = 2;
71  		assertEquals("This returns 1(byte)", oneB, config.getByte("number"));
72  		assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB));
73  		assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB));
74  		assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2")));
75  
76  		// missing key without default value
77  		Throwable t = null;
78  		try {
79  			config.getByte("numberNotInConfig");
80  		} catch (Throwable T) {
81  			t = T;
82  		}
83  		assertNotNull("No exception thrown for missing keys", t);
84  		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
85  
86  		// existing key with an incompatible value
87  		config.setProperty("test.empty", "");
88  		t = null;
89  		try {
90  			config.getByte("test.empty");
91  		} catch (Throwable T) {
92  			t = T;
93  		}
94  		assertNotNull("No exception thrown for incompatible values", t);
95  		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
96  	}
97  
98  	public void testGetShort()
99  	{
100 		config.setProperty("numberS", "1");
101 		short oneS = 1;
102 		short twoS = 2;
103 		assertEquals("This returns 1(short)", oneS, config.getShort("numberS"));
104 		assertEquals("This returns 1(short)", oneS, config.getShort("numberS", twoS));
105 		assertEquals("This returns 2(default short)", twoS, config.getShort("numberNotInConfig", twoS));
106 		assertEquals("This returns 1(Short)", new Short(oneS), config.getShort("numberS", new Short("2")));
107 
108 		// missing key without default value
109 		Throwable t = null;
110 		try {
111 			config.getShort("numberNotInConfig");
112 		} catch (Throwable T) {
113 			t = T;
114 		}
115 		assertNotNull("No exception thrown for missing keys", t);
116 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
117 
118 		// existing key with an incompatible value
119 		config.setProperty("test.empty", "");
120 		t = null;
121 		try {
122 			config.getShort("test.empty");
123 		} catch (Throwable T) {
124 			t = T;
125 		}
126 		assertNotNull("No exception thrown for incompatible values", t);
127 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
128 	}
129 
130 	public void testGetLong()
131 	{
132 		config.setProperty("numberL", "1");
133 		long oneL = 1;
134 		long twoL = 2;
135 		assertEquals("This returns 1(long)", oneL, config.getLong("numberL"));
136 		assertEquals("This returns 1(long)", oneL, config.getLong("numberL", twoL));
137 		assertEquals("This returns 2(default long)", twoL, config.getLong("numberNotInConfig", twoL));
138 		assertEquals("This returns 1(Long)", new Long(oneL), config.getLong("numberL", new Long("2")));
139 
140 		// missing key without default value
141 		Throwable t = null;
142 		try {
143 			config.getLong("numberNotInConfig");
144 		} catch (Throwable T) {
145 			t = T;
146 		}
147 		assertNotNull("No exception thrown for missing keys", t);
148 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
149 
150 		// existing key with an incompatible value
151 		config.setProperty("test.empty", "");
152 		t = null;
153 		try {
154 			config.getLong("test.empty");
155 		} catch (Throwable T) {
156 			t = T;
157 		}
158 		assertNotNull("No exception thrown for incompatible values", t);
159 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
160 	}
161 
162 	public void testGetFloat()
163 	{
164 		config.setProperty("numberF", "1.0");
165 		float oneF = 1;
166 		float twoF = 2;
167 		assertEquals("This returns 1(float)", oneF, config.getFloat("numberF"), 0);
168 		assertEquals("This returns 1(float)", oneF, config.getFloat("numberF", twoF), 0);
169 		assertEquals("This returns 2(default float)", twoF, config.getFloat("numberNotInConfig", twoF), 0);
170 		assertEquals("This returns 1(Float)", new Float(oneF), config.getFloat("numberF", new Float("2")));
171 
172 		// missing key without default value
173 		Throwable t = null;
174 		try {
175 			config.getFloat("numberNotInConfig");
176 		} catch (Throwable T) {
177 			t = T;
178 		}
179 		assertNotNull("No exception thrown for missing keys", t);
180 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
181 
182 		// existing key with an incompatible value
183 		config.setProperty("test.empty", "");
184 		t = null;
185 		try {
186 			config.getFloat("test.empty");
187 		} catch (Throwable T) {
188 			t = T;
189 		}
190 		assertNotNull("No exception thrown for incompatible values", t);
191 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
192 	}
193 
194 	public void testGetDouble()
195 	{
196 		config.setProperty("numberD", "1.0");
197 		double oneD = 1;
198 		double twoD = 2;
199 		assertEquals("This returns 1(double)", oneD, config.getDouble("numberD"), 0);
200 		assertEquals("This returns 1(double)", oneD, config.getDouble("numberD", twoD), 0);
201 		assertEquals("This returns 2(default double)", twoD, config.getDouble("numberNotInConfig", twoD), 0);
202 		assertEquals("This returns 1(Double)", new Double(oneD), config.getDouble("numberD", new Double("2")));
203 
204 		// missing key without default value
205 		Throwable t = null;
206 		try {
207 			config.getDouble("numberNotInConfig");
208 		} catch (Throwable T) {
209 			t = T;
210 		}
211 		assertNotNull("No exception thrown for missing keys", t);
212 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
213 
214 		// existing key with an incompatible value
215 		config.setProperty("test.empty", "");
216 		t = null;
217 		try {
218 			config.getDouble("test.empty");
219 		} catch (Throwable T) {
220 			t = T;
221 		}
222 		assertNotNull("No exception thrown for incompatible values", t);
223 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
224 	}
225 
226 	public void testGetBigDecimal()
227 	{
228 		config.setProperty("numberBigD", "123.456");
229 		BigDecimal number = new BigDecimal("123.456");
230 		BigDecimal defaultValue = new BigDecimal("654.321");
231 
232 		assertEquals("Existing key", number, config.getBigDecimal("numberBigD"));
233 		assertEquals("Existing key with default value", number, config.getBigDecimal("numberBigD", defaultValue));
234 		assertEquals("Missing key with default value", defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue));
235 
236 		// missing key without default value
237 		Throwable t = null;
238 		try {
239 			config.getBigDecimal("numberNotInConfig");
240 		} catch (Throwable T) {
241 			t = T;
242 		}
243 		assertNotNull("No exception thrown for missing keys", t);
244 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
245 
246 		// existing key with an incompatible value
247 		config.setProperty("test.empty", "");
248 		t = null;
249 		try {
250 			config.getBigDecimal("test.empty");
251 		} catch (Throwable T) {
252 			t = T;
253 		}
254 		assertNotNull("No exception thrown for incompatible values", t);
255 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
256 	}
257 
258 	public void testGetBigInteger()
259 	{
260 		config.setProperty("numberBigI", "1234567890");
261 		BigInteger number = new BigInteger("1234567890");
262 		BigInteger defaultValue = new BigInteger("654321");
263 
264 		assertEquals("Existing key", number, config.getBigInteger("numberBigI"));
265 		assertEquals("Existing key with default value", number, config.getBigInteger("numberBigI", defaultValue));
266 		assertEquals("Missing key with default value", defaultValue, config.getBigInteger("numberNotInConfig", defaultValue));
267 
268 		// missing key without default value
269 		Throwable t = null;
270 		try {
271 			config.getBigInteger("numberNotInConfig");
272 		} catch (Throwable T) {
273 			t = T;
274 		}
275 		assertNotNull("No exception thrown for missing keys", t);
276 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
277 
278 		// existing key with an incompatible value
279 		config.setProperty("test.empty", "");
280 		t = null;
281 		try {
282 			config.getBigInteger("test.empty");
283 		} catch (Throwable T) {
284 			t = T;
285 		}
286 		assertNotNull("No exception thrown for incompatible values", t);
287 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
288 	}
289 
290 	public void testGetString()
291 	{
292 		config.setProperty("testString", "The quick brown fox");
293 		String string = new String("The quick brown fox");
294 		String defaultValue = new String("jumps over the lazy dog");
295 
296 		assertEquals("Existing key", string, config.getString("testString"));
297 		assertEquals("Existing key with default value", string, config.getString("testString", defaultValue));
298 		assertEquals("Missing key with default value", defaultValue, config.getString("stringNotInConfig", defaultValue));
299 
300 		// missing key without default value
301 		Throwable t = null;
302 		try {
303 			config.getString("stringNotInConfig");
304 		} catch (Throwable T) {
305 			t = T;
306 		}
307 		assertNotNull("No exception thrown for missing keys", t);
308 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
309 	}
310 
311 	public void testGetBoolean()
312 	{
313 		config.setProperty("boolA", Boolean.TRUE);
314 		boolean boolT = true, boolF = false;
315 		assertEquals("This returns true", boolT, config.getBoolean("boolA"));
316 		assertEquals("This returns true, not the default", boolT, config.getBoolean("boolA", boolF));
317 		assertEquals("This returns false(default)", boolF, config.getBoolean("boolNotInConfig", boolF));
318 		assertEquals("This returns true(Boolean)", new Boolean(boolT), config.getBoolean("boolA", new Boolean(boolF)));
319 
320 		// missing key without default value
321 		Throwable t = null;
322 		try {
323 			config.getBoolean("numberNotInConfig");
324 		} catch (Throwable T) {
325 			t = T;
326 		}
327 		assertNotNull("No exception thrown for missing keys", t);
328 		ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
329 
330 		// existing key with an incompatible value
331 		config.setProperty("test.empty", "");
332 		t = null;
333 		try {
334 			config.getBoolean("test.empty");
335 		} catch (Throwable T) {
336 			t = T;
337 		}
338 		assertNotNull("No exception thrown for incompatible values", t);
339 		ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
340 	}
341 
342 	public void testGetList()
343 	{
344 		config.addProperty("number", "1");
345 		config.addProperty("number", "2");
346 		List list = config.getList("number");
347 		assertNotNull("The list is null", list);
348 		assertEquals("List size", 2, list.size());
349 		assertTrue("The number 1 is missing from the list", list.contains("1"));
350 		assertTrue("The number 2 is missing from the list", list.contains("2"));
351 
352 		/*
353 		 *  now test dan's new fix where we get the first scalar
354 		 *  when we access a list valued property
355 		 */
356 		try
357 		{
358 			config.getString("number");
359 		}
360 		catch (NoSuchElementException nsse)
361 		{
362 			fail("Should return a string");
363 		}
364 	}
365 
366 	public void testGetVector()
367 	{
368 		config.addProperty("number", "1");
369 		config.addProperty("number", "2");
370 		Vector vector = config.getVector("number");
371 		assertNotNull("The vector is null", vector);
372 		assertEquals("Vector size", 2, vector.size());
373 		assertTrue("The number 1 is missing from the vector", vector.contains("1"));
374 		assertTrue("The number 2 is missing from the vector", vector.contains("2"));
375 
376 		/*
377 		 *  now test dan's new fix where we get the first scalar
378 		 *  when we access a vector valued property
379 		 */
380 		try
381 		{
382 			config.getString("number");
383 		}
384 		catch (NoSuchElementException nsse)
385 		{
386 			fail("Should return a string");
387 		}
388 	}
389 
390 	public void testCommaSeparatedString()
391 	{
392 		String prop = "hey, that's a test";
393 		config.setProperty("prop.string", prop);
394 		try
395 		{
396 			config.getList("prop.string");
397 		}
398 		catch (NoSuchElementException nsse)
399 		{
400 			fail("Should return a list");
401 		}
402 
403 		String prop2 = "hey//, that's a test";
404 		config.clearProperty("prop.string");
405 		config.setProperty("prop.string", prop2);
406 		try
407 		{
408 			config.getString("prop.string");
409 		}
410 		catch (NoSuchElementException nsse)
411 		{
412 			fail("Should return a list");
413 		}
414 
415 	}
416 
417 	public void testPropertyAccess()
418 	{
419 		config.clearProperty("prop.properties");
420 		config.setProperty("prop.properties", "");
421 		assertEquals(
422 			"This returns an empty Properties object",
423 			config.getProperties("prop.properties"),
424 			new Properties());
425 		config.clearProperty("prop.properties");
426 		config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber");
427 
428 		Properties p = new Properties();
429 		p.setProperty("foo", "bar");
430 		p.setProperty("baz", "moo");
431 		p.setProperty("seal", "clubber");
432 		assertEquals(
433 			"This returns a filled in Properties object",
434 			config.getProperties("prop.properties"),
435 			p);
436 	}
437 
438 	public void testSubset()
439 	{
440 		/*
441 		 * test subset : assure we don't reprocess the data elements
442 		 * when generating the subset
443 		 */
444 
445 		String prop = "hey, that's a test";
446 		String prop2 = "hey//, that's a test";
447 		config.setProperty("prop.string", prop2);
448 		config.setProperty("property.string", "hello");
449 
450 		Configuration subEprop = config.subset("prop");
451 
452 		assertEquals(
453 			"Returns the full string",
454 			prop,
455 			subEprop.getString("string"));
456 		try
457 		{
458 			subEprop.getString("string");
459 		}
460 		catch (NoSuchElementException nsse)
461 		{
462 			fail("Should return a string");
463 		}
464 		try
465 		{
466 			subEprop.getList("string");
467 		}
468 		catch (NoSuchElementException nsse)
469 		{
470 			fail("Should return a list");
471 		}
472 
473 		Iterator it = subEprop.getKeys();
474 		it.next();
475 		assertFalse(it.hasNext());
476 
477 		subEprop = config.subset("prop.");
478 		it = subEprop.getKeys();
479 		assertFalse(it.hasNext());
480 	}
481 
482 	public void testInterpolation() throws Exception
483 	{
484 		config.setProperty("applicationRoot", "/home/applicationRoot");
485 		config.setProperty("db", "${applicationRoot}/db/hypersonic");
486 		String unInterpolatedValue = "${applicationRoot2}/db/hypersonic";
487 		config.setProperty("dbFailedInterpolate", unInterpolatedValue);
488 		String dbProp = "/home/applicationRoot/db/hypersonic";
489 
490 		//construct a new config, using config as the defaults config for it.
491 		BaseConfiguration superProp = config;
492 
493 		assertEquals(
494 			"Checking interpolated variable",dbProp,
495 			superProp.getString("db"));
496 		assertEquals(
497 			"lookup fails, leave variable as is",
498 			superProp.getString("dbFailedInterpolate"),
499 			unInterpolatedValue);
500 
501 		superProp.setProperty("arrayInt", "${applicationRoot}/1");
502 		String[] arrayInt = superProp.getStringArray("arrayInt");
503 		assertEquals(
504 			"check first entry was interpolated",
505 			"/home/applicationRoot/1",
506 			arrayInt[0]);
507 	}
508 
509 	public void testMultipleInterpolation() throws Exception
510 	{
511 		config.setProperty("test.base-level", "/base-level");
512 		config.setProperty("test.first-level", "${test.base-level}/first-level");
513 		config.setProperty(
514 			"test.second-level",
515 			"${test.first-level}/second-level");
516 		config.setProperty(
517 			"test.third-level",
518 			"${test.second-level}/third-level");
519 
520 		String expectedValue =
521 			"/base-level/first-level/second-level/third-level";
522 
523 		assertEquals(config.getString("test.third-level"), expectedValue);
524 	}
525 
526 	public void testInterpolationLoop() throws Exception
527 	{
528 		config.setProperty("test.a", "${test.b}");
529 		config.setProperty("test.b", "${test.a}");
530 
531 		try
532 		{
533 			config.getString("test.a");
534 		}
535 		catch (IllegalStateException e)
536 		{
537 			return;
538 		}
539 
540 		fail("IllegalStateException should have been thrown for looped property references");
541 	}
542 
543     public void testSplit()
544     {
545         String s1 = "abc,xyz";
546         List tokens = config.split(s1);
547         assertEquals("number of tokens in '" + s1 + "'", 2, tokens.size());
548         assertEquals("1st token for '" + s1 + "'", "abc", tokens.get(0));
549         assertEquals("2nd token for '" + s1 + "'", "xyz", tokens.get(1));
550 
551         String s2 = "abc//,xyz";
552         tokens = config.split(s2);
553         assertEquals("number of tokens in '" + s2 + "'", 1, tokens.size());
554         assertEquals("1st token for '" + s2 + "'", "abc,xyz", tokens.get(0));
555     }
556 
557 }
558