    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
    19  package org.apache.commons.beanutils;
    20
    21
    22  import java.math.BigDecimal;
    23  import java.sql.Date;
    24  import java.sql.ResultSet;
    25  import java.sql.ResultSetMetaData;
    26  import java.sql.SQLException;
    27  import java.sql.Timestamp;
    28  import java.sql.Types;
    29  import java.util.List;
    30
    31  import junit.framework.TestCase;
    32  import junit.framework.Test;
    33  import junit.framework.TestSuite;
    34
    35
    36  /***
    37   * Test accessing RowSets via DynaBeans.
    38   *
    39   * @author Craig R. McClanahan
    40   * @version $Revision: 556233 $ $Date: 2007-07-14 07:37:06 +0100 (Sat, 14 Jul 2007) $
    41   */
    42
    43  public class DynaRowSetTestCase extends TestCase {
    44
    45
    46      // ----------------------------------------------------- Instance Variables
    47
    48
    49      /***
    50       * The mock result set DynaClass to be tested.
    51       */
    52      protected RowSetDynaClass dynaClass = null;
    53
    54
    55      /***
    56       * Names of the columns for this test.  Must match the order they are
    57       * defined in {@link TestResultSetMetaData}, and must be all lower case.
    58       */
    59      protected String columns[] =
    60      { "bigdecimalproperty", "booleanproperty",
    61        "byteproperty", "dateproperty",
    62        "doubleproperty", "floatproperty",
    63        "intproperty", "longproperty",
    64        "nullproperty", "shortproperty",
    65        "stringproperty", "timeproperty",
    66        "timestampproperty" };
    67
    68
    69      // ----------------------------------------------------------- Constructors
    70
    71
    72      /***
    73       * Construct a new instance of this test case.
    74       *
    75       * @param name Name of the test case
    76       */
    77      public DynaRowSetTestCase(String name) {
    78
    79          super(name);
    80
    81      }
    82
    83
    84      // --------------------------------------------------- Overall Test Methods
    85
    86
    87      /***
    88       * Set up instance variables required by this test case.
    89       */
    90      public void setUp() throws Exception {
    91
    92          dynaClass = new RowSetDynaClass(TestResultSet.createProxy());
    93
    94      }
    95
    96
    97      /***
    98       * Return the tests included in this test suite.
    99       */
    100     public static Test suite() {
    101
    102         return (new TestSuite(DynaRowSetTestCase.class));
    103
    104     }
    105
    106
    107     /***
    108      * Tear down instance variables required by this test case.
    109      */
    110     public void tearDown() {
    111
    112         dynaClass = null;
    113
    114     }
    115
    116
    117
    118     // ------------------------------------------------ Individual Test Methods
    119
    120
    121     public void testGetName() {
    122
    123         assertEquals("DynaClass name",
    124                      "org.apache.commons.beanutils.RowSetDynaClass",
    125                      dynaClass.getName());
    126
    127
    128     }
    129
    130
    131     public void testGetDynaProperty() {
    132
    133         // Invalid argument test
    134         try {
    135             dynaClass.getDynaProperty(null);
    136             fail("Did not throw IllegaArgumentException");
    137         } catch (IllegalArgumentException e) {
    138             // Expected result
    139         }
    140
    141         // Negative test
    142         DynaProperty dynaProp = dynaClass.getDynaProperty("unknownProperty");
    143         assertTrue("unknown property returns null",
    144                    (dynaProp == null));
    145
    146         // Positive test
    147         dynaProp = dynaClass.getDynaProperty("stringproperty");
    148         assertNotNull("string property exists", dynaProp);
    149         assertEquals("string property name", "stringproperty",
    150                      dynaProp.getName());
    151         assertEquals("string property class", String.class,
    152                      dynaProp.getType());
    153
    154     }
    155
    156
    157     public void testGetDynaProperties() {
    158
    159         DynaProperty dynaProps[] = dynaClass.getDynaProperties();
    160         assertNotNull("dynaProps exists", dynaProps);
    161         assertEquals("dynaProps length", columns.length, dynaProps.length);
    162         for (int i = 0; i < columns.length; i++) {
    163             assertEquals("Property " + columns[i],
    164                          columns[i], dynaProps[i].getName());
    165         }
    166
    167     }
    168
    169
    170     public void testNewInstance() {
    171
    172         try {
    173             dynaClass.newInstance();
    174             fail("Did not throw UnsupportedOperationException()");
    175         } catch (UnsupportedOperationException e) {
    176             // Expected result
    177         } catch (Exception e) {
    178             fail("Threw exception " + e);
    179         }
    180
    181     }
    182
    183
    184     public void testListCount() {
    185
    186         List rows = dynaClass.getRows();
    187         assertNotNull("list exists", rows);
    188         assertEquals("list row count", 5, rows.size());
    189
    190     }
    191
    192
    193     public void testListResults() {
    194
    195         // Grab the third row
    196         List rows = dynaClass.getRows();
    197         DynaBean row = (DynaBean) rows.get(2);
    198
    199         // Invalid argument test
    200         try {
    201             row.get("unknownProperty");
    202             fail("Did not throw IllegalArgumentException");
    203         } catch (IllegalArgumentException e) {
    204             // Expected result
    205         }
    206
    207         // Verify property values
    208
    209         Object bigDecimalProperty = row.get("bigdecimalproperty");
    210         assertNotNull("bigDecimalProperty exists", bigDecimalProperty);
    211         assertTrue("bigDecimalProperty type",
    212                    bigDecimalProperty instanceof BigDecimal);
    213         assertEquals("bigDecimalProperty value",
    214                      123.45,
    215                      ((BigDecimal) bigDecimalProperty).doubleValue(),
    216                      0.005);
    217
    218         Object intProperty = row.get("intproperty");
    219         assertNotNull("intProperty exists", intProperty);
    220         assertTrue("intProperty type",
    221                    intProperty instanceof Integer);
    222         assertEquals("intProperty value",
    223                      103,
    224                      ((Integer) intProperty).intValue());
    225
    226         Object nullProperty = row.get("nullproperty");
    227         assertNull("nullProperty null", nullProperty);
    228
    229         Object stringProperty = row.get("stringproperty");
    230         assertNotNull("stringProperty exists", stringProperty);
    231         assertTrue("stringProperty type",
    232                    stringProperty instanceof String);
    233         assertEquals("stringProperty value",
    234                      "This is a string",
    235                      (String) stringProperty);
    236
    237
    238     }
    239
    240     /***
    241      * Test normal case column names (i.e. not converted to lower case)
    242      */
    243     public void testListResultsNormalCase() {
    244         RowSetDynaClass dynaClass = null;
    245         try {
    246             dynaClass = new RowSetDynaClass(TestResultSet.createProxy(), false);
    247         } catch (Exception e) {
    248             fail("Error creating RowSetDynaClass: " + e);
    249         }
    250
    251         // Grab the third row
    252         List rows = dynaClass.getRows();
    253         DynaBean row = (DynaBean) rows.get(2);
    254
    255         // Invalid argument test
    256         try {
    257             row.get("unknownProperty");
    258             fail("Did not throw IllegalArgumentException");
    259         } catch (IllegalArgumentException e) {
    260             // Expected result
    261         }
    262
    263         // Verify property values
    264
    265         Object bigDecimalProperty = row.get("bigDecimalProperty");
    266         assertNotNull("bigDecimalProperty exists", bigDecimalProperty);
    267         assertTrue("bigDecimalProperty type",
    268                    bigDecimalProperty instanceof BigDecimal);
    269         assertEquals("bigDecimalProperty value",
    270                      123.45,
    271                      ((BigDecimal) bigDecimalProperty).doubleValue(),
    272                      0.005);
    273
    274         Object intProperty = row.get("intProperty");
    275         assertNotNull("intProperty exists", intProperty);
    276         assertTrue("intProperty type",
    277                    intProperty instanceof Integer);
    278         assertEquals("intProperty value",
    279                      103,
    280                      ((Integer) intProperty).intValue());
    281
    282         Object nullProperty = row.get("nullProperty");
    283         assertNull("nullProperty null", nullProperty);
    284
    285         Object stringProperty = row.get("stringProperty");
    286         assertNotNull("stringProperty exists", stringProperty);
    287         assertTrue("stringProperty type",
    288                    stringProperty instanceof String);
    289         assertEquals("stringProperty value",
    290                      "This is a string",
    291                      (String) stringProperty);
    292
    293
    294     }
    295
    296     public void testLimitedRows() throws Exception {
    297
    298         // created one with low limit
    299         RowSetDynaClass limitedDynaClass = new RowSetDynaClass(TestResultSet.createProxy(), 3);
    300         List rows = limitedDynaClass.getRows();
    301         assertNotNull("list exists", rows);
    302         assertEquals("limited row count", 3, rows.size());
    303
    304     }
    305
    306     /***
    307      * Test issues associated with Oracle JDBC driver.
    308      *
    309      * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142
    310      *
    311      * @throws Exception if an error occurs
    312      */
    313     public void testInconsistentOracleDriver() throws Exception {
    314
    315         ResultSetMetaData metaData = TestResultSetMetaData.createProxy(new TestResultSetMetaDataInconsistent());
    316         ResultSet resultSet = TestResultSet.createProxy(new TestResultSetInconsistent(metaData));
    317
    318         // Date Column returns "java.sql.Timestamp" for the column class name but ResultSet getObject
    319         // returns a java.sql.Date value
    320         int dateColIdx = 4;
    321         assertEquals("Date Meta Name",       "dateProperty",       metaData.getColumnName(dateColIdx));
    322         assertEquals("Date Meta Class",      "java.sql.Timestamp", metaData.getColumnClassName(dateColIdx));
    323         assertEquals("Date Meta Type",       java.sql.Types.DATE,  metaData.getColumnType(dateColIdx));
    324         assertEquals("Date ResultSet Value", java.sql.Date.class,  resultSet.getObject("dateProperty").getClass());
    325
    326         // Timestamp column class returns a custom Timestamp impl for the column class name and ResultSet getObject
    327         int timestampColIdx = 13;
    328         assertEquals("Timestamp Meta Name",       "timestampProperty",             metaData.getColumnName(timestampColIdx));
    329         assertEquals("Timestamp Meta Class",      CustomTimestamp.class.getName(), metaData.getColumnClassName(timestampColIdx));
    330         assertEquals("Timestamp Meta Type",       java.sql.Types.TIMESTAMP,        metaData.getColumnType(timestampColIdx));
    331         assertEquals("Timestamp ResultSet Value", CustomTimestamp.class,           resultSet.getObject("timestampProperty").getClass());
    332
    333         RowSetDynaClass inconsistentDynaClass = new RowSetDynaClass(resultSet);
    334         DynaBean firstRow = (DynaBean)inconsistentDynaClass.getRows().get(0);
    335         Class expectedType = null;
    336         DynaProperty property = null;
    337
    338         // Test Date
    339         property = firstRow.getDynaClass().getDynaProperty("dateproperty");
    340         expectedType = java.sql.Date.class;
    341         assertEquals("Date Class", expectedType, property.getType());
    342         assertEquals("Date Value", expectedType, firstRow.get(property.getName()).getClass());
    343
    344         // Test Timestamp
    345         property = firstRow.getDynaClass().getDynaProperty("timestampproperty");
    346         expectedType = java.sql.Timestamp.class;
    347         assertEquals("Timestamp Class", expectedType, property.getType());
    348         assertEquals("Timestamp Value", expectedType, firstRow.get(property.getName()).getClass());
    349     }
    350
    351     /***
    352      * A proxy ResultSet implementation that returns Timstamp for a date column.
    353      *
    354      * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142
    355      */
    356     private static class TestResultSetInconsistent extends  TestResultSet {
    357
    358         public TestResultSetInconsistent(ResultSetMetaData metaData) {
    359             super(metaData);
    360         }
    361         /***
    362          * Get an columns's value
    363          * @param columnName Name of the column
    364          * @return the column value
    365          * @throws SQLException if an error occurs
    366          */
    367         public Object getObject(String columnName) throws SQLException {
    368             if ("timestampProperty".equals(columnName)) {
    369                 return new CustomTimestamp();
    370             } else {
    371                 return super.getObject(columnName);
    372             }
    373         }
    374
    375     }
    376
    377     /***
    378      * A proxy ResultSetMetaData implementation that returns a class name that
    379      * is inconsistent with the type returned by the ResultSet.getObject() method.
    380      *
    381      * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142
    382      */
    383     private static class TestResultSetMetaDataInconsistent extends  TestResultSetMetaData {
    384
    385         /***
    386          * This method substitues class names of "java.sql.Timestamp" with
    387          * "java.sql.Date" to test inconsistent JDBC drivers.
    388          *
    389          * @param columnIndex The column index
    390          * @return The column class name
    391          * @throws SQLException if an error occurs
    392          */
    393         public String getColumnClassName(int columnIndex) throws SQLException {
    394             String columnName = getColumnName(columnIndex);
    395             if (columnName.equals("dateProperty")) {
    396                 return java.sql.Timestamp.class.getName();
    397             } else if (columnName.equals("timestampProperty")) {
    398                 return CustomTimestamp.class.getName();
    399             } else {
    400                 return super.getColumnClassName(columnIndex);
    401             }
    402         }
    403     }
    404     private static class CustomTimestamp {
    405         private long timestamp = new java.util.Date().getTime();
    406         public String toString() {
    407             return "CustomTimestamp[" + timestamp + "]";
    408         }
    409     }
    410 }