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