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 }