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