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    *      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  
18  package org.apache.commons.beanutils;
19  
20  
21  import java.lang.reflect.InvocationTargetException;
22  import java.util.Calendar;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.StringTokenizer;
28  
29  import junit.framework.Test;
30  import junit.framework.TestCase;
31  import junit.framework.TestSuite;
32  
33  import org.apache.commons.beanutils.converters.ArrayConverter;
34  import org.apache.commons.beanutils.converters.DateConverter;
35  
36  
37  /**
38   * <p>
39   *  Test Case for the BeanUtils class.  The majority of these tests use
40   *  instances of the TestBean class, so be sure to update the tests if you
41   *  change the characteristics of that class.
42   * </p>
43   *
44   * <p>
45   *  Template for this stolen from Craigs PropertyUtilsTestCase
46   * </p>
47   *
48   * <p>
49   *   Note that the tests are dependant upon the static aspects
50   *   (such as array sizes...) of the TestBean.java class, so ensure
51   *   than all changes to TestBean are reflected here.
52   * </p>
53   *
54   * <p>
55   *  So far, this test case has tests for the following methods of the
56   *  <code>BeanUtils</code> class:
57   * </p>
58   * <ul>
59   *   <li>getArrayProperty(Object bean, String name)</li>
60   * </ul>
61   *
62   * @version $Id$
63   */
64  
65  public class BeanUtilsTestCase extends TestCase {
66  
67      // ---------------------------------------------------- Instance Variables
68  
69      /**
70       * The test bean for each test.
71       */
72      protected TestBean bean = null;
73  
74  
75      /**
76       * The set of properties that should be described.
77       */
78      protected String describes[] =
79      { "booleanProperty",
80        "booleanSecond",
81        "byteProperty",
82        "doubleProperty",
83        "dupProperty",
84        "floatProperty",
85        "intArray",
86        //      "intIndexed",
87        "longProperty",
88        "listIndexed",
89        "longProperty",
90        //      "mappedProperty",
91        //      "mappedIntProperty",
92        "nested",
93        "nullProperty",
94        "readOnlyProperty",
95        "shortProperty",
96        "stringArray",
97        //      "stringIndexed",
98        "stringProperty"
99      };
100 
101     /** Test Calendar value */
102     protected java.util.Calendar testCalendar;
103 
104     /** Test java.util.Date value */
105     protected java.util.Date testUtilDate;
106 
107     /** Test String Date value */
108     protected String testStringDate;
109 
110     // ---------------------------------------------------------- Constructors
111 
112     /**
113      * Construct a new instance of this test case.
114      *
115      * @param name Name of the test case
116      */
117     public BeanUtilsTestCase(final String name) {
118         super(name);
119     }
120 
121 
122     // -------------------------------------------------- Overall Test Methods
123 
124 
125     /**
126      * Set up instance variables required by this test case.
127      */
128     @Override
129     public void setUp() {
130         ConvertUtils.deregister();
131         BeanUtilsBean.setInstance(new BeanUtilsBean());
132         setUpShared();
133     }
134 
135     /**
136      * Shared Set up.
137      */
138     protected void setUpShared() {
139         bean = new TestBean();
140 
141         final DateConverter dateConverter = new DateConverter(null);
142         dateConverter.setLocale(Locale.US);
143         dateConverter.setPattern("dd.MM.yyyy");
144         ConvertUtils.register(dateConverter, java.util.Date.class);
145 
146         final ArrayConverter dateArrayConverter =
147             new ArrayConverter(java.util.Date[].class, dateConverter, 0);
148         ConvertUtils.register(dateArrayConverter, java.util.Date[].class);
149 
150         testCalendar = Calendar.getInstance();
151         testCalendar.set(1992, 11, 28, 0, 0, 0);
152         testCalendar.set(Calendar.MILLISECOND, 0);
153         testUtilDate = testCalendar.getTime();
154         testStringDate = "28.12.1992";
155     }
156 
157 
158     /**
159      * Return the tests included in this test suite.
160      */
161     public static Test suite() {
162         return (new TestSuite(BeanUtilsTestCase.class));
163     }
164 
165     /**
166      * Tear down instance variables required by this test case.
167      */
168     @Override
169     public void tearDown() {
170         bean = null;
171     }
172 
173 
174     // ------------------------------------------------ Individual Test Methods
175 
176 
177     /**
178      * Test the copyProperties() method from a DynaBean.
179      */
180     public void testCopyPropertiesDynaBean() {
181 
182         // Set up an origin bean with customized properties
183         final DynaClass dynaClass = DynaBeanUtilsTestCase.createDynaClass();
184         DynaBean orig = null;
185         try {
186             orig = dynaClass.newInstance();
187         } catch (final Exception e) {
188             fail("newInstance(): " + e);
189         }
190         orig.set("booleanProperty", Boolean.FALSE);
191         orig.set("byteProperty", new Byte((byte) 111));
192         orig.set("doubleProperty", new Double(333.33));
193         orig.set("dupProperty",
194                  new String[] { "New 0", "New 1", "New 2" });
195         orig.set("intArray", new int[] { 100, 200, 300 });
196         orig.set("intProperty", new Integer(333));
197         orig.set("longProperty", new Long(3333));
198         orig.set("shortProperty", new Short((short) 33));
199         orig.set("stringArray", new String[] { "New 0", "New 1" });
200         orig.set("stringProperty", "Custom string");
201 
202         // Copy the origin bean to our destination test bean
203         try {
204             BeanUtils.copyProperties(bean, orig);
205         } catch (final Exception e) {
206             fail("Threw exception: " + e);
207         }
208 
209         // Validate the results for scalar properties
210         assertEquals("Copied boolean property",
211                      false,
212                      bean.getBooleanProperty());
213         assertEquals("Copied byte property",
214                      (byte) 111,
215                      bean.getByteProperty());
216         assertEquals("Copied double property",
217                      333.33,
218                      bean.getDoubleProperty(),
219                      0.005);
220         assertEquals("Copied int property",
221                      333,
222                      bean.getIntProperty());
223         assertEquals("Copied long property",
224                      3333,
225                      bean.getLongProperty());
226         assertEquals("Copied short property",
227                      (short) 33,
228                      bean.getShortProperty());
229         assertEquals("Copied string property",
230                      "Custom string",
231                      bean.getStringProperty());
232 
233         // Validate the results for array properties
234         final String dupProperty[] = bean.getDupProperty();
235         assertNotNull("dupProperty present", dupProperty);
236         assertEquals("dupProperty length", 3, dupProperty.length);
237         assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
238         assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
239         assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
240         final int intArray[] = bean.getIntArray();
241         assertNotNull("intArray present", intArray);
242         assertEquals("intArray length", 3, intArray.length);
243         assertEquals("intArray[0]", 100, intArray[0]);
244         assertEquals("intArray[1]", 200, intArray[1]);
245         assertEquals("intArray[2]", 300, intArray[2]);
246         final String stringArray[] = bean.getStringArray();
247         assertNotNull("stringArray present", stringArray);
248         assertEquals("stringArray length", 2, stringArray.length);
249         assertEquals("stringArray[0]", "New 0", stringArray[0]);
250         assertEquals("stringArray[1]", "New 1", stringArray[1]);
251 
252     }
253 
254 
255     /**
256      * Test copyProperties() when the origin is a a <code>Map</code>.
257      */
258     public void testCopyPropertiesMap() {
259 
260         final Map<String, Object> map = new HashMap<String, Object>();
261         map.put("booleanProperty", "false");
262         map.put("byteProperty", "111");
263         map.put("doubleProperty", "333.0");
264         map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
265         map.put("floatProperty", "222.0");
266         map.put("intArray", new String[] { "0", "100", "200" });
267         map.put("intProperty", "111");
268         map.put("longProperty", "444");
269         map.put("shortProperty", "555");
270         map.put("stringProperty", "New String Property");
271 
272         try {
273             BeanUtils.copyProperties(bean, map);
274         } catch (final Throwable t) {
275             fail("Threw " + t.toString());
276         }
277 
278         // Scalar properties
279         assertEquals("booleanProperty", false,
280                      bean.getBooleanProperty());
281         assertEquals("byteProperty", (byte) 111,
282                      bean.getByteProperty());
283         assertEquals("doubleProperty", 333.0,
284                      bean.getDoubleProperty(), 0.005);
285         assertEquals("floatProperty", (float) 222.0,
286                      bean.getFloatProperty(), (float) 0.005);
287         assertEquals("longProperty", 111,
288                      bean.getIntProperty());
289         assertEquals("longProperty", 444,
290                      bean.getLongProperty());
291         assertEquals("shortProperty", (short) 555,
292                      bean.getShortProperty());
293         assertEquals("stringProperty", "New String Property",
294                      bean.getStringProperty());
295 
296         // Indexed Properties
297         final String dupProperty[] = bean.getDupProperty();
298         assertNotNull("dupProperty present", dupProperty);
299         assertEquals("dupProperty length", 3, dupProperty.length);
300         assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
301         assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
302         assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
303         final int intArray[] = bean.getIntArray();
304         assertNotNull("intArray present", intArray);
305         assertEquals("intArray length", 3, intArray.length);
306         assertEquals("intArray[0]", 0, intArray[0]);
307         assertEquals("intArray[1]", 100, intArray[1]);
308         assertEquals("intArray[2]", 200, intArray[2]);
309 
310     }
311 
312 
313     /**
314      * Test the copyProperties() method from a standard JavaBean.
315      */
316     public void testCopyPropertiesStandard() {
317 
318         // Set up an origin bean with customized properties
319         final TestBean orig = new TestBean();
320         orig.setBooleanProperty(false);
321         orig.setByteProperty((byte) 111);
322         orig.setDoubleProperty(333.33);
323         orig.setDupProperty(new String[] { "New 0", "New 1", "New 2" });
324         orig.setIntArray(new int[] { 100, 200, 300 });
325         orig.setIntProperty(333);
326         orig.setLongProperty(3333);
327         orig.setShortProperty((short) 33);
328         orig.setStringArray(new String[] { "New 0", "New 1" });
329         orig.setStringProperty("Custom string");
330 
331         // Copy the origin bean to our destination test bean
332         try {
333             BeanUtils.copyProperties(bean, orig);
334         } catch (final Exception e) {
335             fail("Threw exception: " + e);
336         }
337 
338         // Validate the results for scalar properties
339         assertEquals("Copied boolean property",
340                      false,
341                      bean.getBooleanProperty());
342         assertEquals("Copied byte property",
343                      (byte) 111,
344                      bean.getByteProperty());
345         assertEquals("Copied double property",
346                      333.33,
347                      bean.getDoubleProperty(),
348                      0.005);
349         assertEquals("Copied int property",
350                      333,
351                      bean.getIntProperty());
352         assertEquals("Copied long property",
353                      3333,
354                      bean.getLongProperty());
355         assertEquals("Copied short property",
356                      (short) 33,
357                      bean.getShortProperty());
358         assertEquals("Copied string property",
359                      "Custom string",
360                      bean.getStringProperty());
361 
362         // Validate the results for array properties
363         final String dupProperty[] = bean.getDupProperty();
364         assertNotNull("dupProperty present", dupProperty);
365         assertEquals("dupProperty length", 3, dupProperty.length);
366         assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
367         assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
368         assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
369         final int intArray[] = bean.getIntArray();
370         assertNotNull("intArray present", intArray);
371         assertEquals("intArray length", 3, intArray.length);
372         assertEquals("intArray[0]", 100, intArray[0]);
373         assertEquals("intArray[1]", 200, intArray[1]);
374         assertEquals("intArray[2]", 300, intArray[2]);
375         final String stringArray[] = bean.getStringArray();
376         assertNotNull("stringArray present", stringArray);
377         assertEquals("stringArray length", 2, stringArray.length);
378         assertEquals("stringArray[0]", "New 0", stringArray[0]);
379         assertEquals("stringArray[1]", "New 1", stringArray[1]);
380 
381     }
382 
383 
384     /**
385      * Test the describe() method.
386      */
387     public void testDescribe() {
388 
389         Map<String, String> map = null;
390         try {
391             map = BeanUtils.describe(bean);
392         } catch (final Exception e) {
393             fail("Threw exception " + e);
394         }
395 
396         // Verify existence of all the properties that should be present
397         for (String describe : describes) {
398             assertTrue("Property '" + describe + "' is present",
399                        map.containsKey(describe));
400         }
401         assertTrue("Property 'writeOnlyProperty' is not present",
402                    !map.containsKey("writeOnlyProperty"));
403 
404         // Verify the values of scalar properties
405         assertEquals("Value of 'booleanProperty'",
406                      "true",
407                      map.get("booleanProperty"));
408         assertEquals("Value of 'byteProperty'",
409                      "121",
410                      map.get("byteProperty"));
411         assertEquals("Value of 'doubleProperty'",
412                      "321.0",
413                      map.get("doubleProperty"));
414         assertEquals("Value of 'floatProperty'",
415                      "123.0",
416                      map.get("floatProperty"));
417         assertEquals("Value of 'intProperty'",
418                      "123",
419                      map.get("intProperty"));
420         assertEquals("Value of 'longProperty'",
421                      "321",
422                      map.get("longProperty"));
423         assertEquals("Value of 'shortProperty'",
424                      "987",
425                      map.get("shortProperty"));
426         assertEquals("Value of 'stringProperty'",
427                      "This is a string",
428                      map.get("stringProperty"));
429 
430     }
431 
432 
433     /**
434      *  tests the string and int arrays of TestBean
435      */
436     public void testGetArrayProperty() {
437         try {
438             String arr[] = BeanUtils.getArrayProperty(bean, "stringArray");
439             final String comp[] = bean.getStringArray();
440 
441             assertTrue("String array length = " + comp.length,
442                     (comp.length == arr.length));
443 
444             arr = BeanUtils.getArrayProperty(bean, "intArray");
445             final int iarr[] = bean.getIntArray();
446 
447             assertTrue("String array length = " + iarr.length,
448                     (iarr.length == arr.length));
449 
450 
451             // Test property which isn't array or collection
452             arr = BeanUtils.getArrayProperty(bean, "shortProperty");
453             final String shortAsString = "" + bean.getShortProperty();
454             assertEquals("Short List Test lth", 1, arr.length);
455             assertEquals("Short Test value", shortAsString, arr[0]);
456 
457 
458             // Test comma delimited list
459             bean.setStringProperty("ABC");
460             arr = BeanUtils.getArrayProperty(bean, "stringProperty");
461             assertEquals("Delimited List Test lth", 1, arr.length);
462             assertEquals("Delimited List Test value1", "ABC", arr[0]);
463 
464         } catch (final IllegalAccessException e) {
465             fail("IllegalAccessException");
466         } catch (final InvocationTargetException e) {
467             fail("InvocationTargetException");
468         } catch (final NoSuchMethodException e) {
469             fail("NoSuchMethodException");
470         }
471 
472     }
473 
474     /**
475      * Test <code>getArrayProperty()</code> converting to a String.
476      */
477     public void testGetArrayPropertyDate() {
478         String[] value = null;
479         try {
480             bean.setDateArrayProperty(new java.util.Date[] {testUtilDate});
481             value = BeanUtils.getArrayProperty(bean, "dateArrayProperty");
482         } catch (final Throwable t) {
483             fail("Threw " + t);
484         }
485         assertEquals("java.util.Date[] --> String[] length", 1, value.length);
486         assertEquals("java.util.Date[] --> String[] value ", testUtilDate.toString(), value[0]);
487     }
488 
489     /**
490      *  tests getting an indexed property
491      */
492     public void testGetIndexedProperty1() {
493         try {
494             String val = BeanUtils.getIndexedProperty(bean, "intIndexed[3]");
495             String comp = String.valueOf(bean.getIntIndexed(3));
496             assertTrue("intIndexed[3] == " + comp, val.equals(comp));
497 
498             val = BeanUtils.getIndexedProperty(bean, "stringIndexed[3]");
499             comp = bean.getStringIndexed(3);
500             assertTrue("stringIndexed[3] == " + comp, val.equals(comp));
501         } catch (final IllegalAccessException e) {
502             fail("IllegalAccessException");
503         } catch (final InvocationTargetException e) {
504             fail("InvocationTargetException");
505         } catch (final NoSuchMethodException e) {
506             fail("NoSuchMethodException");
507         }
508     }
509 
510     /**
511      * Test <code>getArrayProperty()</code> converting to a String.
512      */
513     public void testGetIndexedPropertyDate() {
514         String value = null;
515         try {
516             bean.setDateArrayProperty(new java.util.Date[] {testUtilDate});
517             value = BeanUtils.getIndexedProperty(bean, "dateArrayProperty[0]");
518         } catch (final Throwable t) {
519             fail("Threw " + t);
520         }
521         assertEquals("java.util.Date[0] --> String", testUtilDate.toString(), value);
522     }
523 
524     /**
525      *  tests getting an indexed property
526      */
527     public void testGetIndexedProperty2() {
528         try {
529             String val = BeanUtils.getIndexedProperty(bean, "intIndexed", 3);
530             String comp = String.valueOf(bean.getIntIndexed(3));
531 
532             assertTrue("intIndexed,3 == " + comp, val.equals(comp));
533 
534             val = BeanUtils.getIndexedProperty(bean, "stringIndexed", 3);
535             comp = bean.getStringIndexed(3);
536 
537             assertTrue("stringIndexed,3 == " + comp, val.equals(comp));
538 
539         } catch (final IllegalAccessException e) {
540             fail("IllegalAccessException");
541         } catch (final InvocationTargetException e) {
542             fail("InvocationTargetException");
543         } catch (final NoSuchMethodException e) {
544             fail("NoSuchMethodException");
545         }
546     }
547 
548 
549     /**
550      *  tests getting a nested property
551      */
552     public void testGetNestedProperty() {
553         try {
554             final String val = BeanUtils.getNestedProperty(bean, "nested.stringProperty");
555             final String comp = bean.getNested().getStringProperty();
556             assertTrue("nested.StringProperty == " + comp,
557                     val.equals(comp));
558         } catch (final IllegalAccessException e) {
559             fail("IllegalAccessException");
560         } catch (final InvocationTargetException e) {
561             fail("InvocationTargetException");
562         } catch (final NoSuchMethodException e) {
563             fail("NoSuchMethodException");
564         }
565     }
566 
567 
568     /**
569      *  tests getting a 'whatever' property
570      */
571     public void testGetGeneralProperty() {
572         try {
573             final String val = BeanUtils.getProperty(bean, "nested.intIndexed[2]");
574             final String comp = String.valueOf(bean.getIntIndexed(2));
575 
576             assertTrue("nested.intIndexed[2] == " + comp,
577                     val.equals(comp));
578         } catch (final IllegalAccessException e) {
579             fail("IllegalAccessException");
580         } catch (final InvocationTargetException e) {
581             fail("InvocationTargetException");
582         } catch (final NoSuchMethodException e) {
583             fail("NoSuchMethodException");
584         }
585     }
586 
587 
588     /**
589      *  tests getting a 'whatever' property
590      */
591     public void testGetSimpleProperty() {
592         try {
593             final String val = BeanUtils.getSimpleProperty(bean, "shortProperty");
594             final String comp = String.valueOf(bean.getShortProperty());
595 
596             assertTrue("shortProperty == " + comp,
597                     val.equals(comp));
598         } catch (final IllegalAccessException e) {
599             fail("IllegalAccessException");
600         } catch (final InvocationTargetException e) {
601             fail("InvocationTargetException");
602         } catch (final NoSuchMethodException e) {
603             fail("NoSuchMethodException");
604         }
605     }
606 
607     /**
608      * Test <code>getSimpleProperty()</code> converting to a String.
609      */
610     public void testGetSimplePropertyDate() {
611         String value = null;
612         try {
613             bean.setDateProperty(testUtilDate);
614             value = BeanUtils.getSimpleProperty(bean, "dateProperty");
615         } catch (final Throwable t) {
616             fail("Threw " + t);
617         }
618         assertEquals("java.util.Date --> String", testUtilDate.toString(), value);
619     }
620 
621     /**
622      * Test populate() method on individual array elements.
623      */
624     public void testPopulateArrayElements() {
625 
626         try {
627 
628             final HashMap<String, Object> map = new HashMap<String, Object>();
629             map.put("intIndexed[0]", "100");
630             map.put("intIndexed[2]", "120");
631             map.put("intIndexed[4]", "140");
632 
633             BeanUtils.populate(bean, map);
634 
635             assertEquals("intIndexed[0] is 100",
636                          100, bean.getIntIndexed(0));
637             assertEquals("intIndexed[1] is 10",
638                          10, bean.getIntIndexed(1));
639             assertEquals("intIndexed[2] is 120",
640                          120, bean.getIntIndexed(2));
641             assertEquals("intIndexed[3] is 30",
642                          30, bean.getIntIndexed(3));
643             assertEquals("intIndexed[4] is 140",
644                          140, bean.getIntIndexed(4));
645 
646             map.clear();
647             map.put("stringIndexed[1]", "New String 1");
648             map.put("stringIndexed[3]", "New String 3");
649 
650             BeanUtils.populate(bean, map);
651 
652             assertEquals("stringIndexed[0] is \"String 0\"",
653                          "String 0", bean.getStringIndexed(0));
654             assertEquals("stringIndexed[1] is \"New String 1\"",
655                          "New String 1", bean.getStringIndexed(1));
656             assertEquals("stringIndexed[2] is \"String 2\"",
657                          "String 2", bean.getStringIndexed(2));
658             assertEquals("stringIndexed[3] is \"New String 3\"",
659                          "New String 3", bean.getStringIndexed(3));
660             assertEquals("stringIndexed[4] is \"String 4\"",
661                          "String 4", bean.getStringIndexed(4));
662 
663         } catch (final IllegalAccessException e) {
664             fail("IllegalAccessException");
665         } catch (final InvocationTargetException e) {
666             fail("InvocationTargetException");
667         }
668 
669     }
670 
671 
672     /**
673      * Test populate() method on array properties as a whole.
674      */
675     public void testPopulateArrayProperties() {
676 
677         try {
678 
679             final HashMap<String, Object> map = new HashMap<String, Object>();
680             int intArray[] = new int[] { 123, 456, 789 };
681             map.put("intArray", intArray);
682             String stringArray[] = new String[]
683                 { "New String 0", "New String 1" };
684             map.put("stringArray", stringArray);
685 
686             BeanUtils.populate(bean, map);
687 
688             intArray = bean.getIntArray();
689             assertNotNull("intArray is present", intArray);
690             assertEquals("intArray length",
691                          3, intArray.length);
692             assertEquals("intArray[0]", 123, intArray[0]);
693             assertEquals("intArray[1]", 456, intArray[1]);
694             assertEquals("intArray[2]", 789, intArray[2]);
695             stringArray = bean.getStringArray();
696             assertNotNull("stringArray is present", stringArray);
697             assertEquals("stringArray length", 2, stringArray.length);
698             assertEquals("stringArray[0]", "New String 0", stringArray[0]);
699             assertEquals("stringArray[1]", "New String 1", stringArray[1]);
700 
701         } catch (final IllegalAccessException e) {
702             fail("IllegalAccessException");
703         } catch (final InvocationTargetException e) {
704             fail("InvocationTargetException");
705         }
706 
707     }
708 
709 
710     /**
711      * Test populate() on mapped properties.
712      */
713     public void testPopulateMapped() {
714 
715         try {
716 
717             final HashMap<String, Object> map = new HashMap<String, Object>();
718             map.put("mappedProperty(First Key)", "New First Value");
719             map.put("mappedProperty(Third Key)", "New Third Value");
720 
721             BeanUtils.populate(bean, map);
722 
723             assertEquals("mappedProperty(First Key)",
724                          "New First Value",
725                          bean.getMappedProperty("First Key"));
726             assertEquals("mappedProperty(Second Key)",
727                          "Second Value",
728                          bean.getMappedProperty("Second Key"));
729             assertEquals("mappedProperty(Third Key)",
730                          "New Third Value",
731                          bean.getMappedProperty("Third Key"));
732             assertNull("mappedProperty(Fourth Key",
733                        bean.getMappedProperty("Fourth Key"));
734 
735         } catch (final IllegalAccessException e) {
736             fail("IllegalAccessException");
737         } catch (final InvocationTargetException e) {
738             fail("InvocationTargetException");
739         }
740 
741     }
742 
743 
744     /**
745      * Test populate() method on nested properties.
746      */
747     public void testPopulateNested() {
748 
749         try {
750 
751             final HashMap<String, Object> map = new HashMap<String, Object>();
752             map.put("nested.booleanProperty", "false");
753             // booleanSecond is left at true
754             map.put("nested.doubleProperty", "432.0");
755             // floatProperty is left at 123.0
756             map.put("nested.intProperty", "543");
757             // longProperty is left at 321
758             map.put("nested.shortProperty", "654");
759             // stringProperty is left at "This is a string"
760             map.put("nested.writeOnlyProperty", "New writeOnlyProperty value");
761 
762             BeanUtils.populate(bean, map);
763 
764             assertTrue("booleanProperty is false",
765                        !bean.getNested().getBooleanProperty());
766             assertTrue("booleanSecond is true",
767                        bean.getNested().isBooleanSecond());
768             assertEquals("doubleProperty is 432.0",
769                          432.0,
770                          bean.getNested().getDoubleProperty(),
771                          0.005);
772             assertEquals("floatProperty is 123.0",
773                          (float) 123.0,
774                          bean.getNested().getFloatProperty(),
775                          (float) 0.005);
776             assertEquals("intProperty is 543",
777                          543, bean.getNested().getIntProperty());
778             assertEquals("longProperty is 321",
779                          321, bean.getNested().getLongProperty());
780             assertEquals("shortProperty is 654",
781                          (short) 654, bean.getNested().getShortProperty());
782             assertEquals("stringProperty is \"This is a string\"",
783                          "This is a string",
784                          bean.getNested().getStringProperty());
785             assertEquals("writeOnlyProperty is \"New writeOnlyProperty value\"",
786                          "New writeOnlyProperty value",
787                          bean.getNested().getWriteOnlyPropertyValue());
788 
789         } catch (final IllegalAccessException e) {
790             fail("IllegalAccessException");
791         } catch (final InvocationTargetException e) {
792             fail("InvocationTargetException");
793         }
794 
795     }
796 
797 
798     /**
799      * Test populate() method on scalar properties.
800      */
801     public void testPopulateScalar() {
802 
803         try {
804 
805             bean.setNullProperty("Non-null value");
806 
807             final HashMap<String, Object> map = new HashMap<String, Object>();
808             map.put("booleanProperty", "false");
809             // booleanSecond is left at true
810             map.put("byteProperty", "111");
811             map.put("doubleProperty", "432.0");
812             // floatProperty is left at 123.0
813             map.put("intProperty", "543");
814             map.put("longProperty", "");
815             map.put("nullProperty", null);
816             map.put("shortProperty", "654");
817             // stringProperty is left at "This is a string"
818             map.put("writeOnlyProperty", "New writeOnlyProperty value");
819             map.put("readOnlyProperty", "New readOnlyProperty value");
820 
821             BeanUtils.populate(bean, map);
822 
823             assertTrue("booleanProperty is false", !bean.getBooleanProperty());
824             assertTrue("booleanSecond is true", bean.isBooleanSecond());
825             assertEquals("byteProperty is 111",
826                          (byte) 111, bean.getByteProperty());
827             assertEquals("doubleProperty is 432.0",
828                          432.0, bean.getDoubleProperty(),
829                          0.005);
830             assertEquals("floatProperty is 123.0",
831                          (float) 123.0, bean.getFloatProperty(),
832                          (float) 0.005);
833             assertEquals("intProperty is 543",
834                          543, bean.getIntProperty());
835             assertEquals("longProperty is 0",
836                          0, bean.getLongProperty());
837             assertNull("nullProperty is null",
838                        bean.getNullProperty());
839             assertEquals("shortProperty is 654",
840                          (short) 654, bean.getShortProperty());
841             assertEquals("stringProperty is \"This is a string\"",
842                          "This is a string", bean.getStringProperty());
843             assertEquals("writeOnlyProperty is \"New writeOnlyProperty value\"",
844                          "New writeOnlyProperty value",
845                          bean.getWriteOnlyPropertyValue());
846             assertEquals("readOnlyProperty is \"Read Only String Property\"",
847                          "Read Only String Property",
848                          bean.getReadOnlyProperty());
849 
850         } catch (final IllegalAccessException e) {
851             fail("IllegalAccessException");
852         } catch (final InvocationTargetException e) {
853             fail("InvocationTargetException");
854         }
855 
856     }
857 
858 
859     /**
860      * Test calling setProperty() with null property values.
861      */
862     public void testSetPropertyNullValues() throws Exception {
863 
864         Object oldValue = null;
865         Object newValue = null;
866 
867         // Scalar value into array
868         oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
869         BeanUtils.setProperty(bean, "stringArray", (String) null);
870         newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
871         assertNotNull("stringArray is not null", newValue);
872         assertTrue("stringArray of correct type",
873                    newValue instanceof String[]);
874         assertEquals("stringArray length",
875                      1, ((String[]) newValue).length);
876         PropertyUtils.setProperty(bean, "stringArray", oldValue);
877 
878         // Indexed value into array
879         oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
880         BeanUtils.setProperty(bean, "stringArray[2]", (String) null);
881         newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
882         assertNotNull("stringArray is not null", newValue);
883         assertTrue("stringArray of correct type",
884                    newValue instanceof String[]);
885         assertEquals("stringArray length",
886                      5, ((String[]) newValue).length);
887         assertTrue("stringArray[2] is null",
888                    ((String[]) newValue)[2] == null);
889         PropertyUtils.setProperty(bean, "stringArray", oldValue);
890 
891         // Value into scalar
892         BeanUtils.setProperty(bean, "stringProperty", null);
893         assertTrue("stringProperty is now null",
894                    BeanUtils.getProperty(bean, "stringProperty") == null);
895 
896     }
897 
898 
899     /**
900      * Test converting to and from primitive wrapper types.
901      */
902     public void testSetPropertyOnPrimitiveWrappers() throws Exception {
903 
904         BeanUtils.setProperty(bean,"intProperty", new Integer(1));
905         assertEquals(1,bean.getIntProperty());
906         BeanUtils.setProperty(bean,"stringProperty", new Integer(1));
907         assertEquals(1, Integer.parseInt(bean.getStringProperty()));
908 
909     }
910 
911 
912     /**
913      * Test narrowing and widening conversions on byte.
914      */
915     public void testSetPropertyByte() throws Exception {
916 
917         BeanUtils.setProperty(bean, "byteProperty", new Byte((byte) 123));
918         assertEquals((byte) 123, bean.getByteProperty());
919 /*
920         BeanUtils.setProperty(bean, "byteProperty", new Double((double) 123));
921         assertEquals((byte) 123, bean.getByteProperty());
922         BeanUtils.setProperty(bean, "byteProperty", new Float((float) 123));
923         assertEquals((byte) 123, bean.getByteProperty());
924 */
925         BeanUtils.setProperty(bean, "byteProperty", new Integer(123));
926         assertEquals((byte) 123, bean.getByteProperty());
927         BeanUtils.setProperty(bean, "byteProperty", new Long(123));
928         assertEquals((byte) 123, bean.getByteProperty());
929         BeanUtils.setProperty(bean, "byteProperty", new Short((short) 123));
930         assertEquals((byte) 123, bean.getByteProperty());
931 
932     }
933 
934     /**
935      * Test <code>setProperty()</code> conversion.
936      */
937     public void testSetPropertyConvert() {
938         try {
939             BeanUtils.setProperty(bean, "dateProperty", testCalendar);
940         } catch (final Throwable t) {
941             fail("Threw " + t);
942         }
943         assertEquals("Calendar --> java.util.Date", testUtilDate, bean.getDateProperty());
944     }
945 
946     /**
947      * Test <code>setProperty()</code> converting from a String.
948      */
949     public void testSetPropertyConvertFromString() {
950         try {
951             BeanUtils.setProperty(bean, "dateProperty", testStringDate);
952         } catch (final Throwable t) {
953             fail("Threw " + t);
954         }
955         assertEquals("String --> java.util.Date", testUtilDate, bean.getDateProperty());
956     }
957 
958     /**
959      * Test <code>setProperty()</code> converting to a String.
960      */
961     public void testSetPropertyConvertToString() {
962         try {
963             BeanUtils.setProperty(bean, "stringProperty", testUtilDate);
964         } catch (final Throwable t) {
965             fail("Threw " + t);
966         }
967         assertEquals("java.util.Date --> String", testUtilDate.toString(), bean.getStringProperty());
968     }
969 
970     /**
971      * Test <code>setProperty()</code> converting to a String array.
972      */
973     public void testSetPropertyConvertToStringArray() {
974         try {
975             bean.setStringArray(null);
976             BeanUtils.setProperty(bean, "stringArray", new java.util.Date[] {testUtilDate});
977         } catch (final Throwable t) {
978             fail("Threw " + t);
979         }
980         assertEquals("java.util.Date[] --> String[] length", 1, bean.getStringArray().length);
981         assertEquals("java.util.Date[] --> String[] value ", testUtilDate.toString(), bean.getStringArray()[0]);
982     }
983 
984     /**
985      * Test <code>setProperty()</code> converting to a String on indexed property
986      */
987     public void testSetPropertyConvertToStringIndexed() {
988         try {
989             bean.setStringArray(new String[1]);
990             BeanUtils.setProperty(bean, "stringArray[0]", testUtilDate);
991         } catch (final Throwable t) {
992             fail("Threw " + t);
993         }
994         assertEquals("java.util.Date --> String[]", testUtilDate.toString(), bean.getStringArray()[0]);
995     }
996 
997     /**
998      * Test narrowing and widening conversions on double.
999      */
1000     public void testSetPropertyDouble() throws Exception {
1001 
1002         BeanUtils.setProperty(bean, "doubleProperty", new Byte((byte) 123));
1003         assertEquals(123, bean.getDoubleProperty(), 0.005);
1004         BeanUtils.setProperty(bean, "doubleProperty", new Double(123));
1005         assertEquals(123, bean.getDoubleProperty(), 0.005);
1006         BeanUtils.setProperty(bean, "doubleProperty", new Float(123));
1007         assertEquals(123, bean.getDoubleProperty(), 0.005);
1008         BeanUtils.setProperty(bean, "doubleProperty", new Integer(123));
1009         assertEquals(123, bean.getDoubleProperty(), 0.005);
1010         BeanUtils.setProperty(bean, "doubleProperty", new Long(123));
1011         assertEquals(123, bean.getDoubleProperty(), 0.005);
1012         BeanUtils.setProperty(bean, "doubleProperty", new Short((short) 123));
1013         assertEquals(123, bean.getDoubleProperty(), 0.005);
1014 
1015     }
1016 
1017 
1018     /**
1019      * Test narrowing and widening conversions on float.
1020      */
1021     public void testSetPropertyFloat() throws Exception {
1022 
1023         BeanUtils.setProperty(bean, "floatProperty", new Byte((byte) 123));
1024         assertEquals(123, bean.getFloatProperty(), 0.005);
1025         BeanUtils.setProperty(bean, "floatProperty", new Double(123));
1026         assertEquals(123, bean.getFloatProperty(), 0.005);
1027         BeanUtils.setProperty(bean, "floatProperty", new Float(123));
1028         assertEquals(123, bean.getFloatProperty(), 0.005);
1029         BeanUtils.setProperty(bean, "floatProperty", new Integer(123));
1030         assertEquals(123, bean.getFloatProperty(), 0.005);
1031         BeanUtils.setProperty(bean, "floatProperty", new Long(123));
1032         assertEquals(123, bean.getFloatProperty(), 0.005);
1033         BeanUtils.setProperty(bean, "floatProperty", new Short((short) 123));
1034         assertEquals(123, bean.getFloatProperty(), 0.005);
1035 
1036     }
1037 
1038 
1039     /**
1040      * Test narrowing and widening conversions on int.
1041      */
1042     public void testSetPropertyInteger() throws Exception {
1043 
1044         BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
1045         assertEquals(123, bean.getIntProperty());
1046 /*
1047         BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
1048         assertEquals((int) 123, bean.getIntProperty());
1049         BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
1050         assertEquals((int) 123, bean.getIntProperty());
1051 */
1052         BeanUtils.setProperty(bean, "longProperty", new Integer(123));
1053         assertEquals(123, bean.getIntProperty());
1054         BeanUtils.setProperty(bean, "longProperty", new Long(123));
1055         assertEquals(123, bean.getIntProperty());
1056         BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
1057         assertEquals(123, bean.getIntProperty());
1058 
1059     }
1060 
1061 
1062     /**
1063      * Test narrowing and widening conversions on long.
1064      */
1065     public void testSetPropertyLong() throws Exception {
1066 
1067         BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
1068         assertEquals(123, bean.getLongProperty());
1069 /*
1070         BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
1071         assertEquals((long) 123, bean.getLongProperty());
1072         BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
1073         assertEquals((long) 123, bean.getLongProperty());
1074 */
1075         BeanUtils.setProperty(bean, "longProperty", new Integer(123));
1076         assertEquals(123, bean.getLongProperty());
1077         BeanUtils.setProperty(bean, "longProperty", new Long(123));
1078         assertEquals(123, bean.getLongProperty());
1079         BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
1080         assertEquals(123, bean.getLongProperty());
1081 
1082     }
1083 
1084 
1085     /**
1086      * Test setting a null property value.
1087      */
1088     public void testSetPropertyNull() throws Exception {
1089 
1090         bean.setNullProperty("non-null value");
1091         BeanUtils.setProperty(bean, "nullProperty", null);
1092         assertNull("nullProperty is null", bean.getNullProperty());
1093 
1094     }
1095 
1096 
1097     /**
1098      * Test narrowing and widening conversions on short.
1099      */
1100     public void testSetPropertyShort() throws Exception {
1101 
1102         BeanUtils.setProperty(bean, "shortProperty", new Byte((byte) 123));
1103         assertEquals((short) 123, bean.getShortProperty());
1104 /*
1105         BeanUtils.setProperty(bean, "shortProperty", new Double((double) 123));
1106         assertEquals((short) 123, bean.getShortProperty());
1107         BeanUtils.setProperty(bean, "shortProperty", new Float((float) 123));
1108         assertEquals((short) 123, bean.getShortProperty());
1109 */
1110         BeanUtils.setProperty(bean, "shortProperty", new Integer(123));
1111         assertEquals((short) 123, bean.getShortProperty());
1112         BeanUtils.setProperty(bean, "shortProperty", new Long(123));
1113         assertEquals((short) 123, bean.getShortProperty());
1114         BeanUtils.setProperty(bean, "shortProperty", new Short((short) 123));
1115         assertEquals((short) 123, bean.getShortProperty());
1116 
1117     }
1118 
1119     /**
1120      * Test setting a String value to a String array property
1121      */
1122     public void testSetPropertyStringToArray() throws Exception {
1123         BeanUtils.setProperty(bean, "stringArray", "ABC,DEF,GHI");
1124         final String[] strArray =  bean.getStringArray();
1125         assertEquals("length", 3, strArray.length);
1126         assertEquals("value[0]", "ABC", strArray[0]);
1127         assertEquals("value[1]", "DEF", strArray[1]);
1128         assertEquals("value[2]", "GHI", strArray[2]);
1129 
1130         BeanUtils.setProperty(bean, "intArray", "0, 10, 20, 30, 40");
1131         final int[] intArray =  bean.getIntArray();
1132         assertEquals("length", 5, intArray.length);
1133         assertEquals("value[0]", 0, intArray[0]);
1134         assertEquals("value[1]", 10, intArray[1]);
1135         assertEquals("value[2]", 20, intArray[2]);
1136         assertEquals("value[3]", 30, intArray[3]);
1137         assertEquals("value[4]", 40, intArray[4]);
1138     }
1139 
1140 
1141     /**
1142      * Test narrowing and widening conversions on byte.
1143      */
1144     public void testCopyPropertyByte() throws Exception {
1145 
1146         BeanUtils.copyProperty(bean, "byteProperty", new Byte((byte) 123));
1147         assertEquals((byte) 123, bean.getByteProperty());
1148         BeanUtils.copyProperty(bean, "byteProperty", new Double(123));
1149         assertEquals((byte) 123, bean.getByteProperty());
1150         BeanUtils.copyProperty(bean, "byteProperty", new Float(123));
1151         assertEquals((byte) 123, bean.getByteProperty());
1152         BeanUtils.copyProperty(bean, "byteProperty", new Integer(123));
1153         assertEquals((byte) 123, bean.getByteProperty());
1154         BeanUtils.copyProperty(bean, "byteProperty", new Long(123));
1155         assertEquals((byte) 123, bean.getByteProperty());
1156         BeanUtils.copyProperty(bean, "byteProperty", new Short((short) 123));
1157         assertEquals((byte) 123, bean.getByteProperty());
1158 
1159     }
1160 
1161     /**
1162      * Test <code>copyProperty()</code> conversion.
1163      */
1164     public void testCopyPropertyConvert() {
1165         try {
1166             BeanUtils.copyProperty(bean, "dateProperty", testCalendar);
1167         } catch (final Throwable t) {
1168             fail("Threw " + t);
1169         }
1170         assertEquals("Calendar --> java.util.Date", testUtilDate, bean.getDateProperty());
1171     }
1172 
1173     /**
1174      * Test <code>copyProperty()</code> converting from a String.
1175      */
1176     public void testCopyPropertyConvertFromString() {
1177         try {
1178             BeanUtils.copyProperty(bean, "dateProperty", testStringDate);
1179         } catch (final Throwable t) {
1180             fail("Threw " + t);
1181         }
1182         assertEquals("String --> java.util.Date", testUtilDate, bean.getDateProperty());
1183     }
1184 
1185     /**
1186      * Test <code>copyProperty()</code> converting to a String.
1187      */
1188     public void testCopyPropertyConvertToString() {
1189         try {
1190             BeanUtils.copyProperty(bean, "stringProperty", testUtilDate);
1191         } catch (final Throwable t) {
1192             fail("Threw " + t);
1193         }
1194         assertEquals("java.util.Date --> String", testUtilDate.toString(), bean.getStringProperty());
1195     }
1196 
1197     /**
1198      * Test <code>copyProperty()</code> converting to a String.
1199      */
1200     public void testCopyPropertyConvertToStringArray() {
1201         try {
1202             bean.setStringArray(null);
1203             BeanUtils.copyProperty(bean, "stringArray", new java.util.Date[] {testUtilDate});
1204         } catch (final Throwable t) {
1205             fail("Threw " + t);
1206         }
1207         assertEquals("java.util.Date[] --> String[] length", 1, bean.getStringArray().length);
1208         assertEquals("java.util.Date[] --> String[] value ", testUtilDate.toString(), bean.getStringArray()[0]);
1209     }
1210 
1211     /**
1212      * Test <code>copyProperty()</code> converting to a String on indexed property
1213      */
1214     public void testCopyPropertyConvertToStringIndexed() {
1215         try {
1216             bean.setStringArray(new String[1]);
1217             BeanUtils.copyProperty(bean, "stringArray[0]", testUtilDate);
1218         } catch (final Throwable t) {
1219             fail("Threw " + t);
1220         }
1221         assertEquals("java.util.Date --> String[]", testUtilDate.toString(), bean.getStringArray()[0]);
1222     }
1223 
1224     /**
1225      * Test narrowing and widening conversions on double.
1226      */
1227     public void testCopyPropertyDouble() throws Exception {
1228 
1229         BeanUtils.copyProperty(bean, "doubleProperty", new Byte((byte) 123));
1230         assertEquals(123, bean.getDoubleProperty(), 0.005);
1231         BeanUtils.copyProperty(bean, "doubleProperty", new Double(123));
1232         assertEquals(123, bean.getDoubleProperty(), 0.005);
1233         BeanUtils.copyProperty(bean, "doubleProperty", new Float(123));
1234         assertEquals(123, bean.getDoubleProperty(), 0.005);
1235         BeanUtils.copyProperty(bean, "doubleProperty", new Integer(123));
1236         assertEquals(123, bean.getDoubleProperty(), 0.005);
1237         BeanUtils.copyProperty(bean, "doubleProperty", new Long(123));
1238         assertEquals(123, bean.getDoubleProperty(), 0.005);
1239         BeanUtils.copyProperty(bean, "doubleProperty", new Short((short) 123));
1240         assertEquals(123, bean.getDoubleProperty(), 0.005);
1241 
1242     }
1243 
1244 
1245     /**
1246      * Test narrowing and widening conversions on float.
1247      */
1248     public void testCopyPropertyFloat() throws Exception {
1249 
1250         BeanUtils.copyProperty(bean, "floatProperty", new Byte((byte) 123));
1251         assertEquals(123, bean.getFloatProperty(), 0.005);
1252         BeanUtils.copyProperty(bean, "floatProperty", new Double(123));
1253         assertEquals(123, bean.getFloatProperty(), 0.005);
1254         BeanUtils.copyProperty(bean, "floatProperty", new Float(123));
1255         assertEquals(123, bean.getFloatProperty(), 0.005);
1256         BeanUtils.copyProperty(bean, "floatProperty", new Integer(123));
1257         assertEquals(123, bean.getFloatProperty(), 0.005);
1258         BeanUtils.copyProperty(bean, "floatProperty", new Long(123));
1259         assertEquals(123, bean.getFloatProperty(), 0.005);
1260         BeanUtils.copyProperty(bean, "floatProperty", new Short((short) 123));
1261         assertEquals(123, bean.getFloatProperty(), 0.005);
1262 
1263     }
1264 
1265 
1266     /**
1267      * Test narrowing and widening conversions on int.
1268      */
1269     public void testCopyPropertyInteger() throws Exception {
1270 
1271         BeanUtils.copyProperty(bean, "longProperty", new Byte((byte) 123));
1272         assertEquals(123, bean.getIntProperty());
1273         BeanUtils.copyProperty(bean, "longProperty", new Double(123));
1274         assertEquals(123, bean.getIntProperty());
1275         BeanUtils.copyProperty(bean, "longProperty", new Float(123));
1276         assertEquals(123, bean.getIntProperty());
1277         BeanUtils.copyProperty(bean, "longProperty", new Integer(123));
1278         assertEquals(123, bean.getIntProperty());
1279         BeanUtils.copyProperty(bean, "longProperty", new Long(123));
1280         assertEquals(123, bean.getIntProperty());
1281         BeanUtils.copyProperty(bean, "longProperty", new Short((short) 123));
1282         assertEquals(123, bean.getIntProperty());
1283 
1284     }
1285 
1286 
1287     /**
1288      * Test narrowing and widening conversions on long.
1289      */
1290     public void testCopyPropertyLong() throws Exception {
1291 
1292         BeanUtils.copyProperty(bean, "longProperty", new Byte((byte) 123));
1293         assertEquals(123, bean.getLongProperty());
1294         BeanUtils.copyProperty(bean, "longProperty", new Double(123));
1295         assertEquals(123, bean.getLongProperty());
1296         BeanUtils.copyProperty(bean, "longProperty", new Float(123));
1297         assertEquals(123, bean.getLongProperty());
1298         BeanUtils.copyProperty(bean, "longProperty", new Integer(123));
1299         assertEquals(123, bean.getLongProperty());
1300         BeanUtils.copyProperty(bean, "longProperty", new Long(123));
1301         assertEquals(123, bean.getLongProperty());
1302         BeanUtils.copyProperty(bean, "longProperty", new Short((short) 123));
1303         assertEquals(123, bean.getLongProperty());
1304 
1305     }
1306 
1307 
1308     /**
1309      * Test narrowing and widening conversions on short.
1310      */
1311     public void testCopyPropertyShort() throws Exception {
1312 
1313         BeanUtils.copyProperty(bean, "shortProperty", new Byte((byte) 123));
1314         assertEquals((short) 123, bean.getShortProperty());
1315         BeanUtils.copyProperty(bean, "shortProperty", new Double(123));
1316         assertEquals((short) 123, bean.getShortProperty());
1317         BeanUtils.copyProperty(bean, "shortProperty", new Float(123));
1318         assertEquals((short) 123, bean.getShortProperty());
1319         BeanUtils.copyProperty(bean, "shortProperty", new Integer(123));
1320         assertEquals((short) 123, bean.getShortProperty());
1321         BeanUtils.copyProperty(bean, "shortProperty", new Long(123));
1322         assertEquals((short) 123, bean.getShortProperty());
1323         BeanUtils.copyProperty(bean, "shortProperty", new Short((short) 123));
1324         assertEquals((short) 123, bean.getShortProperty());
1325 
1326     }
1327 
1328 
1329     /**
1330      * Test copying a property using a nested indexed array expression,
1331      * with and without conversions.
1332      */
1333     public void testCopyPropertyNestedIndexedArray() throws Exception {
1334 
1335         final int origArray[] = { 0, 10, 20, 30, 40 };
1336         final int intArray[] = { 0, 0, 0 };
1337         bean.getNested().setIntArray(intArray);
1338         final int intChanged[] = { 0, 0, 0 };
1339 
1340         // No conversion required
1341         BeanUtils.copyProperty(bean, "nested.intArray[1]", new Integer(1));
1342         checkIntArray(bean.getIntArray(), origArray);
1343         intChanged[1] = 1;
1344         checkIntArray(bean.getNested().getIntArray(), intChanged);
1345 
1346         // Widening conversion required
1347         BeanUtils.copyProperty(bean, "nested.intArray[1]", new Byte((byte) 2));
1348         checkIntArray(bean.getIntArray(), origArray);
1349         intChanged[1] = 2;
1350         checkIntArray(bean.getNested().getIntArray(), intChanged);
1351 
1352         // Narrowing conversion required
1353         BeanUtils.copyProperty(bean, "nested.intArray[1]", new Long(3));
1354         checkIntArray(bean.getIntArray(), origArray);
1355         intChanged[1] = 3;
1356         checkIntArray(bean.getNested().getIntArray(), intChanged);
1357 
1358         // String conversion required
1359         BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
1360         checkIntArray(bean.getIntArray(), origArray);
1361         intChanged[1] = 4;
1362         checkIntArray(bean.getNested().getIntArray(), intChanged);
1363 
1364     }
1365 
1366 
1367     /**
1368      * Test copying a property using a nested mapped map property.
1369      */
1370     public void testCopyPropertyNestedMappedMap() throws Exception {
1371 
1372         final Map<String, Object> origMap = new HashMap<String, Object>();
1373         origMap.put("First Key", "First Value");
1374         origMap.put("Second Key", "Second Value");
1375         final Map<String, Object> changedMap = new HashMap<String, Object>();
1376         changedMap.put("First Key", "First Value");
1377         changedMap.put("Second Key", "Second Value");
1378 
1379         // No conversion required
1380         BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)",
1381                                "New Second Value");
1382         checkMap(bean.getMapProperty(), origMap);
1383         changedMap.put("Second Key", "New Second Value");
1384         checkMap(bean.getNested().getMapProperty(), changedMap);
1385 
1386     }
1387 
1388 
1389     /**
1390      * Test copying a property using a nested simple expression, with and
1391      * without conversions.
1392      */
1393     public void testCopyPropertyNestedSimple() throws Exception {
1394 
1395         bean.setIntProperty(0);
1396         bean.getNested().setIntProperty(0);
1397 
1398         // No conversion required
1399         BeanUtils.copyProperty(bean, "nested.intProperty", new Integer(1));
1400         assertNotNull(bean.getNested());
1401         assertEquals(0, bean.getIntProperty());
1402         assertEquals(1, bean.getNested().getIntProperty());
1403 
1404         // Widening conversion required
1405         BeanUtils.copyProperty(bean, "nested.intProperty", new Byte((byte) 2));
1406         assertNotNull(bean.getNested());
1407         assertEquals(0, bean.getIntProperty());
1408         assertEquals(2, bean.getNested().getIntProperty());
1409 
1410         // Narrowing conversion required
1411         BeanUtils.copyProperty(bean, "nested.intProperty", new Long(3));
1412         assertNotNull(bean.getNested());
1413         assertEquals(0, bean.getIntProperty());
1414         assertEquals(3, bean.getNested().getIntProperty());
1415 
1416         // String conversion required
1417         BeanUtils.copyProperty(bean, "nested.intProperty", "4");
1418         assertNotNull(bean.getNested());
1419         assertEquals(0, bean.getIntProperty());
1420         assertEquals(4, bean.getNested().getIntProperty());
1421 
1422     }
1423 
1424 
1425     /**
1426      * Test copying a null property value.
1427      */
1428     public void testCopyPropertyNull() throws Exception {
1429 
1430         bean.setNullProperty("non-null value");
1431         BeanUtils.copyProperty(bean, "nullProperty", null);
1432         assertNull("nullProperty is null", bean.getNullProperty());
1433 
1434     }
1435 
1436 
1437     /**
1438      * Test copying a new value to a write-only property, with and without
1439      * conversions.
1440      */
1441     public void testCopyPropertyWriteOnly() throws Exception {
1442 
1443         bean.setWriteOnlyProperty("Original value");
1444 
1445         // No conversion required
1446         BeanUtils.copyProperty(bean, "writeOnlyProperty", "New value");
1447         assertEquals("New value", bean.getWriteOnlyPropertyValue());
1448 
1449         // Integer->String conversion required
1450         BeanUtils.copyProperty(bean, "writeOnlyProperty", new Integer(123));
1451         assertEquals("123", bean.getWriteOnlyPropertyValue());
1452 
1453     }
1454 
1455 
1456     /**
1457      * Test setting a new value to a write-only property, with and without
1458      * conversions.
1459      */
1460     public void testSetPropertyWriteOnly() throws Exception {
1461 
1462         bean.setWriteOnlyProperty("Original value");
1463 
1464         // No conversion required
1465         BeanUtils.setProperty(bean, "writeOnlyProperty", "New value");
1466         assertEquals("New value", bean.getWriteOnlyPropertyValue());
1467 
1468         // Integer->String conversion required
1469         BeanUtils.setProperty(bean, "writeOnlyProperty", new Integer(123));
1470         assertEquals("123", bean.getWriteOnlyPropertyValue());
1471 
1472     }
1473 
1474     /**
1475      * Test setting a value out of a mapped Map
1476      */
1477     public void testSetMappedMap() {
1478         final TestBean bean = new TestBean();
1479         final Map<String, Object> map = new HashMap<String, Object>();
1480         map.put("sub-key-1", "sub-value-1");
1481         map.put("sub-key-2", "sub-value-2");
1482         map.put("sub-key-3", "sub-value-3");
1483         bean.getMapProperty().put("mappedMap", map);
1484 
1485         assertEquals("BEFORE", "sub-value-3", ((Map<?, ?>)bean.getMapProperty().get("mappedMap")).get("sub-key-3"));
1486         try {
1487             BeanUtils.setProperty(bean, "mapProperty(mappedMap)(sub-key-3)", "SUB-KEY-3-UPDATED");
1488         } catch (final Throwable t) {
1489             fail("Threw " + t + "");
1490         }
1491         assertEquals("AFTER", "SUB-KEY-3-UPDATED", ((Map<?, ?>)bean.getMapProperty().get("mappedMap")).get("sub-key-3"));
1492     }
1493 
1494     /** Tests that separate instances can register separate instances */
1495     public void testSeparateInstances() throws Exception {
1496         final BeanUtilsBean utilsOne = new BeanUtilsBean(
1497                                                 new ConvertUtilsBean(),
1498                                                 new PropertyUtilsBean());
1499         final BeanUtilsBean utilsTwo = new BeanUtilsBean(
1500                                                 new ConvertUtilsBean(),
1501                                                 new PropertyUtilsBean());
1502 
1503 
1504         final TestBean bean = new TestBean();
1505 
1506         // Make sure what we're testing works
1507         bean.setBooleanProperty(false);
1508         utilsOne.setProperty(bean, "booleanProperty", "true");
1509         assertEquals("Set property failed (1)", bean.getBooleanProperty(), true);
1510 
1511         bean.setBooleanProperty(false);
1512         utilsTwo.setProperty(bean, "booleanProperty", "true");
1513         assertEquals("Set property failed (2)", bean.getBooleanProperty(), true);
1514 
1515         // now change the registered conversion
1516 
1517         utilsOne.getConvertUtils().register(new ThrowExceptionConverter(), Boolean.TYPE);
1518         try {
1519 
1520             bean.setBooleanProperty(false);
1521             utilsOne.setProperty(bean, "booleanProperty", "true");
1522             fail("Registered conversion not used.");
1523 
1524         } catch (final PassTestException e) { /* Do nothing */ }
1525 
1526         // make sure that this conversion has no been registered in the other instance
1527         try {
1528 
1529             bean.setBooleanProperty(false);
1530             utilsTwo.setProperty(bean, "booleanProperty", "true");
1531             assertEquals("Set property failed (3)", bean.getBooleanProperty(), true);
1532 
1533         } catch (final PassTestException e) {
1534             fail("Registed converter is used by other instances");
1535         }
1536     }
1537 
1538     public void testArrayPropertyConversion() throws Exception {
1539         final BeanUtilsBean beanUtils = new BeanUtilsBean(
1540                                                     new ConvertUtilsBean(),
1541                                                     new PropertyUtilsBean());
1542 
1543         final TestBean bean = new TestBean();
1544         final String [] results = beanUtils.getArrayProperty(bean, "intArray");
1545 
1546         final int[] values = bean.getIntArray();
1547         assertEquals(
1548                     "Converted array size not equal to property array size.",
1549                     results.length,
1550                     values.length);
1551         for (int i=0, size=values.length ;  i<size; i++) {
1552             assertEquals(
1553                     "Value " + i + " incorrectly converted ",
1554                     values[i] + "",
1555                     results[i]);
1556         }
1557     }
1558 
1559     // Ensure that the actual int[] matches the expected int[]
1560     protected void checkIntArray(final int actual[], final int expected[]) {
1561         assertNotNull("actual array not null", actual);
1562         assertEquals("actual array length", expected.length, actual.length);
1563         for (int i = 0; i < actual.length; i++) {
1564             assertEquals("actual array value[" + i + "]",
1565                          expected[i], actual[i]);
1566         }
1567     }
1568 
1569 
1570     // Ensure that the actual Map matches the expected Map
1571     protected void checkMap(final Map<?, ?> actual, final Map<?, ?> expected) {
1572         assertNotNull("actual map not null", actual);
1573         assertEquals("actual map size", expected.size(), actual.size());
1574         final Iterator<?> keys = expected.keySet().iterator();
1575         while (keys.hasNext()) {
1576             final Object key = keys.next();
1577             assertEquals("actual map value(" + key + ")",
1578                          expected.get(key), actual.get(key));
1579         }
1580     }
1581 
1582     public void testMappedProperty() throws Exception {
1583         final MappedPropertyTestBean bean = new MappedPropertyTestBean();
1584 
1585         BeanUtils.setProperty(bean, "mapproperty(this.that.the-other)", "some.dotty.value");
1586 
1587         assertEquals(
1588                         "Mapped property set correctly",
1589                         "some.dotty.value",
1590                         bean.getMapproperty("this.that.the-other"));
1591     }
1592 
1593     /**
1594      * Test for {@link BeanUtilsBean#initCause(Throwable, Throwable)} method.
1595      */
1596     public void testInitCause() {
1597         if (isPre14JVM()) {
1598             return;
1599         }
1600         final String parentMsg = "PARENT-THROWABLE";
1601         final String causeMsg  = "THROWABLE-CAUSE";
1602         try {
1603             initCauseAndThrowException(parentMsg, causeMsg);
1604         } catch (final Throwable thrownParent) {
1605             assertEquals("Parent", parentMsg, thrownParent.getMessage());
1606             try {
1607                 assertEquals("Parent", parentMsg, thrownParent.getMessage());
1608                 final Throwable thrownCause = getCause(thrownParent);
1609                 assertNotNull("Cause Null", thrownCause);
1610                 assertEquals("Cause", causeMsg, thrownCause.getMessage());
1611             } catch (final Throwable testError) {
1612                 fail("If you're running JDK 1.3 then don't worry this should fail," +
1613                         " if not then needs checking out: " + testError);
1614             }
1615         }
1616     }
1617 
1618     /**
1619      * Use reflection to get the cause
1620      */
1621     private Throwable getCause(final Throwable t) throws Throwable {
1622         return (Throwable)PropertyUtils.getProperty(t, "cause");
1623     }
1624 
1625     /**
1626      * Catch a cause, initialize using BeanUtils.initCause() and throw new exception
1627      */
1628     private void initCauseAndThrowException(final String parent, final String cause) throws Throwable {
1629         try {
1630             throwException(cause);
1631         } catch (final Throwable e) {
1632             final Throwable t = new Exception(parent);
1633             BeanUtils.initCause(t, e);
1634             throw t;
1635         }
1636     }
1637 
1638     /**
1639      * Throw an exception with the specified message.
1640      */
1641     private void throwException(final String msg) throws Throwable {
1642         throw new Exception(msg);
1643     }
1644 
1645     /**
1646      * Test for JDK 1.4
1647      */
1648     public static boolean isPre14JVM() {
1649         final String version = System.getProperty("java.specification.version");
1650         final StringTokenizer tokenizer = new StringTokenizer(version,".");
1651         if (tokenizer.nextToken().equals("1")) {
1652             final String minorVersion = tokenizer.nextToken();
1653             if (minorVersion.equals("0")) {
1654                 return true;
1655             }
1656             if (minorVersion.equals("1")) {
1657                 return true;
1658             }
1659             if (minorVersion.equals("2")) {
1660                 return true;
1661             }
1662             if (minorVersion.equals("3")) {
1663                 return true;
1664             }
1665         }
1666         return false;
1667     }
1668 }