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.plist;
19  
20  import java.io.File;
21  import java.io.StringReader;
22  import java.util.Calendar;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Date;
26  import java.util.TimeZone;
27  
28  import junit.framework.TestCase;
29  import junitx.framework.ArrayAssert;
30  import junitx.framework.ListAssert;
31  import junitx.framework.ObjectAssert;
32  import org.apache.commons.configuration.Configuration;
33  import org.apache.commons.configuration.ConfigurationComparator;
34  import org.apache.commons.configuration.ConfigurationException;
35  import org.apache.commons.configuration.StrictConfigurationComparator;
36  
37  /***
38   * @author Emmanuel Bourg
39   * @version $Revision: 590474 $, $Date: 2007-10-30 22:35:11 +0100 (Di, 30 Okt 2007) $
40   */
41  public class TestPropertyListConfiguration extends TestCase
42  {
43      private PropertyListConfiguration config;
44  
45      private String testProperties = new File("conf/test.plist").getAbsolutePath();
46  
47      protected void setUp() throws Exception
48      {
49          config = new PropertyListConfiguration();
50          config.setFileName(testProperties);
51          config.load();
52      }
53  
54      public void testLoad()
55      {
56          assertFalse("the configuration is empty", config.isEmpty());
57      }
58  
59      public void testLoadWithError()
60      {
61          config = new PropertyListConfiguration();
62          try {
63              config.load(new StringReader(""));
64              fail("No exception thrown on loading an empty file");
65          } catch (ConfigurationException e) {
66              // expected
67              assertNotNull(e.getMessage());
68          }
69      }
70  
71      public void testString()
72      {
73          assertEquals("simple-string", "string1", config.getProperty("simple-string"));
74      }
75  
76      public void testQuotedString()
77      {
78          assertEquals("quoted-string", "string2", config.getProperty("quoted-string"));
79          assertEquals("quoted-string2", "this is a string", config.getProperty("quoted-string2"));
80          assertEquals("complex-string", "this is a \"complex\" string {(=,;)}", config.getProperty("complex-string"));
81      }
82  
83      public void testEmptyArray()
84      {
85          String key = "empty-array";
86          assertNotNull("array null", config.getProperty(key));
87  
88          List list = (List) config.getProperty(key);
89          assertTrue("array is not empty", list.isEmpty());
90      }
91  
92      public void testArray()
93      {
94          String key = "array";
95          assertNotNull("array null", config.getProperty(key));
96  
97          List list = (List) config.getProperty(key);
98          assertFalse("array is empty", list.isEmpty());
99  
100         assertEquals("1st value", "value1", list.get(0));
101         assertEquals("2nd value", "value2", list.get(1));
102         assertEquals("3rd value", "value3", list.get(2));
103     }
104 
105     public void testNestedArrays()
106     {
107         String key = "nested-arrays";
108 
109         Object array = config.getProperty(key);
110 
111         // root array
112         assertNotNull("array not found", array);
113         ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array);
114         List list = config.getList(key);
115 
116         assertFalse("empty array", list.isEmpty());
117         assertEquals("size", 2, list.size());
118 
119         // 1st array
120         ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(0));
121         List list1 = (List) list.get(0);
122         assertFalse("nested array 1 is empty", list1.isEmpty());
123         assertEquals("size", 2, list1.size());
124         assertEquals("1st element", "a", list1.get(0));
125         assertEquals("2nd element", "b", list1.get(1));
126 
127         // 2nd array
128         ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(1));
129         List list2 = (List) list.get(1);
130         assertFalse("nested array 2 is empty", list2.isEmpty());
131         assertEquals("size", 2, list2.size());
132         assertEquals("1st element", "c", list2.get(0));
133         assertEquals("2nd element", "d", list2.get(1));
134     }
135 
136     public void testDictionary()
137     {
138         assertEquals("1st element in dictionary", "bar1", config.getProperty("dictionary.foo1"));
139         assertEquals("2nd element in dictionary", "bar2", config.getProperty("dictionary.foo2"));
140     }
141 
142     public void testDictionaryArray()
143     {
144         String key = "dictionary-array";
145 
146         Object array = config.getProperty(key);
147 
148         // root array
149         assertNotNull("array not found", array);
150         ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array);
151         List list = config.getList(key);
152 
153         assertFalse("empty array", list.isEmpty());
154         assertEquals("size", 2, list.size());
155 
156         // 1st dictionary
157         ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(0));
158         Configuration conf1 = (Configuration) list.get(0);
159         assertFalse("configuration 1 is empty", conf1.isEmpty());
160         assertEquals("configuration element", "bar", conf1.getProperty("foo"));
161 
162         // 2nd dictionary
163         ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(1));
164         Configuration conf2 = (Configuration) list.get(1);
165         assertFalse("configuration 2 is empty", conf2.isEmpty());
166         assertEquals("configuration element", "value", conf2.getProperty("key"));
167     }
168 
169     public void testNestedDictionaries()
170     {
171         assertEquals("nested property", "value", config.getString("nested-dictionaries.foo.bar.key"));
172     }
173 
174     public void testData()
175     {
176         ObjectAssert.assertInstanceOf("data", (new byte[0]).getClass(), config.getProperty("data"));
177         ArrayAssert.assertEquals("data", "foo bar".getBytes(), (byte[]) config.getProperty("data"));
178     }
179 
180     public void testDate() throws Exception
181     {
182         Calendar cal = Calendar.getInstance();
183         cal.clear();
184         cal.set(2002, 2, 22, 11, 30, 0);
185         cal.setTimeZone(TimeZone.getTimeZone("GMT+0100"));
186         Date date = cal.getTime();
187 
188         assertEquals("date", date, config.getProperty("date"));
189     }
190 
191     public void testSave() throws Exception
192     {
193         File savedFile = new File("target/testsave.plist");
194 
195         // remove the file previously saved if necessary
196         if (savedFile.exists())
197         {
198             assertTrue(savedFile.delete());
199         }
200 
201         // save the configuration
202         String filename = savedFile.getAbsolutePath();
203         config.save(filename);
204 
205         assertTrue("The saved file doesn't exist", savedFile.exists());
206 
207         // read the configuration and compare the properties
208         Configuration checkConfig = new PropertyListConfiguration(new File(filename));
209 
210         Iterator it = config.getKeys();
211         while (it.hasNext())
212         {
213             String key = (String) it.next();
214             assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key));
215 
216             Object value = checkConfig.getProperty(key);
217             if (value instanceof byte[])
218             {
219                 byte[] array = (byte[]) value;
220                 ArrayAssert.assertEquals("Value of the '" + key + "' property", (byte[]) config.getProperty(key), array);
221             }
222             else if (value instanceof List)
223             {
224                 List list1 = (List) config.getProperty(key);
225                 List list2 = (List) value;
226 
227                 assertEquals("The size of the list for the key '" + key + "' doesn't match", list1.size(), list2.size());
228 
229                 for (int i = 0; i < list2.size(); i++)
230                 {
231                     Object value1 = list1.get(i);
232                     Object value2 = list2.get(i);
233 
234                     if (value1 instanceof Configuration)
235                     {
236                         ConfigurationComparator comparator = new StrictConfigurationComparator();
237                         assertTrue("The dictionnary at index " + i + " for the key '" + key + "' doesn't match", comparator.compare((Configuration) value1, (Configuration) value2));
238                     }
239                     else
240                     {
241                         assertEquals("Element at index " + i + " for the key '" + key + "'", value1, value2);
242                     }
243                 }
244 
245                 ListAssert.assertEquals("Value of the '" + key + "' property", (List) config.getProperty(key), list1);
246             }
247             else
248             {
249                 assertEquals("Value of the '" + key + "' property", config.getProperty(key), checkConfig.getProperty(key));
250             }
251 
252         }
253     }
254 
255     public void testQuoteString()
256     {
257         assertEquals("null string", null, config.quoteString(null));
258         assertEquals("simple string", "abcd", config.quoteString("abcd"));
259         assertEquals("string with a space", "\"ab cd\"", config.quoteString("ab cd"));
260         assertEquals("string with a quote", "\"foo//\"bar\"", config.quoteString("foo\"bar"));
261         assertEquals("string with a special char", "\"foo;bar\"", config.quoteString("foo;bar"));
262     }
263 
264     /***
265      * Ensure that setProperty doesn't alter an array of byte
266      * since it's a first class type in plist file
267      */
268     public void testSetDataProperty() throws Exception
269     {
270         byte[] expected = new byte[]{1, 2, 3, 4};
271         PropertyListConfiguration config = new PropertyListConfiguration();
272         config.setProperty("foo", expected);
273         config.save("target/testdata.plist");
274 
275         PropertyListConfiguration config2 = new PropertyListConfiguration("target/testdata.plist");
276         Object array = config2.getProperty("foo");
277 
278         assertNotNull("data not found", array);
279         assertEquals("property type", byte[].class, array.getClass());
280         ArrayAssert.assertEquals(expected, (byte[]) array);
281     }
282 
283     /***
284      * Ensure that addProperty doesn't alter an array of byte
285      */
286     public void testAddDataProperty() throws Exception
287     {
288         byte[] expected = new byte[]{1, 2, 3, 4};
289         PropertyListConfiguration config = new PropertyListConfiguration();
290         config.addProperty("foo", expected);
291         config.save("target/testdata.plist");
292 
293         PropertyListConfiguration config2 = new PropertyListConfiguration("target/testdata.plist");
294         Object array = config2.getProperty("foo");
295 
296         assertNotNull("data not found", array);
297         assertEquals("property type", byte[].class, array.getClass());
298         ArrayAssert.assertEquals(expected, (byte[]) array);
299     }
300 
301     public void testInitCopy()
302     {
303     	PropertyListConfiguration copy = new PropertyListConfiguration(config);
304     	assertFalse("Nothing was copied", copy.isEmpty());
305     }
306 
307     /***
308      * Tests parsing a date with an invalid numeric value.
309      */
310     public void testParseDateNoNumber()
311     {
312         try
313         {
314             PropertyListConfiguration
315                     .parseDate("<*D2002-03-22 1c:30:00 +0100>");
316             fail("Could parse date with an invalid number!");
317         }
318         catch (ParseException pex)
319         {
320             // ok
321         }
322     }
323 
324     /***
325      * Tests parsing a date that is not long enough.
326      */
327     public void testParseDateTooShort()
328     {
329         try
330         {
331             PropertyListConfiguration.parseDate("<*D2002-03-22 11:3>");
332             fail("Could parse too short date!");
333         }
334         catch (ParseException pex)
335         {
336             // ok
337         }
338     }
339 
340     /***
341      * Tests parsing a date that contains an invalid separator character.
342      */
343     public void testParseDateInvalidChar()
344     {
345         try
346         {
347             PropertyListConfiguration
348                     .parseDate("<*D2002+03-22 11:30:00 +0100>");
349             fail("Could parse date with an invalid separator!");
350         }
351         catch (ParseException pex)
352         {
353             // ok
354         }
355     }
356 
357     /***
358      * Tries parsing a null date. This should cause an exception.n
359      */
360     public void testParseDateNull()
361     {
362         try
363         {
364             PropertyListConfiguration.parseDate(null);
365             fail("Could parse null date!");
366         }
367         catch (ParseException pex)
368         {
369             // ok
370         }
371     }
372 
373     /***
374      * Tests formatting a date.
375      */
376     public void testFormatDate()
377     {
378         Calendar cal = Calendar.getInstance();
379         cal.clear();
380         cal.set(2007, 9, 29, 23, 4, 30);
381         cal.setTimeZone(TimeZone.getTimeZone("GMT-0230"));
382         assertEquals("Wrong date literal (1)", "<*D2007-10-29 23:04:30 -0230>",
383                 PropertyListConfiguration.formatDate(cal));
384         cal.clear();
385         cal.set(2007, 9, 30, 22, 2, 15);
386         cal.setTimeZone(TimeZone.getTimeZone("GMT+1111"));
387         assertEquals("Wrong date literal (2)", "<*D2007-10-30 22:02:15 +1111>",
388                 PropertyListConfiguration.formatDate(cal));
389     }
390 }