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