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