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 }