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