1   /*
2    * Copyright 2004 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  package org.apache.commons.beanutils;
17  
18  import java.util.HashMap;
19  import java.util.TreeMap;
20  import java.util.ArrayList;
21  import java.util.LinkedList;
22  import java.lang.reflect.InvocationTargetException;
23  import junit.framework.TestCase;
24  import junit.framework.Test;
25  import junit.framework.TestSuite;
26  
27  /**
28   * <p>Test Case for the <code>LazyDynaBean</code> implementation class.</p>
29   *
30   * @author Niall Pemberton
31   */
32  public class LazyDynaBeanTestCase extends TestCase {
33  
34      protected LazyDynaBean  bean      = null;
35      protected LazyDynaClass dynaClass = null;
36      protected String testProperty     = "myProperty";
37      protected String testPropertyA    = "myProperty-A";
38      protected String testPropertyB    = "myProperty-B";
39      protected String testString1      = "myStringValue-1";
40      protected String testString2      = "myStringValue-2";
41      protected Integer testInteger1    = new Integer(30);
42      protected Integer testInteger2    = new Integer(40);
43      protected String testKey          = "myKey";
44  
45      // ---------------------------------------------------------- Constructors
46  
47      /**
48       * Construct a new instance of this test case.
49       *
50       * @param name Name of the test case
51       */
52      public LazyDynaBeanTestCase(String name) {
53          super(name);
54      }
55  
56      // -------------------------------------------------- Overall Test Methods
57  
58      /**
59       * Run thus Test
60       */
61      public static void main(String[] args) {
62          junit.textui.TestRunner.run(suite());
63      }
64  
65      /**
66       * Return the tests included in this test suite.
67       */
68      public static Test suite() {
69          return (new TestSuite(LazyDynaBeanTestCase.class));
70      }
71  
72      /**
73       * Set up instance variables required by this test case.
74       */
75      public void setUp() throws Exception {
76          bean = new LazyDynaBean();
77          dynaClass = (LazyDynaClass)bean.getDynaClass();
78          dynaClass.setReturnNull(true);
79      }
80  
81      /**
82       * Tear down instance variables required by this test case.
83       */
84      public void tearDown() {
85        bean = null;
86      }
87  
88      // ------------------------------------------------ Individual Test Methods
89  
90      /**
91       * Test Getting/Setting a Simple Property
92       */
93      public void testSimpleProperty() {
94  
95          // Check the property & value doesn't exist
96          assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
97          assertNull("Check Value is null", bean.get(testProperty));
98  
99          // Set a new property - should add new property and set value
100         bean.set(testProperty, testInteger1);
101         assertEquals("Check First Value is correct", testInteger1, bean.get(testProperty));
102         assertEquals("Check Property type is correct", Integer.class, dynaClass.getDynaProperty(testProperty).getType());
103 
104         // Set the property again - should set the new value
105         bean.set(testProperty, testInteger2);
106         assertEquals("Check Second Value is correct", testInteger2, bean.get(testProperty));
107 
108         // Set the property again - with a different type, should fail
109         try {
110             bean.set(testProperty, testString1);
111             fail("expected ConversionException trying to set an Integer property to a String");
112         } catch (ConversionException expected) {
113             // expected result
114         }
115 
116     }
117 
118     /**
119      * Test Setting a Simple Property when MutableDynaClass is set to restricted
120      */
121     public void testSimplePropertyRestricted() {
122 
123         // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
124         dynaClass.setRestricted(true);
125         assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
126 
127         // Check the property & value doesn't exist
128         assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
129         assertNull("Check Value is null", bean.get(testProperty));
130 
131         // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
132         try {
133             bean.set(testProperty, testString1);
134             fail("expected IllegalArgumentException trying to add new property to restricted DynaClass");
135         } catch (IllegalArgumentException expected) {
136             // expected result
137         }
138 
139     }
140 
141     /**
142      * Test Getting/Setting a 'Mapped' Property - default HashMap property
143      */
144     public void testMappedPropertyDefault() {
145 
146         // Check the property & value doesn't exist
147         assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
148         assertNull("Check Map is null", bean.get(testProperty));
149         assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
150 
151         // Set a new mapped property - should add new HashMap property and set the mapped value
152         bean.set(testProperty, testKey, testInteger1);
153         assertEquals("Check Mapped Property exists", HashMap.class, bean.get(testProperty).getClass());
154         assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
155         assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((HashMap)bean.get(testProperty)).get(testKey));
156 
157         // Set the property again - should set the new value
158         bean.set(testProperty, testKey, testInteger2);
159         assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
160         assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((HashMap)bean.get(testProperty)).get(testKey));
161     }
162 
163     /**
164      * Test Getting/Setting a 'Mapped' Property - use TreeMap property
165      */
166     public void testMappedPropertyTreeMap() {
167 
168         // Check the property & value doesn't exist
169         assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
170 
171         // Add a 'TreeMap' property to the DynaClass
172         dynaClass.add(testProperty, TreeMap.class);
173         assertTrue("Check Property is mapped", dynaClass.getDynaProperty(testProperty).isMapped());
174         assertEquals("Check Property is correct type", TreeMap.class, dynaClass.getDynaProperty(testProperty).getType());
175         assertEquals("Check Mapped Property exists", TreeMap.class, bean.get(testProperty).getClass());
176 //        assertNull("Check mapped property is null", bean.get(testProperty));
177 
178         // Set a new mapped property - should instatiate a new TreeMap property and set the mapped value
179         bean.set(testProperty, testKey, testInteger1);
180         assertEquals("Check Mapped Property exists", TreeMap.class, bean.get(testProperty).getClass());
181         assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
182         assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((TreeMap)bean.get(testProperty)).get(testKey));
183 
184         // Set the property again - should set the new value
185         bean.set(testProperty, testKey, testInteger2);
186         assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
187         assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((TreeMap)bean.get(testProperty)).get(testKey));
188     }
189 
190     /**
191      * Test Setting a 'Mapped' Property using PropertyUtils
192      */
193     public void testMappedPropertyUtils() {
194 
195         dynaClass.setReturnNull(false);
196 
197         // Check the property & value doesn't exist
198         assertFalse("Check Mapped Property doesn't exist", dynaClass.isDynaProperty(testProperty));
199         assertNull("Check Map is null", bean.get(testProperty));
200         assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
201 
202         // Set the mapped property using PropertyUtils
203         try {
204           PropertyUtils.setProperty(bean, testProperty+"("+testKey+")", testString1);
205         }
206         catch (NoSuchMethodException ex) {
207             fail("testIndexedPropertyUtils threw "+ex);
208         }
209         catch (InvocationTargetException ex) {
210             fail("testIndexedPropertyUtils threw "+ex);
211         }
212         catch (IllegalAccessException ex) {
213             fail("testIndexedPropertyUtils threw "+ex);
214         }
215 
216         // Check property value correctly set
217         assertEquals("Check Mapped Bean Value is correct", testString1, bean.get(testProperty, testKey));
218 
219     }
220 
221     /**
222      * Test Setting a Mapped Property when MutableDynaClass is set to restricted
223      */
224     public void testMappedPropertyRestricted() {
225 
226         // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
227         dynaClass.setRestricted(true);
228         assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
229 
230         // Check the property & value doesn't exist
231         assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
232         assertNull("Check Value is null", bean.get(testProperty));
233 
234         // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
235         try {
236             bean.set(testProperty, testKey, testInteger1);
237             fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
238         } catch (IllegalArgumentException expected) {
239             // expected result
240         }
241 
242     }
243 
244     /**
245      * Test setting mapped property for type which is not Map
246      */
247     public void testMappedInvalidType() {
248         dynaClass.add(testProperty, String.class);
249         assertFalse("Check Property is not mapped", dynaClass.getDynaProperty(testProperty).isMapped());
250         try {
251             bean.set(testProperty, testKey, testInteger1);
252             fail("set(property, key, value) should have thrown IllegalArgumentException");
253         } catch (IllegalArgumentException expected) {
254             // expected result
255         }
256     }
257 
258     /**
259      * Test Getting/Setting an 'Indexed' Property - default ArrayList property
260      */
261     public void testIndexedPropertyDefault() {
262 
263         int index = 3;
264 
265         // Check the property & value doesn't exist
266         assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
267         assertNull("Check Indexed Property is null", bean.get(testProperty));
268         assertNull("Check Indexed value is null", bean.get(testProperty, index));
269 
270         // Set the property, should create new ArrayList and set appropriate indexed value
271         bean.set(testProperty, index, testInteger1);
272         assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
273         assertEquals("Check Indexed Property is correct type", ArrayList.class, bean.get(testProperty).getClass());
274         assertEquals("Check First Indexed Value is correct", testInteger1, bean.get(testProperty, index));
275         assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((ArrayList)bean.get(testProperty)).size()));
276 
277         // Set a second indexed value, should automatically grow the ArrayList and set appropriate indexed value
278         index = index + 2;
279         bean.set(testProperty, index, testString1);
280         assertEquals("Check Second Indexed Value is correct", testString1, bean.get(testProperty, index));
281         assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((ArrayList)bean.get(testProperty)).size()));
282     }
283 
284     /**
285      * Test Getting/Setting a List 'Indexed' Property - use alternative List (LinkedList)
286      */
287     public void testIndexedLinkedList() {
288 
289         int   index     = 3;
290 
291         // Check the property & value doesn't exist
292         assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
293         assertNull("Check Indexed Property is null", bean.get(testProperty));
294 
295         // Add a 'LinkedList' property to the DynaClass
296         dynaClass.add(testProperty, LinkedList.class);
297         assertTrue("Check Property is indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
298         assertEquals("Check Property is correct type", LinkedList.class, dynaClass.getDynaProperty(testProperty).getType());
299         assertEquals("Check Property type is correct", LinkedList.class, bean.get(testProperty).getClass());
300 
301         // Set the property, should instantiate a new LinkedList and set appropriate indexed value
302         bean.set(testProperty, index, testString1);
303         assertEquals("Check Property type is correct", LinkedList.class, bean.get(testProperty).getClass());
304         assertEquals("Check First Indexed Value is correct", testString1, bean.get(testProperty, index));
305         assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((LinkedList)bean.get(testProperty)).size()));
306 
307         // Set a second indexed value, should automatically grow the LinkedList and set appropriate indexed value
308         index = index + 2;
309         bean.set(testProperty, index, testInteger1);
310         assertEquals("Check Second Indexed Value is correct", testInteger1, bean.get(testProperty, index));
311         assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((LinkedList)bean.get(testProperty)).size()));
312     }
313 
314     /**
315      * Test Getting/Setting a primitive array 'Indexed' Property - use int[]
316      */
317     public void testIndexedPrimitiveArray() {
318 
319         int   index     = 3;
320         int[] primitiveArray = new int[0];
321 
322         // Check the property & value doesn't exist
323         assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
324         assertNull("Check Indexed Property is null", bean.get(testProperty));
325 
326         // Add a DynaProperty of type int[]
327         dynaClass.add(testProperty, primitiveArray.getClass());
328         assertEquals("Check Indexed Property exists", primitiveArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
329         assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), bean.get(testProperty).getClass());
330 
331         // Set an indexed value
332         bean.set(testProperty, index, testInteger1);
333         assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
334         assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), bean.get(testProperty).getClass());
335         assertEquals("Check First Indexed Value is correct(a)", testInteger1, bean.get(testProperty, index));
336         assertEquals("Check First Indexed Value is correct(b)", testInteger1, new Integer(((int[])bean.get(testProperty))[index]));
337         assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((int[])bean.get(testProperty)).length));
338 
339         // Set a second indexed value, should automatically grow the int[] and set appropriate indexed value
340         index = index + 2;
341         bean.set(testProperty, index, testInteger2);
342         assertEquals("Check Second Indexed Value is correct(a)", testInteger2, bean.get(testProperty, index));
343         assertEquals("Check Second Indexed Value is correct(b)", testInteger2, new Integer(((int[])bean.get(testProperty))[index]));
344         assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((int[])bean.get(testProperty)).length));
345 
346     }
347 
348     /**
349      * Test Getting/Setting an Object array 'Indexed' Property - use String[]
350      */
351     public void testIndexedObjectArray() {
352 
353         int   index     = 3;
354         Object objectArray = new String[0];
355 
356         // Check the property & value doesn't exist
357         assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
358         assertNull("Check Indexed Property is null", bean.get(testProperty));
359 
360         // Add a DynaProperty of type String[]
361         dynaClass.add(testProperty, objectArray.getClass());
362         assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
363         assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
364 
365         // Set an indexed value
366         bean.set(testProperty, index, testString1);
367         assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
368         assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
369         assertEquals("Check First Indexed Value is correct(a)", testString1, bean.get(testProperty, index));
370         assertEquals("Check First Indexed Value is correct(b)", testString1, ((String[])bean.get(testProperty))[index]);
371         assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((String[])bean.get(testProperty)).length));
372 
373         // Set a second indexed value, should automatically grow the String[] and set appropriate indexed value
374         index = index + 2;
375         bean.set(testProperty, index, testString2);
376         assertEquals("Check Second Indexed Value is correct(a)", testString2, bean.get(testProperty, index));
377         assertEquals("Check Second Indexed Value is correct(b)", testString2, ((String[])bean.get(testProperty))[index]);
378         assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((String[])bean.get(testProperty)).length));
379     }
380 
381     /**
382      * Test Getting/Setting an DynaBean[] array
383      */
384     public void testIndexedDynaBeanArray() {
385 
386         int   index     = 3;
387         Object objectArray = new LazyDynaMap[0];
388 
389         // Check the property & value doesn't exist
390         assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
391         assertNull("Check Indexed Property is null", bean.get(testProperty));
392 
393         // Add a DynaProperty of type String[]
394         dynaClass.add(testProperty, objectArray.getClass());
395         assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
396         assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
397 
398         // Retrieving from Array should initialize DynaBean
399         for (int i = index; i >= 0; i--) {
400             assertEquals("Check Array Components initialized", LazyDynaMap.class, bean.get(testProperty, index).getClass());
401         }
402 
403         dynaClass.add(testPropertyB, objectArray.getClass());
404         LazyDynaMap newMap = new LazyDynaMap();
405         newMap.set(testPropertyB, testString2);
406         bean.set(testPropertyA, index, newMap);
407         assertEquals("Check Indexed Value is correct(a)", testString2, ((DynaBean)bean.get(testPropertyA, index)).get(testPropertyB));
408 
409     }
410 
411     /**
412      * Test Setting an 'Indexed' Property using PropertyUtils
413      */
414     public void testIndexedPropertyUtils() {
415 
416         int   index     = 3;
417         dynaClass.setReturnNull(false);
418 
419         // Check the property & value doesn't exist
420         assertFalse("Check Indexed Property doesn't exist", dynaClass.isDynaProperty(testProperty));
421         assertNull("Check Indexed Property is null", bean.get(testProperty));
422         assertNull("Check Indexed value is null", bean.get(testProperty, index));
423 
424         // Use PropertyUtils to set the indexed value
425         try {
426           PropertyUtils.setProperty(bean, testProperty+"["+index+"]", testString1);
427         }
428         catch (NoSuchMethodException ex) {
429             fail("testIndexedPropertyUtils threw "+ex);
430         }
431         catch (InvocationTargetException ex) {
432             fail("testIndexedPropertyUtils threw "+ex);
433         }
434         catch (IllegalAccessException ex) {
435             fail("testIndexedPropertyUtils threw "+ex);
436         }
437 
438         // Check property value correctly set
439         assertEquals("Check Indexed Bean Value is correct", testString1, bean.get(testProperty, index));
440 
441     }
442 
443     /**
444      * Test Setting an Indexed Property when MutableDynaClass is set to restricted
445      */
446     public void testIndexedPropertyRestricted() {
447 
448         int   index     = 3;
449 
450         // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
451         dynaClass.setRestricted(true);
452         assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
453 
454         // Check the property & value doesn't exist
455         assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
456         assertNull("Check Value is null", bean.get(testProperty));
457 
458         // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
459         try {
460             bean.set(testProperty, index, testInteger1);
461             fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
462         } catch (IllegalArgumentException expected) {
463             // expected result
464         }
465 
466     }
467 
468     /**
469      * Test setting indexed property for type which is not List or Array
470      */
471     public void testIndexedInvalidType() {
472         int   index     = 3;
473         dynaClass.add(testProperty, String.class);
474         assertFalse("Check Property is not indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
475         try {
476             bean.set(testProperty, index, testString1);
477             fail("set(property, index, value) should have thrown IllegalArgumentException");
478         } catch (IllegalArgumentException expected) {
479             // expected result
480         }
481     }
482 
483 }