001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.configuration.plist;
019    
020    import static org.junit.Assert.assertEquals;
021    import static org.junit.Assert.assertFalse;
022    import static org.junit.Assert.assertNotNull;
023    import static org.junit.Assert.assertTrue;
024    
025    import java.io.File;
026    import java.util.Calendar;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.TimeZone;
030    
031    import junitx.framework.ArrayAssert;
032    import junitx.framework.ListAssert;
033    import junitx.framework.ObjectAssert;
034    
035    import org.apache.commons.configuration.Configuration;
036    import org.apache.commons.configuration.ConfigurationAssert;
037    import org.apache.commons.configuration.ConfigurationComparator;
038    import org.apache.commons.configuration.ConfigurationException;
039    import org.apache.commons.configuration.FileConfiguration;
040    import org.apache.commons.configuration.HierarchicalConfiguration;
041    import org.apache.commons.configuration.StrictConfigurationComparator;
042    import org.junit.Before;
043    import org.junit.Test;
044    
045    /**
046     * @author Emmanuel Bourg
047     * @version $Id: TestXMLPropertyListConfiguration.java 1367253 2012-07-30 19:59:36Z oheger $
048     */
049    public class TestXMLPropertyListConfiguration
050    {
051        private FileConfiguration config;
052    
053        @Before
054        public void setUp() throws Exception
055        {
056            config = new XMLPropertyListConfiguration();
057            config.setFile(ConfigurationAssert.getTestFile("test.plist.xml"));
058            config.load();
059        }
060    
061        @Test
062        public void testString() throws Exception
063        {
064            assertEquals("'string' property", "value1", config.getString("string"));
065        }
066    
067        @Test
068        public void testInteger() throws Exception
069        {
070            assertEquals("'integer' property", 12345678900L, config.getLong("integer"));
071        }
072    
073        @Test
074        public void testReal() throws Exception
075        {
076            assertEquals("'real' property", -12.345, config.getDouble("real"), 0);
077        }
078    
079        @Test
080        public void testBoolean() throws Exception
081        {
082            assertEquals("'boolean1' property", true, config.getBoolean("boolean1"));
083            assertEquals("'boolean2' property", false, config.getBoolean("boolean2"));
084        }
085    
086        @Test
087        public void testDictionary()
088        {
089            assertEquals("1st element", "value1", config.getProperty("dictionary.key1"));
090            assertEquals("2nd element", "value2", config.getProperty("dictionary.key2"));
091            assertEquals("3rd element", "value3", config.getProperty("dictionary.key3"));
092        }
093    
094        @Test
095        public void testDate() throws Exception
096        {
097            Calendar calendar = Calendar.getInstance();
098            calendar.clear();
099            calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
100            calendar.set(2005, Calendar.JANUARY, 1, 12, 0, 0);
101    
102            assertEquals("'date' property", calendar.getTime(), config.getProperty("date"));
103    
104            calendar.setTimeZone(TimeZone.getTimeZone("CET"));
105            calendar.set(2002, Calendar.MARCH, 22, 11, 30, 0);
106    
107            assertEquals("'date-gnustep' property", calendar.getTime(), config.getProperty("date-gnustep"));
108        }
109    
110        @Test
111        public void testSubset()
112        {
113            Configuration subset = config.subset("dictionary");
114            Iterator<String> keys = subset.getKeys();
115    
116            String key = keys.next();
117            assertEquals("1st key", "key1", key);
118            assertEquals("1st value", "value1", subset.getString(key));
119    
120            key = keys.next();
121            assertEquals("2nd key", "key2", key);
122            assertEquals("2nd value", "value2", subset.getString(key));
123    
124            key = keys.next();
125            assertEquals("3rd key", "key3", key);
126            assertEquals("3rd value", "value3", subset.getString(key));
127    
128            assertFalse("more than 3 properties founds", keys.hasNext());
129        }
130    
131        @Test
132        public void testArray()
133        {
134            Object array = config.getProperty("array");
135    
136            assertNotNull("array not found", array);
137            ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array);
138            List<?> list = config.getList("array");
139    
140            assertFalse("empty array", list.isEmpty());
141            assertEquals("size", 3, list.size());
142            assertEquals("1st element", "value1", list.get(0));
143            assertEquals("2nd element", "value2", list.get(1));
144            assertEquals("3rd element", "value3", list.get(2));
145        }
146    
147        @Test
148        public void testNestedArray()
149        {
150            String key = "nested-array";
151    
152            Object array = config.getProperty(key);
153    
154            // root array
155            assertNotNull("array not found", array);
156            ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array);
157            List<?> list = config.getList(key);
158    
159            assertFalse("empty array", list.isEmpty());
160            assertEquals("size", 2, list.size());
161    
162            // 1st array
163            ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(0));
164            List<?> list1 = (List<?>) list.get(0);
165            assertFalse("nested array 1 is empty", list1.isEmpty());
166            assertEquals("size", 2, list1.size());
167            assertEquals("1st element", "a", list1.get(0));
168            assertEquals("2nd element", "b", list1.get(1));
169    
170            // 2nd array
171            ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(1));
172            List<?> list2 = (List<?>) list.get(1);
173            assertFalse("nested array 2 is empty", list2.isEmpty());
174            assertEquals("size", 2, list2.size());
175            assertEquals("1st element", "c", list2.get(0));
176            assertEquals("2nd element", "d", list2.get(1));
177        }
178    
179        @Test
180        public void testDictionaryArray()
181        {
182            String key = "dictionary-array";
183    
184            Object array = config.getProperty(key);
185    
186            // root array
187            assertNotNull("array not found", array);
188            ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array);
189            List<?> list = config.getList(key);
190    
191            assertFalse("empty array", list.isEmpty());
192            assertEquals("size", 2, list.size());
193    
194            // 1st dictionary
195            ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(0));
196            Configuration conf1 = (Configuration) list.get(0);
197            assertFalse("configuration 1 is empty", conf1.isEmpty());
198            assertEquals("configuration element", "bar", conf1.getProperty("foo"));
199    
200            // 2nd dictionary
201            ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(1));
202            Configuration conf2 = (Configuration) list.get(1);
203            assertFalse("configuration 2 is empty", conf2.isEmpty());
204            assertEquals("configuration element", "value", conf2.getProperty("key"));
205        }
206    
207        @Test
208        public void testNested()
209        {
210            assertEquals("nested property", "value", config.getString("nested.node1.node2.node3"));
211        }
212    
213        @Test
214        public void testSave() throws Exception
215        {
216            File savedFile = new File("target/testsave.plist.xml");
217    
218            // remove the file previously saved if necessary
219            if (savedFile.exists())
220            {
221                assertTrue(savedFile.delete());
222            }
223    
224            // add an array of strings to the configuration
225            /*
226            config.addProperty("string", "value1");
227            List list = new ArrayList();
228            for (int i = 1; i < 5; i++)
229            {
230                list.add("value" + i);
231            }
232            config.addProperty("newarray", list);*/
233            // todo : investigate why the array structure of 'newarray' is lost in the saved file
234    
235            // add a map of strings
236            /*
237            Map map = new HashMap();
238            map.put("foo", "bar");
239            map.put("int", new Integer(123));
240            config.addProperty("newmap", map);
241            */
242            // todo : a Map added to a HierarchicalConfiguration should be decomposed as list of nodes
243    
244            // save the configuration
245            String filename = savedFile.getAbsolutePath();
246            config.save(filename);
247    
248            assertTrue("The saved file doesn't exist", savedFile.exists());
249    
250            // read the configuration and compare the properties
251            Configuration checkConfig = new XMLPropertyListConfiguration(new File(filename));
252    
253            Iterator<String> it = config.getKeys();
254            while (it.hasNext())
255            {
256                String key = it.next();
257                assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key));
258    
259                Object value = checkConfig.getProperty(key);
260                if (value instanceof byte[])
261                {
262                    byte[] array = (byte[]) value;
263                    ArrayAssert.assertEquals("Value of the '" + key + "' property", (byte[]) config.getProperty(key), array);
264                }
265                else if (value instanceof List)
266                {
267                    List<?> list1 = (List<?>) config.getProperty(key);
268                    List<?> list2 = (List<?>) value;
269    
270                    assertEquals("The size of the list for the key '" + key + "' doesn't match", list1.size(), list2.size());
271    
272                    for (int i = 0; i < list2.size(); i++)
273                    {
274                        Object value1 = list1.get(i);
275                        Object value2 = list2.get(i);
276    
277                        if (value1 instanceof Configuration)
278                        {
279                            ConfigurationComparator comparator = new StrictConfigurationComparator();
280                            assertTrue("The dictionnary at index " + i + " for the key '" + key + "' doesn't match", comparator.compare((Configuration) value1, (Configuration) value2));
281                        }
282                        else
283                        {
284                            assertEquals("Element at index " + i + " for the key '" + key + "'", value1, value2);
285                        }
286                    }
287    
288                    ListAssert.assertEquals("Value of the '" + key + "' property", (List<?>) config.getProperty(key), list1);
289                }
290                else
291                {
292                    assertEquals("Value of the '" + key + "' property", config.getProperty(key), checkConfig.getProperty(key));
293                }
294    
295            }
296        }
297    
298        @Test
299        public void testSaveEmptyDictionary() throws Exception
300        {
301            File savedFile = new File("target/testsave.plist.xml");
302    
303            // remove the file previously saved if necessary
304            if (savedFile.exists())
305            {
306                assertTrue(savedFile.delete());
307            }
308    
309            // save the configuration
310            String filename = savedFile.getAbsolutePath();
311            config.save(filename);
312    
313            assertTrue("The saved file doesn't exist", savedFile.exists());
314    
315            // read the configuration and compare the properties
316            Configuration checkConfig = new XMLPropertyListConfiguration(new File(filename));
317    
318            assertEquals(null, config.getProperty("empty-dictionary"));
319            assertEquals(null, checkConfig.getProperty("empty-dictionary"));
320        }
321    
322        /**
323         * Ensure that setProperty doesn't alter an array of byte
324         * since it's a first class type in plist file
325         */
326        @Test
327        public void testSetDataProperty() throws Exception
328        {
329            byte[] expected = new byte[]{1, 2, 3, 4};
330            XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
331            config.setProperty("foo", expected);
332            config.save("target/testdata.plist.xml");
333    
334            XMLPropertyListConfiguration config2 = new XMLPropertyListConfiguration("target/testdata.plist.xml");
335            Object array = config2.getProperty("foo");
336    
337            assertNotNull("data not found", array);
338            assertEquals("property type", byte[].class, array.getClass());
339            ArrayAssert.assertEquals(expected, (byte[]) array);
340        }
341    
342        /**
343         * Ensure that addProperty doesn't alter an array of byte
344         */
345        @Test
346        public void testAddDataProperty() throws Exception
347        {
348            byte[] expected = new byte[]{1, 2, 3, 4};
349            XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
350            config.addProperty("foo", expected);
351            config.save("target/testdata.plist.xml");
352    
353            XMLPropertyListConfiguration config2 = new XMLPropertyListConfiguration("target/testdata.plist.xml");
354            Object array = config2.getProperty("foo");
355    
356            assertNotNull("data not found", array);
357            assertEquals("property type", byte[].class, array.getClass());
358            ArrayAssert.assertEquals(expected, (byte[]) array);
359        }
360    
361        @Test
362        public void testInitCopy()
363        {
364            XMLPropertyListConfiguration copy = new XMLPropertyListConfiguration((HierarchicalConfiguration) config);
365            StrictConfigurationComparator comp = new StrictConfigurationComparator();
366            assertTrue("Configurations are not equal", comp.compare(config, copy));
367        }
368    
369        /**
370         * Tests whether a configuration can be loaded that does not start with a
371         * {@code dict} element. This test case is related to
372         * CONFIGURATION-405.
373         */
374        @Test
375        public void testLoadNoDict() throws ConfigurationException
376        {
377            XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration();
378            plist.setFile(ConfigurationAssert.getTestFile("test2.plist.xml"));
379            plist.load();
380            assertFalse("Configuration is empty", plist.isEmpty());
381        }
382    
383        /**
384         * Tests whether a configuration that does not start with a
385         * {@code dict} element can be loaded from a constructor. This test
386         * case is related to CONFIGURATION-405.
387         */
388        @Test
389        public void testLoadNoDictConstr() throws ConfigurationException
390        {
391            XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration(
392                    ConfigurationAssert.getTestFile("test2.plist.xml"));
393            assertFalse("Configuration is empty", plist.isEmpty());
394        }
395    
396        /**
397         * Tests a configuration file which contains an invalid date property value.
398         * This test is related to CONFIGURATION-501.
399         */
400        @Test
401        public void testSetDatePropertyInvalid() throws ConfigurationException
402        {
403            config.clear();
404            config.setFile(ConfigurationAssert.getTestFile("test_invalid_date.plist.xml"));
405            config.load();
406            assertEquals("'string' property", "value1", config.getString("string"));
407            assertFalse("Date property was loaded", config.containsKey("date"));
408        }
409    }