    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.io.Serializable;
    20  import java.lang.reflect.Method;
    21  import java.util.Map;
    22  import java.util.HashMap;
    23
    24  import junit.framework.Test;
    25  import junit.textui.TestRunner;
    26
    27  import org.apache.commons.collections.map.AbstractTestMap;
    28  import org.apache.commons.collections.BulkTest;
    29  import org.apache.commons.collections.Transformer;
    30
    31  /***
    32   * Test cases for BeanMap
    33   *
    34   * @version $Revision: 557796 $ $Date: 2007-07-19 23:28:49 +0100 (Thu, 19 Jul 2007) $
    35   *
    36   * @author Morgan Delagrange
    37   * @author Stephen Colebourne
    38   */
    39  public class BeanMapTestCase extends AbstractTestMap {
    40
    41      public BeanMapTestCase(String testName) {
    42          super(testName);
    43      }
    44
    45      public static void main(String[] args) {
    46          TestRunner.run(suite());
    47      }
    48
    49      public static Test suite() {
    50          return BulkTest.makeSuite(BeanMapTestCase.class);
    51      }
    52
    53  /*
    54    note to self.  The getter and setter methods were generated by copying the
    55    field declarations and using the following regular expression search and
    56    replace:
    57
    58    From:
    59          private \(.*\) some\(.*\);
    60    To:
    61          public \1 getSome\2Value() {
    62              return some\2;
    63          }
    64          public void setSome\2Value(\1 value) {
    65              some\2 = value;
    66          }
    67
    68    Also note:  The sample keys and mappings were generated manually.
    69  */
    70
    71
    72      public static class BeanWithProperties implements Serializable {
    73          private int someInt;
    74          private long someLong;
    75          private double someDouble;
    76          private float someFloat;
    77          private short someShort;
    78          private byte someByte;
    79          private char someChar;
    80          private Integer someInteger;
    81          private String someString;
    82          private Object someObject;
    83
    84          public int getSomeIntValue() {
    85              return someInt;
    86          }
    87          public void setSomeIntValue(int value) {
    88              someInt = value;
    89          }
    90
    91          public long getSomeLongValue() {
    92              return someLong;
    93          }
    94          public void setSomeLongValue(long value) {
    95              someLong = value;
    96          }
    97
    98          public double getSomeDoubleValue() {
    99              return someDouble;
    100         }
    101         public void setSomeDoubleValue(double value) {
    102             someDouble = value;
    103         }
    104
    105         public float getSomeFloatValue() {
    106             return someFloat;
    107         }
    108         public void setSomeFloatValue(float value) {
    109             someFloat = value;
    110         }
    111
    112         public short getSomeShortValue() {
    113             return someShort;
    114         }
    115         public void setSomeShortValue(short value) {
    116             someShort = value;
    117         }
    118
    119         public byte getSomeByteValue() {
    120             return someByte;
    121         }
    122         public void setSomeByteValue(byte value) {
    123             someByte = value;
    124         }
    125
    126         public char getSomeCharValue() {
    127             return someChar;
    128         }
    129         public void setSomeCharValue(char value) {
    130             someChar = value;
    131         }
    132
    133         public String getSomeStringValue() {
    134             return someString;
    135         }
    136         public void setSomeStringValue(String value) {
    137             someString = value;
    138         }
    139
    140         public Integer getSomeIntegerValue() {
    141             return someInteger;
    142         }
    143         public void setSomeIntegerValue(Integer value) {
    144             someInteger = value;
    145         }
    146
    147         public Object getSomeObjectValue() {
    148             return someObject;
    149         }
    150         public void setSomeObjectValue(Object value) {
    151             someObject = value;
    152         }
    153     }
    154
    155     // note to self.  The Sample keys were generated by copying the field
    156     // declarations and using the following regular expression search and replace:
    157     //
    158     // From:
    159     //    private \(.*\) some\(.*\);
    160     // To:
    161     //    "some\2Value",
    162     //
    163     // Then, I manually added the "class" key, which is a property that exists for
    164     // all beans (and all objects for that matter.
    165     public Object[] getSampleKeys() {
    166         Object[] keys = new Object[] {
    167             "someIntValue",
    168             "someLongValue",
    169             "someDoubleValue",
    170             "someFloatValue",
    171             "someShortValue",
    172             "someByteValue",
    173             "someCharValue",
    174             "someIntegerValue",
    175             "someStringValue",
    176             "someObjectValue",
    177             "class",
    178         };
    179         return keys;
    180     }
    181
    182     /***
    183      *  An object value that will be stored in the bean map as a value.  Need
    184      *  to save this externally so that we can make sure the object instances
    185      *  are equivalent since getSampleValues() would otherwise construct a new
    186      *  and different Object each time.
    187      **/
    188     private Object objectInFullMap = new Object();
    189
    190     // note to self: the sample values were created manually
    191     public Object[] getSampleValues() {
    192         Object[] values = new Object[] {
    193             new Integer(1234),
    194             new Long(1298341928234L),
    195             new Double(123423.34),
    196             new Float(1213332.12f),
    197             new Short((short)134),
    198             new Byte((byte)10),
    199             new Character('a'),
    200             new Integer(1432),
    201             "SomeStringValue",
    202             objectInFullMap,
    203             BeanWithProperties.class,
    204         };
    205         return values;
    206     }
    207
    208     public Object[] getNewSampleValues() {
    209         Object[] values = new Object[] {
    210             new Integer(223),
    211             new Long(23341928234L),
    212             new Double(23423.34),
    213             new Float(213332.12f),
    214             new Short((short)234),
    215             new Byte((byte)20),
    216             new Character('b'),
    217             new Integer(232),
    218             "SomeNewStringValue",
    219             new Object(),
    220             null,
    221         };
    222         return values;
    223     }
    224
    225     /***
    226      * Values is a dead copy in BeanMap, so refresh each time.
    227      */
    228     public void verifyValues() {
    229         values = map.values();
    230         super.verifyValues();
    231     }
    232
    233     /***
    234      * The mappings in a BeanMap are fixed on the properties the underlying
    235      * bean has.  Adding and removing mappings is not possible, thus this
    236      * method is overridden to return false.
    237      */
    238     public boolean isPutAddSupported() {
    239         return false;
    240     }
    241
    242     /***
    243      * The mappings in a BeanMap are fixed on the properties the underlying
    244      * bean has.  Adding and removing mappings is not possible, thus this
    245      * method is overridden to return false.
    246      */
    247     public boolean isRemoveSupported() {
    248         return false;
    249     }
    250
    251     public Map makeFullMap() {
    252         // note: These values must match (i.e. .equals() must return true)
    253         // those returned from getSampleValues().
    254         BeanWithProperties bean = new BeanWithProperties();
    255         bean.setSomeIntValue(1234);
    256         bean.setSomeLongValue(1298341928234L);
    257         bean.setSomeDoubleValue(123423.34);
    258         bean.setSomeFloatValue(1213332.12f);
    259         bean.setSomeShortValue((short)134);
    260         bean.setSomeByteValue((byte)10);
    261         bean.setSomeCharValue('a');
    262         bean.setSomeIntegerValue(new Integer(1432));
    263         bean.setSomeStringValue("SomeStringValue");
    264         bean.setSomeObjectValue(objectInFullMap);
    265         return new BeanMap(bean);
    266     }
    267
    268     public Map makeEmptyMap() {
    269         return new BeanMap();
    270     }
    271
    272     public String[] ignoredTests() {
    273         // Ignore the serialization tests on collection views.
    274         return new String[] {
    275          "TestBeanMap.bulkTestMapEntrySet.testCanonicalEmptyCollectionExists",
    276          "TestBeanMap.bulkTestMapEntrySet.testCanonicalFullCollectionExists",
    277          "TestBeanMap.bulkTestMapKeySet.testCanonicalEmptyCollectionExists",
    278          "TestBeanMap.bulkTestMapKeySet.testCanonicalFullCollectionExists",
    279          "TestBeanMap.bulkTestMapValues.testCanonicalEmptyCollectionExists",
    280          "TestBeanMap.bulkTestMapValues.testCanonicalFullCollectionExists",
    281          "TestBeanMap.bulkTestMapEntrySet.testSimpleSerialization",
    282          "TestBeanMap.bulkTestMapKeySet.testSimpleSerialization",
    283          "TestBeanMap.bulkTestMapEntrySet.testSerializeDeserializeThenCompare",
    284          "TestBeanMap.bulkTestMapKeySet.testSerializeDeserializeThenCompare"
    285         };
    286     }
    287
    288     /***
    289      * Need to override this method because the "clear()" method on the bean
    290      * map just returns the bean properties to their default states.  It does
    291      * not actually remove the mappings as per the map contract.  The default
    292      * testClear() methods checks that the clear method throws an
    293      * UnsupportedOperationException since this class is not add/remove
    294      * modifiable.  In our case though, we do not always throw that exception.
    295      */
    296     public void testMapClear() {
    297         //TODO: make sure a call to BeanMap.clear returns the bean to its
    298         //default initialization values.
    299     }
    300
    301     /***
    302      * Need to override this method because the "put()" method on the bean
    303      * doesn't work for this type of Map.
    304      */
    305     public void testMapPut() {
    306         // see testBeanMapPutAllWriteable
    307     }
    308
    309     public void testBeanMapClone() {
    310         BeanMap map = (BeanMap)makeFullMap();
    311         try {
    312             BeanMap map2 = (BeanMap)((BeanMap)map).clone();
    313
    314             // make sure containsKey is working to verify the bean was cloned
    315             // ok, and the read methods were properly initialized
    316             Object[] keys = getSampleKeys();
    317             for(int i = 0; i < keys.length; i++) {
    318                 assertTrue("Cloned BeanMap should contain the same keys",
    319                            map2.containsKey(keys[i]));
    320             }
    321         } catch (CloneNotSupportedException exception) {
    322             fail("BeanMap.clone() should not throw a " +
    323                  "CloneNotSupportedException when clone should succeed.");
    324         }
    325     }
    326
    327     public void testBeanMapPutAllWriteable() {
    328         BeanMap map1 = (BeanMap)makeFullMap();
    329         BeanMap map2 = (BeanMap)makeFullMap();
    330         map2.put("someIntValue", new Integer(0));
    331         map1.putAllWriteable(map2);
    332         assertEquals(map1.get("someIntValue"), new Integer(0));
    333     }
    334
    335     public void testMethodAccessor() throws Exception {
    336         BeanMap map = (BeanMap) makeFullMap();
    337         Method method = BeanWithProperties.class.getDeclaredMethod("getSomeIntegerValue", null);
    338         assertEquals(method, map.getReadMethod("someIntegerValue"));
    339     }
    340
    341     public void testMethodMutator() throws Exception {
    342         BeanMap map = (BeanMap) makeFullMap();
    343         Method method = BeanWithProperties.class.getDeclaredMethod("setSomeIntegerValue", new Class[] {Integer.class});
    344         assertEquals(method, map.getWriteMethod("someIntegerValue"));
    345     }
    346
    347     /***
    348      *  Test the default transformers using the getTypeTransformer() method
    349      */
    350     public void testGetTypeTransformerMethod() {
    351         BeanMap beanMap = new BeanMap();
    352         assertEquals("Boolean.TYPE",   Boolean.TRUE,        beanMap.getTypeTransformer(Boolean.TYPE).transform("true"));
    353         assertEquals("Character.TYPE", new Character('B'),  beanMap.getTypeTransformer(Character.TYPE).transform("BCD"));
    354         assertEquals("Byte.TYPE",      new Byte((byte)1),   beanMap.getTypeTransformer(Byte.TYPE).transform("1"));
    355         assertEquals("Short.TYPE",     new Short((short)2), beanMap.getTypeTransformer(Short.TYPE).transform("2"));
    356         assertEquals("Integer.TYPE",   new Integer(3),      beanMap.getTypeTransformer(Integer.TYPE).transform("3"));
    357         assertEquals("Long.TYPE",      new Long(4),         beanMap.getTypeTransformer(Long.TYPE).transform("4"));
    358         assertEquals("Float.TYPE",     new Float("5"),      beanMap.getTypeTransformer(Float.TYPE).transform("5"));
    359         assertEquals("Double.TYPE",    new Double("6"),     beanMap.getTypeTransformer(Double.TYPE).transform("6"));
    360     }
    361
    362     /***
    363      *  Test the default transformers via the public static Map instance
    364      */
    365     public void testGetDefaultTransformersMap() {
    366         BeanMap beanMap = new BeanMap();
    367         assertEquals("Boolean.TYPE",   Boolean.TRUE,        ((Transformer)BeanMap.defaultTransformers.get(Boolean.TYPE)).transform("true"));
    368         assertEquals("Character.TYPE", new Character('B'),  ((Transformer)BeanMap.defaultTransformers.get(Character.TYPE)).transform("BCD"));
    369         assertEquals("Byte.TYPE",      new Byte((byte)1),   ((Transformer)BeanMap.defaultTransformers.get(Byte.TYPE)).transform("1"));
    370         assertEquals("Short.TYPE",     new Short((short)2), ((Transformer)BeanMap.defaultTransformers.get(Short.TYPE)).transform("2"));
    371         assertEquals("Integer.TYPE",   new Integer(3),      ((Transformer)BeanMap.defaultTransformers.get(Integer.TYPE)).transform("3"));
    372         assertEquals("Long.TYPE",      new Long(4),         ((Transformer)BeanMap.defaultTransformers.get(Long.TYPE)).transform("4"));
    373         assertEquals("Float.TYPE",     new Float("5"),      ((Transformer)BeanMap.defaultTransformers.get(Float.TYPE)).transform("5"));
    374         assertEquals("Double.TYPE",    new Double("6"),     ((Transformer)BeanMap.defaultTransformers.get(Double.TYPE)).transform("6"));
    375     }
    376
    377     /***
    378      *  Test the default transformers HashMap
    379      */
    380     public void testDefaultTransformersMap() {
    381         assertEquals("Size",     8, BeanMap.defaultTransformers.size());
    382         assertEquals("entrySet", 8, BeanMap.defaultTransformers.entrySet().size());
    383         assertEquals("keySet",   8, BeanMap.defaultTransformers.keySet().size());
    384         assertEquals("values",   8, BeanMap.defaultTransformers.values().size());
    385         assertFalse("isEmpty",      BeanMap.defaultTransformers.isEmpty());
    386         assertTrue("containsKey(Double)",    BeanMap.defaultTransformers.containsKey(Double.TYPE));
    387         assertFalse("containsKey(Object)",   BeanMap.defaultTransformers.containsKey(Object.class));
    388         assertTrue("containsValue(double)",  BeanMap.defaultTransformers.containsValue(BeanMap.defaultTransformers.get(Double.TYPE)));
    389         assertFalse("containsValue(Object)", BeanMap.defaultTransformers.containsValue(Object.class));
    390
    391         try {
    392             BeanMap.defaultTransformers.clear();
    393             fail("clear() - expected UnsupportedOperationException");
    394         } catch(UnsupportedOperationException e) {
    395             // expected result
    396         }
    397         try {
    398             BeanMap.defaultTransformers.put("FOO", null);
    399             fail("put() - expected UnsupportedOperationException");
    400         } catch(UnsupportedOperationException e) {
    401             // expected result
    402         }
    403         try {
    404             BeanMap.defaultTransformers.putAll(new HashMap());
    405             fail("putAll() - expected UnsupportedOperationException");
    406         } catch(UnsupportedOperationException e) {
    407             // expected result
    408         }
    409         try {
    410             BeanMap.defaultTransformers.remove("FOO");
    411             fail("remove() - expected UnsupportedOperationException");
    412         } catch(UnsupportedOperationException e) {
    413             // expected result
    414         }
    415     }
    416
    417 }