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