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