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.beanutils;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import junit.framework.AssertionFailedError;
24  import junit.framework.TestCase;
25  import junitx.framework.ObjectAssert;
26  import org.apache.commons.beanutils.DynaProperty;
27  import org.apache.commons.configuration.BaseConfiguration;
28  import org.apache.commons.configuration.Configuration;
29  
30  /***
31   * <p>Test Case for the <code>ConfigurationDynaBean</code> implementation class.
32   * These tests were based on the ones in <code>BasicDynaBeanTestCase</code>
33   * because the two classes provide similar levels of functionality.</p>
34   *
35   * @author <a href="mailto:ricardo.gladwell@btinternet.com">Ricardo Gladwell</a>
36   * @version $Revision: 447537 $
37   */
38  public class TestConfigurationDynaBean extends TestCase
39  {
40      /***
41       * The basic test bean for each test.
42       */
43      private ConfigurationDynaBean bean;
44  
45      /***
46       * The set of property names we expect to have returned when calling
47       * <code>getDynaProperties()</code>.  You should update this list
48       * when new properties are added to TestBean.
49       */
50      String[] properties = {
51              "booleanProperty",
52              "booleanSecond",
53              "doubleProperty",
54              "floatProperty",
55              "intProperty",
56              "longProperty",
57              "mappedProperty.key1",
58              "mappedProperty.key2",
59              "mappedProperty.key3",
60              "mappedIntProperty.key1",
61              "shortProperty",
62              "stringProperty",
63              "byteProperty",
64              "charProperty"
65      };
66  
67      Object[] values = {
68              Boolean.TRUE,
69              Boolean.TRUE,
70              new Double(Double.MAX_VALUE),
71              new Float(Float.MAX_VALUE),
72              new Integer(Integer.MAX_VALUE),
73              new Long(Long.MAX_VALUE),
74              "First Value",
75              "Second Value",
76              "Third Value",
77              new Integer(Integer.MAX_VALUE),
78              new Short(Short.MAX_VALUE),
79              "This is a string",
80              new Byte(Byte.MAX_VALUE),
81              new Character(Character.MAX_VALUE)
82      };
83  
84      int[] intArray = {0, 10, 20, 30, 40};
85      boolean[] booleanArray = {true, false, true, false, true};
86      char[] charArray = {'a', 'b', 'c', 'd', 'e'};
87      byte[] byteArray = {0, 10, 20, 30, 40};
88      long[] longArray = {0, 10, 20, 30, 40};
89      short[] shortArray = {0, 10, 20, 30, 40};
90      float[] floatArray = {0, 10, 20, 30, 40};
91      double[] doubleArray = {0.0, 10.0, 20.0, 30.0, 40.0};
92      String[] stringArray = {"String 0", "String 1", "String 2", "String 3", "String 4"};
93  
94  
95      /***
96       * Set up instance variables required by this test case.
97       */
98      public void setUp() throws Exception
99      {
100         Configuration configuration = createConfiguration();
101 
102         for (int i = 0; i < properties.length; i++)
103         {
104             configuration.setProperty(properties[i], values[i]);
105         }
106 
107         for (int a = 0; a < intArray.length; a++)
108         {
109             configuration.addProperty("intIndexed", new Integer(intArray[a]));
110         }
111 
112         for (int a = 0; a < stringArray.length; a++)
113         {
114             configuration.addProperty("stringIndexed", stringArray[a]);
115         }
116 
117         List list = new ArrayList();
118         for (int i = 0; i < stringArray.length; i++)
119         {
120             list.add(stringArray[i]);
121         }
122         configuration.addProperty("listIndexed", list);
123 
124         bean = new ConfigurationDynaBean(configuration);
125 
126         bean.set("listIndexed", list);
127         bean.set("intArray", intArray);
128         bean.set("booleanArray", booleanArray);
129         bean.set("charArray", charArray);
130         bean.set("longArray", longArray);
131         bean.set("shortArray", shortArray);
132         bean.set("floatArray", floatArray);
133         bean.set("doubleArray", doubleArray);
134         bean.set("byteArray", byteArray);
135         bean.set("stringArray", stringArray);
136     }
137 
138     /***
139      * Creates the underlying configuration object for the dyna bean.
140      * @return the underlying configuration object
141      */
142     protected Configuration createConfiguration()
143     {
144         return new BaseConfiguration();
145     }
146 
147     /***
148      * Corner cases on getDynaProperty invalid arguments.
149      */
150     public void testGetDescriptorArguments()
151     {
152         DynaProperty descriptor = bean.getDynaClass().getDynaProperty("unknown");
153         assertNull("Unknown property descriptor should be null", descriptor);
154 
155         try
156         {
157             bean.getDynaClass().getDynaProperty(null);
158             fail("Should throw IllegalArgumentException");
159         }
160         catch (java.lang.IllegalArgumentException e)
161         {
162             // Expected response
163         }
164         catch (AssertionFailedError e)
165         {
166             // ignore other failed responses
167         }
168         catch (Throwable t)
169         {
170             fail("Threw '" + t + "' instead of 'IllegalArgumentException'");
171         }
172     }
173 
174     /***
175      * Positive getDynaProperty on property <code>booleanProperty</code>.
176      */
177     public void testGetDescriptorBoolean()
178     {
179         testGetDescriptorBase("booleanProperty", Boolean.TYPE);
180     }
181 
182     /***
183      * Positive getDynaProperty on property <code>doubleProperty</code>.
184      */
185     public void testGetDescriptorDouble()
186     {
187         testGetDescriptorBase("doubleProperty", Double.TYPE);
188     }
189 
190     /***
191      * Positive getDynaProperty on property <code>floatProperty</code>.
192      */
193     public void testGetDescriptorFloat()
194     {
195         testGetDescriptorBase("floatProperty", Float.TYPE);
196     }
197 
198     /***
199      * Positive getDynaProperty on property <code>intProperty</code>.
200      */
201     public void testGetDescriptorInt()
202     {
203         testGetDescriptorBase("intProperty", Integer.TYPE);
204     }
205 
206     /***
207      * Positive getDynaProperty on property <code>longProperty</code>.
208      */
209     public void testGetDescriptorLong()
210     {
211         testGetDescriptorBase("longProperty", Long.TYPE);
212     }
213 
214     /***
215      * Positive getDynaProperty on property <code>booleanSecond</code>
216      * that uses an "is" method as the getter.
217      */
218     public void testGetDescriptorSecond()
219     {
220         testGetDescriptorBase("booleanSecond", Boolean.TYPE);
221     }
222 
223     /***
224      * Positive getDynaProperty on property <code>shortProperty</code>.
225      */
226     public void testGetDescriptorShort()
227     {
228         testGetDescriptorBase("shortProperty", Short.TYPE);
229     }
230 
231     /***
232      * Positive getDynaProperty on property <code>stringProperty</code>.
233      */
234     public void testGetDescriptorString()
235     {
236         testGetDescriptorBase("stringProperty", String.class);
237     }
238 
239     /***
240      * Positive test for getDynaPropertys().  Each property name
241      * listed in <code>properties</code> should be returned exactly once.
242      */
243     public void testGetDescriptors()
244     {
245         DynaProperty pd[] = bean.getDynaClass().getDynaProperties();
246         assertNotNull("Got descriptors", pd);
247         int count[] = new int[properties.length];
248         for (int i = 0; i < pd.length; i++)
249         {
250             String name = pd[i].getName();
251             for (int j = 0; j < properties.length; j++)
252             {
253                 if (name.equals(properties[j]))
254                 {
255                     count[j]++;
256                 }
257             }
258         }
259 
260         for (int j = 0; j < properties.length; j++)
261         {
262             if (count[j] < 0)
263             {
264                 fail("Missing property " + properties[j]);
265             }
266             else if (count[j] > 1)
267             {
268                 fail("Duplicate property " + properties[j]);
269             }
270         }
271     }
272 
273     /***
274      * Corner cases on getIndexedProperty invalid arguments.
275      */
276     public void testGetIndexedArguments()
277     {
278         try
279         {
280             bean.get("intArray", -1);
281         }
282         catch (IndexOutOfBoundsException e)
283         {
284             return; // Expected response
285         }
286         catch (Throwable t)
287         {
288             fail("Threw '" + t + "' instead of 'IndexOutOfBoundsException'");
289             return;
290         }
291 
292         fail("Should throw IndexOutOfBoundsException");
293     }
294 
295     /***
296      * Positive and negative tests on getIndexedProperty valid arguments.
297      */
298     public void testGetIndexedValues()
299     {
300         for (int i = 0; i < 5; i++)
301         {
302             Object value = bean.get("intArray", i);
303 
304             assertNotNull("intArray index " + i + " did not return value.", value);
305             ObjectAssert.assertInstanceOf("intArray index " + i, Integer.class, value);
306             assertEquals("intArray " + i + " returned incorrect value.", i * 10, ((Integer) value).intValue());
307 
308             value = bean.get("intIndexed", i);
309 
310             assertNotNull("intIndexed index " + i + "returned value " + i, value);
311             ObjectAssert.assertInstanceOf("intIndexed index " + i, Integer.class, value);
312             assertEquals("intIndexed index " + i + "returned correct " + i, i * 10, ((Integer) value).intValue());
313 
314             value = bean.get("listIndexed", i);
315 
316             assertNotNull("listIndexed index " + i + "returned value " + i, value);
317             ObjectAssert.assertInstanceOf("list index " + i, String.class, value);
318             assertEquals("listIndexed index " + i + "returned correct " + i, "String " + i, (String) value);
319 
320             value = bean.get("stringArray", i);
321 
322             assertNotNull("stringArray index " + i + " returnde null.", value);
323             assertFalse("stringArray index " + i + " returned array instead of String.", value.getClass().isArray());
324             ObjectAssert.assertInstanceOf("stringArray index " + i, String.class, value);
325             assertEquals("stringArray returned correct " + i, "String " + i, (String) value);
326 
327             value = bean.get("stringIndexed", i);
328 
329             assertNotNull("stringIndexed returned value " + i, value);
330             ObjectAssert.assertInstanceOf("stringIndexed", String.class, value);
331             assertEquals("stringIndexed returned correct " + i, "String " + i, (String) value);
332         }
333     }
334 
335     /***
336      * Corner cases on getMappedProperty invalid arguments.
337      */
338     public void testGetMappedArguments()
339     {
340         try
341         {
342             Object value = bean.get("mappedProperty", "unknown");
343             assertNull("Should not return a value", value);
344         }
345         catch (Throwable t)
346         {
347             fail("Threw " + t + " instead of returning null");
348         }
349     }
350 
351     /***
352      * Positive and negative tests on getMappedProperty valid arguments.
353      */
354     public void testGetMappedValues()
355     {
356         Object value = bean.get("mappedProperty", "key1");
357         assertEquals("Can find first value", "First Value", value);
358 
359         value = bean.get("mappedProperty", "key2");
360         assertEquals("Can find second value", "Second Value", value);
361 
362         value = bean.get("mappedProperty", "key3");
363         assertNotNull("Cannot find third value", value);
364     }
365 
366     /***
367      * Corner cases on getSimpleProperty invalid arguments.
368      */
369     public void testGetSimpleArguments()
370     {
371         try
372         {
373             bean.get("a non existing property");
374         }
375         catch (IllegalArgumentException e)
376         {
377             return; // Expected response
378         }
379         catch (Throwable t)
380         {
381             fail("Threw " + t + " instead of IllegalArgumentException");
382         }
383         fail("Should throw IllegalArgumentException");
384     }
385 
386     /***
387      * Test getSimpleProperty on a boolean property.
388      */
389     public void testGetSimpleBoolean()
390     {
391         Object value = bean.get("booleanProperty");
392         assertNotNull("Got a value", value);
393         ObjectAssert.assertInstanceOf("Got correct type", Boolean.class, value);
394         assertTrue("Got correct value", ((Boolean) value).booleanValue());
395     }
396 
397     /***
398      * Test getSimpleProperty on a double property.
399      */
400     public void testGetSimpleDouble()
401     {
402         Object value = bean.get("doubleProperty");
403         assertNotNull("Got a value", value);
404         ObjectAssert.assertInstanceOf("Got correct type", Double.class, value);
405         assertEquals("Got correct value", ((Double) value).doubleValue(), Double.MAX_VALUE, 0.005);
406     }
407 
408     /***
409      * Test getSimpleProperty on a float property.
410      */
411     public void testGetSimpleFloat()
412     {
413         Object value = bean.get("floatProperty");
414         assertNotNull("Got a value", value);
415         ObjectAssert.assertInstanceOf("Got correct type", Float.class, value);
416         assertEquals("Got correct value", ((Float) value).floatValue(), Float.MAX_VALUE, 0.005f);
417     }
418 
419     /***
420      * Test getSimpleProperty on a int property.
421      */
422     public void testGetSimpleInt()
423     {
424         Object value = bean.get("intProperty");
425         assertNotNull("Failed to get value", value);
426         ObjectAssert.assertInstanceOf("Incorrect type", Integer.class, value);
427         assertEquals("Incorrect value", ((Integer) value).intValue(), Integer.MAX_VALUE);
428     }
429 
430     /***
431      * Test getSimpleProperty on a long property.
432      */
433     public void testGetSimpleLong()
434     {
435         Object value = bean.get("longProperty");
436         assertNotNull("Got a value", value);
437         ObjectAssert.assertInstanceOf("Returned incorrect type", Long.class, value);
438         assertEquals("Returned value of Incorrect value", ((Long) value).longValue(), Long.MAX_VALUE);
439     }
440 
441     /***
442      * Test getSimpleProperty on a short property.
443      */
444     public void testGetSimpleShort()
445     {
446         Object value = bean.get("shortProperty");
447         assertNotNull("Got a value", value);
448         ObjectAssert.assertInstanceOf("Got correct type", Short.class, value);
449         assertEquals("Got correct value", ((Short) value).shortValue(), Short.MAX_VALUE);
450     }
451 
452     /***
453      * Test getSimpleProperty on a String property.
454      */
455     public void testGetSimpleString()
456     {
457         Object value = bean.get("stringProperty");
458         assertNotNull("Got a value", value);
459         ObjectAssert.assertInstanceOf("Got correct type", String.class, value);
460         assertEquals("Got correct value", (String) value, "This is a string");
461     }
462 
463     /***
464      * Test <code>contains()</code> method for mapped properties.
465      */
466     public void testMappedContains()
467     {
468         assertTrue("Can't see first key", bean.contains("mappedProperty", "key1"));
469         assertTrue("Can see unknown key", !bean.contains("mappedProperty", "Unknown Key"));
470     }
471 
472     /***
473      * Test <code>remove()</code> method for mapped properties.
474      */
475     public void testMappedRemove()
476     {
477         assertTrue("Can see first key", bean.contains("mappedProperty", "key1"));
478         bean.remove("mappedProperty", "key1");
479         assertTrue("Can not see first key", !bean.contains("mappedProperty", "key1"));
480 
481         assertTrue("Can not see unknown key", !bean.contains("mappedProperty", "key4"));
482         bean.remove("mappedProperty", "key4");
483         assertTrue("Can not see unknown key", !bean.contains("mappedProperty", "key4"));
484     }
485 
486     /***
487      * Corner cases on setIndexedProperty invalid arguments.
488      */
489     public void testSetIndexedArguments()
490     {
491         try
492         {
493             bean.set("intArray", -1, new Integer(0));
494         }
495         catch (IndexOutOfBoundsException e)
496         {
497             return; // Expected response
498         }
499         catch (Throwable t)
500         {
501             fail("Threw " + t + " instead of IndexOutOfBoundsException");
502         }
503 
504         fail("Should throw IndexOutOfBoundsException");
505     }
506 
507     /***
508      * Positive and negative tests on setIndexedProperty valid arguments.
509      */
510     public void testSetIndexedValues()
511     {
512         bean.set("intArray", 0, new Integer(1));
513         Object value = bean.get("intArray", 0);
514 
515         assertNotNull("Returned new value 0", value);
516         ObjectAssert.assertInstanceOf("Returned Integer new value 0", Integer.class,  value);
517         assertEquals("Returned correct new value 0", 1, ((Integer) value).intValue());
518 
519 
520         bean.set("intIndexed", 1, new Integer(11));
521         value = bean.get("intIndexed", 1);
522 
523         assertNotNull("Returned new value 1", value);
524         ObjectAssert.assertInstanceOf("Returned Integer new value 1", Integer.class,  value);
525         assertEquals("Returned correct new value 1", 11, ((Integer) value).intValue());
526 
527 
528         bean.set("listIndexed", 2, "New Value 2");
529         value = bean.get("listIndexed", 2);
530 
531         assertNotNull("Returned new value 2", value);
532         ObjectAssert.assertInstanceOf("Returned String new value 2", String.class,  value);
533         assertEquals("Returned correct new value 2", "New Value 2", (String) value);
534 
535 
536         bean.set("stringArray", 3, "New Value 3");
537         value = bean.get("stringArray", 3);
538 
539         assertNotNull("Returned new value 3", value);
540         ObjectAssert.assertInstanceOf("Returned String new value 3", String.class,  value);
541         assertEquals("Returned correct new value 3", "New Value 3", (String) value);
542 
543 
544         bean.set("stringIndexed", 4, "New Value 4");
545         value = bean.get("stringIndexed", 4);
546 
547         assertNotNull("Returned new value 4", value);
548         ObjectAssert.assertInstanceOf("Returned String new value 4", String.class,  value);
549         assertEquals("Returned correct new value 4", "New Value 4", (String) value);
550     }
551 
552     /***
553      * Positive and negative tests on setMappedProperty valid arguments.
554      */
555     public void testSetMappedValues()
556     {
557         bean.set("mappedProperty", "First Key", "New First Value");
558         assertEquals("Can replace old value", "New First Value", (String) bean.get("mappedProperty", "First Key"));
559 
560         bean.set("mappedProperty", "Fourth Key", "Fourth Value");
561         assertEquals("Can set new value", "Fourth Value", (String) bean.get("mappedProperty", "Fourth Key"));
562     }
563 
564     /***
565      * Test setSimpleProperty on a boolean property.
566      */
567     public void testSetSimpleBoolean()
568     {
569         boolean oldValue = ((Boolean) bean.get("booleanProperty")).booleanValue();
570         boolean newValue = !oldValue;
571         bean.set("booleanProperty", new Boolean(newValue));
572         assertTrue("Matched new value", newValue == ((Boolean) bean.get("booleanProperty")).booleanValue());
573     }
574 
575     /***
576      * Test setSimpleProperty on a double property.
577      */
578     public void testSetSimpleDouble()
579     {
580         double oldValue = ((Double) bean.get("doubleProperty")).doubleValue();
581         double newValue = oldValue + 1.0;
582         bean.set("doubleProperty", new Double(newValue));
583         assertEquals("Matched new value", newValue, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
584     }
585 
586     /***
587      * Test setSimpleProperty on a float property.
588      */
589     public void testSetSimpleFloat()
590     {
591         float oldValue = ((Float) bean.get("floatProperty")).floatValue();
592         float newValue = oldValue + (float) 1.0;
593         bean.set("floatProperty", new Float(newValue));
594         assertEquals("Matched new value", newValue, ((Float) bean.get("floatProperty")).floatValue(), 0.005f);
595     }
596 
597     /***
598      * Test setSimpleProperty on a int property.
599      */
600     public void testSetSimpleInt()
601     {
602         int oldValue = ((Integer) bean.get("intProperty")).intValue();
603         int newValue = oldValue + 1;
604         bean.set("intProperty", new Integer(newValue));
605         assertEquals("Matched new value", newValue, ((Integer) bean.get("intProperty")).intValue());
606     }
607 
608     /***
609      * Test setSimpleProperty on a long property.
610      */
611     public void testSetSimpleLong()
612     {
613         long oldValue = ((Long) bean.get("longProperty")).longValue();
614         long newValue = oldValue + 1;
615         bean.set("longProperty", new Long(newValue));
616         assertEquals("Matched new value", newValue, ((Long) bean.get("longProperty")).longValue());
617     }
618 
619     /***
620      * Test setSimpleProperty on a short property.
621      */
622     public void testSetSimpleShort()
623     {
624         short oldValue = ((Short) bean.get("shortProperty")).shortValue();
625         short newValue = (short) (oldValue + 1);
626         bean.set("shortProperty", new Short(newValue));
627         assertEquals("Matched new value", newValue, ((Short) bean.get("shortProperty")).shortValue());
628     }
629 
630     /***
631      * Test setSimpleProperty on a String property.
632      */
633     public void testSetSimpleString()
634     {
635         String oldValue = (String) bean.get("stringProperty");
636         String newValue = oldValue + " Extra Value";
637         bean.set("stringProperty", newValue);
638         assertEquals("Matched new value", newValue, (String) bean.get("stringProperty"));
639     }
640 
641     /***
642      * Tests set on a null value: should throw NPE.
643      */
644     public void testAddNullPropertyValue()
645     {
646         try
647         {
648             bean.set("nullProperty", null);
649         }
650         catch (NullPointerException e)
651         {
652             return;
653         }
654         catch (Throwable t)
655         {
656             fail("Threw " + t + " instead of NullPointerException");
657             return;
658         }
659         fail("Should have thrown NullPointerException");
660     }
661 
662     /***
663      * Test the retrieval of a non-existent property.
664      */
665     public void testGetNonExistentProperty()
666     {
667         try
668         {
669             bean.get("nonexistProperty");
670         }
671         catch (IllegalArgumentException e)
672         {
673             return;
674         }
675         catch (Exception e)
676         {
677             fail("Threw '" + e + "' instead of java.lang.IllegalArgumentException");
678         }
679 
680         fail("Get non-existent property failed to throw java.lang.IllegalArgumentException");
681     }
682 
683     /***
684      * Base for testGetDescriptorXxxxx() series of tests.
685      *
686      * @param name Name of the property to be retrieved
687      * @param type Expected class type of this property
688      */
689     protected void testGetDescriptorBase(String name, Class type)
690     {
691         DynaProperty descriptor = bean.getDynaClass().getDynaProperty(name);
692 
693         assertNotNull("Failed to get descriptor", descriptor);
694         assertEquals("Got incorrect type", type, descriptor.getType());
695     }
696 
697     /***
698      * Tests if accessing a non-indexed property using the index
699      * get method throws an IllegalArgumentException as it
700      * should.
701      */
702     public void testNonIndexedPropeties()
703     {
704         ConfigurationDynaBean nested = (ConfigurationDynaBean) bean.get("mappedProperty");
705 
706         String value = (String) nested.get("key1");
707         assertEquals("Can find first value", "First Value", value);
708 
709         nested.set("key1", "undefined");
710         assertEquals("Incorrect value returned", "undefined", bean.get("mappedProperty.key1"));
711     }
712 
713     /***
714      * Tests if accessing a non-indexed property using the index
715      * get method throws an IllegalArgumentException as it
716      * should.
717      */
718     public void testNestedPropeties()
719     {
720         try
721         {
722             bean.get("booleanProperty", 0);
723         }
724         catch (IllegalArgumentException e)
725         {
726             return;
727         }
728         catch (Throwable t)
729         {
730             fail("Threw " + t + " instead of IllegalArgumentException");
731             return;
732         }
733 
734         fail("Should have thrown IllegalArgumentException");
735 
736         try
737         {
738             bean.set("booleanProperty", 0, Boolean.TRUE);
739         }
740         catch (IllegalArgumentException e)
741         {
742             return;
743         }
744         catch (Throwable t)
745         {
746             fail("Threw " + t + " instead of IllegalArgumentException");
747             return;
748         }
749 
750         fail("Should have thrown IllegalArgumentException");
751     }
752 
753 
754 }