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.lang.reflect.Method;
21  import java.math.BigDecimal;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import org.apache.commons.lang.SystemUtils;
26  
27  import junit.framework.TestCase;
28  
29  /***
30   * Test class for PropertyConverter.
31   *
32   * @author Emmanuel Bourg
33   * @version $Revision: 662269 $, $Date: 2008-06-01 21:30:02 +0200 (So, 01 Jun 2008) $
34   */
35  public class TestPropertyConverter extends TestCase
36  {
37      public void testSplit()
38      {
39          String s = "abc, xyz , 123";
40          List list = PropertyConverter.split(s, ',');
41  
42          assertEquals("size", 3, list.size());
43          assertEquals("1st token for '" + s + "'", "abc", list.get(0));
44          assertEquals("2nd token for '" + s + "'", "xyz", list.get(1));
45          assertEquals("3rd token for '" + s + "'", "123", list.get(2));
46      }
47  
48      public void testSplitNoTrim()
49      {
50          String s = "abc, xyz , 123";
51          List list = PropertyConverter.split(s, ',', false);
52  
53          assertEquals("size", 3, list.size());
54          assertEquals("1st token for '" + s + "'", "abc", list.get(0));
55          assertEquals("2nd token for '" + s + "'", " xyz ", list.get(1));
56          assertEquals("3rd token for '" + s + "'", " 123", list.get(2));
57      }
58  
59      public void testSplitWithEscapedSeparator()
60      {
61          String s = "abc//,xyz, 123";
62          List list = PropertyConverter.split(s, ',');
63  
64          assertEquals("size", 2, list.size());
65          assertEquals("1st token for '" + s + "'", "abc,xyz", list.get(0));
66          assertEquals("2nd token for '" + s + "'", "123", list.get(1));
67      }
68  
69      public void testSplitEmptyValues()
70      {
71          String s = ",,";
72          List list = PropertyConverter.split(s, ',');
73  
74          assertEquals("size", 3, list.size());
75          assertEquals("1st token for '" + s + "'", "", list.get(0));
76          assertEquals("2nd token for '" + s + "'", "", list.get(1));
77          assertEquals("3rd token for '" + s + "'", "", list.get(2));
78      }
79  
80      public void testSplitWithEndingSlash()
81      {
82          String s = "abc, xyz//";
83          List list = PropertyConverter.split(s, ',');
84  
85          assertEquals("size", 2, list.size());
86          assertEquals("1st token for '" + s + "'", "abc", list.get(0));
87          assertEquals("2nd token for '" + s + "'", "xyz//", list.get(1));
88      }
89  
90      public void testSplitNull()
91      {
92          List list = PropertyConverter.split(null, ',');
93          assertNotNull(list);
94          assertTrue(list.isEmpty());
95      }
96  
97      /***
98       * Tests whether an escape character can be itself escaped.
99       */
100     public void testSplitEscapeEscapeChar()
101     {
102         List list = PropertyConverter.split("C://Temp////,xyz", ',');
103         assertEquals("Wrong list size", 2, list.size());
104         assertEquals("Wrong element 1", "C://Temp//", list.get(0));
105         assertEquals("Wrong element 2", "xyz", list.get(1));
106     }
107 
108     /***
109      * Tests whether delimiters are correctly escaped.
110      */
111     public void testEscapeDelimiters()
112     {
113         assertEquals("Wrong escaped delimiters",
114                 "C:////Temp//////,D:////Data////", PropertyConverter
115                         .escapeDelimiters("C://Temp//,D://Data//", ','));
116     }
117 
118     public void testToIterator()
119     {
120         int[] array = new int[]{1, 2, 3};
121 
122         Iterator it = PropertyConverter.toIterator(array, ',');
123 
124         assertEquals("1st element", new Integer(1), it.next());
125         assertEquals("2nd element", new Integer(2), it.next());
126         assertEquals("3rd element", new Integer(3), it.next());
127     }
128 
129     /***
130      * Tests the interpolation features.
131      */
132     public void testInterpolateString()
133     {
134         PropertiesConfiguration config = new PropertiesConfiguration();
135         config.addProperty("animal", "quick brown fox");
136         config.addProperty("target", "lazy dog");
137         assertEquals("Wrong interpolation",
138                 "The quick brown fox jumps over the lazy dog.",
139                 PropertyConverter.interpolate("The ${animal} jumps over the ${target}.", config));
140     }
141 
142     /***
143      * Tests interpolation of an object. Here nothing should be substituted.
144      */
145     public void testInterpolateObject()
146     {
147         assertEquals("Object was not correctly interpolated", new Integer(42),
148                 PropertyConverter.interpolate(new Integer(42), new PropertiesConfiguration()));
149     }
150 
151     /***
152      * Tests complex interpolation where the variables' values contain in turn
153      * other variables.
154      */
155     public void testInterpolateRecursive()
156     {
157         PropertiesConfiguration config = new PropertiesConfiguration();
158         config.addProperty("animal", "${animal_attr} fox");
159         config.addProperty("target", "${target_attr} dog");
160         config.addProperty("animal_attr", "quick brown");
161         config.addProperty("target_attr", "lazy");
162         assertEquals("Wrong complex interpolation",
163                 "The quick brown fox jumps over the lazy dog.",
164                 PropertyConverter.interpolate("The ${animal} jumps over the ${target}.", config));
165     }
166 
167     /***
168      * Tests an interpolation that leads to a cycle. This should throw an
169      * exception.
170      */
171     public void testCyclicInterpolation()
172     {
173         PropertiesConfiguration config = new PropertiesConfiguration();
174         config.addProperty("animal", "${animal_attr} ${species}");
175         config.addProperty("animal_attr", "quick brown");
176         config.addProperty("species", "${animal}");
177         try
178         {
179             PropertyConverter.interpolate("This is a ${animal}", config);
180             fail("Cyclic interpolation was not detected!");
181         }
182         catch (IllegalStateException iex)
183         {
184             // ok
185         }
186     }
187 
188     /***
189      * Tests interpolation if a variable is unknown. Then the variable won't be
190      * substituted.
191      */
192     public void testInterpolationUnknownVariable()
193     {
194         PropertiesConfiguration config = new PropertiesConfiguration();
195         config.addProperty("animal", "quick brown fox");
196         assertEquals("Wrong interpolation",
197                 "The quick brown fox jumps over ${target}.",
198                 PropertyConverter.interpolate("The ${animal} jumps over ${target}.", config));
199     }
200 
201     /***
202      * Tests conversion to numbers when the passed in objects are already
203      * numbers.
204      */
205     public void testToNumberDirect()
206     {
207         Integer i = new Integer(42);
208         assertSame("Wrong integer", i, PropertyConverter.toNumber(i, Integer.class));
209         BigDecimal d = new BigDecimal("3.1415");
210         assertSame("Wrong BigDecimal", d, PropertyConverter.toNumber(d, Integer.class));
211     }
212 
213     /***
214      * Tests conversion to numbers when the passed in objects have a compatible
215      * string representation.
216      */
217     public void testToNumberFromString()
218     {
219         assertEquals("Incorrect Integer value", new Integer(42), PropertyConverter.toNumber("42", Integer.class));
220         assertEquals("Incorrect Short value", new Short((short) 10), PropertyConverter.toNumber(new StringBuffer("10"), Short.class));
221     }
222 
223     /***
224      * Tests conversion to numbers when the passed in objects are strings with
225      * prefixes for special radices.
226      */
227     public void testToNumberFromHexString()
228     {
229         Number n = PropertyConverter.toNumber("0x10", Integer.class);
230         assertEquals("Incorrect Integer value", 16, n.intValue());
231     }
232 
233     /***
234      * Tests conversion to numbers when an invalid Hex value is passed in. This
235      * should cause an exception.
236      */
237     public void testToNumberFromInvalidHexString()
238     {
239         try
240         {
241             PropertyConverter.toNumber("0xNotAHexValue", Integer.class);
242             fail("Could convert invalid hex value!");
243         }
244         catch (ConversionException cex)
245         {
246             // ok
247         }
248     }
249 
250     /***
251      * Tests conversion to numbers when the passed in objects have no numeric
252      * String representation. This should cause an exception.
253      */
254     public void testToNumberFromInvalidString()
255     {
256         try
257         {
258             PropertyConverter.toNumber("Not a number", Byte.class);
259             fail("Could convert invalid String!");
260         }
261         catch (ConversionException cex)
262         {
263             // ok
264         }
265     }
266 
267     /***
268      * Tests conversion to numbers when the passed in target class is invalid.
269      * This should cause an exception.
270      */
271     public void testToNumberWithInvalidClass()
272     {
273         try
274         {
275             PropertyConverter.toNumber("42", Object.class);
276             fail("Could convert to invalid target class!");
277         }
278         catch (ConversionException cex)
279         {
280             //ok
281         }
282     }
283 
284     // enumeration type used for the tests, Java 5 only
285     private Class enumClass;
286     private Object enumObject;
287     {
288         if (SystemUtils.isJavaVersionAtLeast(1.5f))
289         {
290             try
291             {
292                 enumClass = Class.forName("java.lang.annotation.ElementType");
293 
294                 Method valueOfMethod = enumClass.getMethod("valueOf", new Class[] { String.class });
295                 enumObject = valueOfMethod.invoke(null, new Object[] { "METHOD" });
296             }
297             catch (Exception e)
298             {
299             }
300         }
301     }
302 
303     public void testToEnumFromEnum()
304     {
305         if (!SystemUtils.isJavaVersionAtLeast(1.5f))
306         {
307             return;
308         }
309 
310         assertEquals(enumObject, PropertyConverter.toEnum(enumObject, enumClass));
311     }
312 
313     public void testToEnumFromString()
314     {
315         if (!SystemUtils.isJavaVersionAtLeast(1.5f))
316         {
317             return;
318         }
319 
320         assertEquals(enumObject, PropertyConverter.toEnum("METHOD", enumClass));
321     }
322 
323     public void testToEnumFromInvalidString()
324     {
325         if (!SystemUtils.isJavaVersionAtLeast(1.5f))
326         {
327             return;
328         }
329 
330         try
331         {
332             assertEquals(enumObject, PropertyConverter.toEnum("FOO", enumClass));
333             fail("Could convert invalid String!");
334         }
335         catch (ConversionException e)
336         {
337             // expected
338         }
339     }
340 
341     public void testToEnumFromNumber()
342     {
343         if (!SystemUtils.isJavaVersionAtLeast(1.5f))
344         {
345             return;
346         }
347 
348         assertEquals(enumObject, PropertyConverter.toEnum(new Integer(2), enumClass));
349     }
350 
351     public void testToEnumFromInvalidNumber()
352     {
353         if (!SystemUtils.isJavaVersionAtLeast(1.5f))
354         {
355             return;
356         }
357         
358         try
359         {
360             assertEquals(enumObject, PropertyConverter.toEnum(new Integer(-1), enumClass));
361             fail("Could convert invalid number!");
362         }
363         catch (ConversionException e)
364         {
365             // expected
366         }
367     }
368 }