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