001: // $Id: BeanTest.java 11 2007-08-19 20:05:36Z jcamaia $
002:
003: package net.sf.persist.tests.framework;
004:
005: import static org.junit.Assert.assertEquals;
006: import static org.junit.Assert.assertNotNull;
007: import static org.junit.Assert.assertNull;
008: import static org.junit.Assert.assertTrue;
009:
010: import java.sql.Connection;
011: import java.sql.SQLException;
012: import java.util.List;
013: import java.util.Map;
014:
015: import net.sf.persist.Persist;
016: import net.sf.persist.Result;
017: import net.sf.persist.TableMapping;
018: import net.sf.persist.tests.common.Simple;
019: import net.sf.persist.tests.common.TestSimple;
020:
021: public class BeanTest {
022:
023: // TODO: test updates passing a single value
024:
025: public static void test(Persist persist, BeanMap beanMap) {
026: Connection connection = persist.getConnection();
027: Class cls = DynamicBean.createBeanClass(beanMap, false);
028: Class clsNoTable = DynamicBean.createBeanClass(beanMap, true);
029:
030: String tableName = dbName(beanMap.getClassName());
031:
032: try {
033: connection.createStatement().execute(
034: "delete from " + tableName);
035: } catch (SQLException e) {
036: throw new RuntimeException(e);
037: }
038: BeanTest.testAll(persist, cls, clsNoTable, beanMap);
039:
040: try {
041: connection.createStatement().execute(
042: "delete from " + tableName);
043: } catch (SQLException e) {
044: throw new RuntimeException(e);
045: }
046: BeanTest.testAllNull(persist, cls, clsNoTable, beanMap);
047:
048: if (beanMap.supportsAutoGeneratedKeys()) {
049: testExecuteUpdateAutoGeneratedKeys(persist);
050: testSetAutoGeneratedKeys(persist);
051: }
052:
053: }
054:
055: /**
056: * Perform tests using a bean with non-null values
057: */
058: public static void testAll(Persist persist, Class cls,
059: Class clsNoTable, BeanMap beanMap) {
060: persist.setAutoCommit(false);
061: Object obj = DynamicBean.createInstance(cls, beanMap, false);
062: BeanTest.testInsert(persist, obj, beanMap);
063: BeanTest.testSelectByFields(persist, obj, beanMap);
064: BeanTest.testSelectFields(persist, obj, beanMap, false);
065: BeanTest.testSelectMap(persist, obj, beanMap);
066: BeanTest.testReadNoTable(persist, obj, clsNoTable);
067: persist.commit();
068: persist.setAutoCommit(true);
069: }
070:
071: /**
072: * Perform tests using a bean with null values
073: */
074: public static void testAllNull(Persist persist, Class cls,
075: Class clsNoTable, BeanMap beanMap) {
076: persist.setAutoCommit(false);
077: Object objNull = DynamicBean.createInstance(cls, beanMap, true);
078: BeanTest.testInsert(persist, objNull, beanMap);
079: BeanTest.testSelectByFieldsNull(persist, objNull, beanMap);
080: BeanTest.testSelectFields(persist, objNull, beanMap, true);
081: BeanTest.testSelectMap(persist, objNull, beanMap);
082: BeanTest.testReadNoTable(persist, objNull, clsNoTable);
083: persist.commit();
084: persist.setAutoCommit(true);
085: }
086:
087: /**
088: * tests insertion of a bean
089: */
090: public static void testInsert(Persist persist, Object obj,
091: BeanMap beanMap) {
092: Class cls = obj.getClass();
093: String tableName = dbName(obj.getClass().getSimpleName());
094:
095: // perform insert
096: persist.insert(obj);
097:
098: // check if a single result exists in the table (expects the table to be clean by the beginning of the process)
099: String sql = "select * from " + tableName;
100: List read = persist.readList(cls, sql);
101: if (read.size() != 1) {
102: throw new AssertionError("Expected 1 result but got ["
103: + read.size() + "] as result of sql [" + sql + "]");
104: }
105:
106: // check if the bean read is the same as inserted
107: if (!obj.equals(read.get(0))) {
108: throw new AssertionError("Expected ["
109: + DynamicBean.toString(obj) + "] but got ["
110: + DynamicBean.toString(read.get(0))
111: + "] as result of [" + sql + "]");
112: }
113: }
114:
115: /**
116: * tests reading with NoTable class
117: */
118: public static void testReadNoTable(Persist persist, Object obj,
119: Class clsNoTable) {
120:
121: String tableName = dbName(obj.getClass().getSimpleName());
122:
123: // now read with NoTable (assumes previously inserted data)
124: Object objNoTable = persist.read(clsNoTable, "select * from "
125: + tableName);
126:
127: // compare values
128: if (!DynamicBean.compareBeansFromDifferentClasses(obj,
129: objNoTable)) {
130: throw new AssertionError("Expected ["
131: + DynamicBean.toString(obj) + "] but got ["
132: + DynamicBean.toString(objNoTable) + "]");
133: }
134: }
135:
136: /**
137: * For each field and each field type, execute a query in the format
138: * select * from tableName where columnName=?
139: */
140: public static void testSelectByFields(Persist persist, Object obj,
141: BeanMap beanMap) {
142: Class cls = obj.getClass();
143: String tableName = dbName(obj.getClass().getSimpleName());
144:
145: // for each field in the bean
146: for (FieldMap fieldMap : beanMap.getFields()) {
147:
148: // only perform tests if the field supports queries by value (blobs in oracle, for instance, don't)
149: if (fieldMap.isSupportsQueryByValue()) {
150: String columnName = dbName(fieldMap.getFieldName());
151: String sql = "select * from " + tableName + " where "
152: + columnName + "=?";
153: Object fieldValue = DynamicBean.getFieldValue(obj,
154: fieldMap.getFieldName());
155:
156: // for each type supported by the field, test if a query using an object of that type returns data correctly
157: for (Class fieldType : fieldMap.getTypes()) {
158:
159: // use value converted to the type being tested
160: Object fieldValueConverted = DynamicBean
161: .convertToType(fieldType, fieldValue);
162:
163: // query using the type being tested
164: Object ret = persist.read(cls, sql,
165: fieldValueConverted);
166:
167: // check if the result is not null and has the same data as the object being tested
168: if (ret == null) {
169: throw new AssertionError(
170: "Expected not null value but got null as result of ["
171: + sql + "] with parameter ["
172: + fieldValue + "]");
173: }
174: if (!obj.equals(ret)) {
175: throw new AssertionError("Expected ["
176: + DynamicBean.toString(obj)
177: + "] but got ["
178: + DynamicBean.toString(ret)
179: + "] as result of [" + sql + "]");
180: }
181: }
182: }
183: }
184: }
185:
186: /**
187: * For each field, execute a query in the format
188: * select * from tableName where columnName is null
189: */
190: public static void testSelectByFieldsNull(Persist persist,
191: Object obj, BeanMap beanMap) {
192: Class cls = obj.getClass();
193: String tableName = dbName(obj.getClass().getSimpleName());
194:
195: // for each field in the bean
196: for (FieldMap fieldMap : beanMap.getFields()) {
197:
198: // only perform tests if the field supports queries by value (blobs in oracle, for instance, don't)
199: if (fieldMap.isSupportsQueryByValue()) {
200: String columnName = dbName(fieldMap.getFieldName());
201:
202: // test if query for null value in the column related with the field return the object correctly
203: String sql = "select * from " + tableName + " where "
204: + columnName + " is null";
205: Object ret = persist.read(cls, sql);
206: if (ret == null)
207: throw new AssertionError(
208: "Expected not null value but got null as result of ["
209: + sql + "]");
210: if (!obj.equals(ret)) {
211: throw new AssertionError("Expected ["
212: + DynamicBean.toString(obj) + "] but got ["
213: + DynamicBean.toString(ret)
214: + "] as result of [" + sql + "]");
215: }
216: }
217: }
218: }
219:
220: /**
221: * for each field, and for each field type perform a query in the form
222: * select columnName from tableName
223: */
224: public static void testSelectFields(Persist persist, Object obj,
225: BeanMap beanMap, boolean useNulls) {
226: String tableName = dbName(obj.getClass().getSimpleName());
227:
228: // for each field in the bean
229: for (FieldMap fieldMap : beanMap.getFields()) {
230: String columnName = dbName(fieldMap.getFieldName());
231: String sql = "select " + columnName + " from " + tableName;
232:
233: // get field value from the bean
234: Object fieldValue = DynamicBean.getFieldValue(obj, fieldMap
235: .getFieldName());
236:
237: // for each supported type
238: for (Class fieldType : fieldMap.getTypes()) {
239:
240: // query for a single column data using the field type (eg byte, Byte, String, InputStream, etc.)
241: Object ret = persist.read(fieldType, sql);
242:
243: if (useNulls) {
244: // check if "null", which means 0 for numeric values type as primitive (byte, short, int, etc.)
245: if (!DynamicBean.isNull(fieldType, ret))
246: throw new AssertionError(
247: "Expected null value but got [" + ret
248: + "] as result of [" + sql
249: + "]");
250: } else {
251: if (ret == null) {
252: throw new AssertionError(
253: "Expected not null value but got null as result of ["
254: + sql + "]");
255: }
256:
257: // TODO: maybe test compatibility of return type with field type?
258:
259: // compare values using a method that takes into consideration "compatible" types
260: // (eg char[]-String, double-BigDecimal, etc)
261: Object retConverted = DynamicBean.convertToType(
262: fieldValue.getClass(), ret);
263: if (!DynamicBean.compareValues(fieldValue,
264: retConverted)) {
265: throw new AssertionError("Expected ["
266: + fieldValue + "] but got [" + ret
267: + "] as result of [" + sql + "]");
268: }
269: }
270: }
271: }
272: }
273:
274: /**
275: * perform [select * from tableName] and get the results as a map
276: */
277: public static void testSelectMap(Persist persist, Object obj,
278: BeanMap beanMap) {
279: String tableName = dbName(obj.getClass().getSimpleName());
280:
281: // read list of all data in the table as a map
282: String sql = "select * from " + tableName;
283: List<Map<String, Object>> mapList = persist.readMapList(sql);
284:
285: // asserts there's only one entry (added during the insert test)
286: if (mapList.size() != 1) {
287: throw new AssertionError("Expected 1 result but got ["
288: + mapList.size() + "] as result of sql [" + sql
289: + "]");
290: }
291:
292: // use the first (or single) map returned
293: Map m = mapList.get(0);
294:
295: // for each field in the bean
296: for (FieldMap fieldMap : beanMap.getFields()) {
297: String columnName = dbName(fieldMap.getFieldName());
298:
299: // get the field value
300: Object fieldValue = DynamicBean.getFieldValue(obj, fieldMap
301: .getFieldName());
302:
303: // get the corresponding map value
304: Object mapValue = m.get(columnName);
305:
306: // if field supports comparisons on the map values (mysql's year2 and year4, for instance,
307: // have Date objects here, but must be inserted as short's, therefore can't be compared properly)
308: if (fieldMap.isSupportsCompareMapValue()) {
309:
310: // compare values using a method that takes into consideration "compatible" types
311: // (eg char[]-String, double-BigDecimal, etc)
312: if (!DynamicBean.compareValues(fieldValue, mapValue)) {
313: throw new AssertionError("Map entry [" + columnName
314: + "]=[" + mapValue
315: + "] does not match field ["
316: + fieldMap.getFieldName() + "]=["
317: + fieldValue + "] as result of sql [" + sql
318: + "]");
319: }
320: }
321: }
322: }
323:
324: /**
325: * Tests if explicitly specifying autoGeneratedKeys in executeUpdate works
326: */
327: public static void testExecuteUpdateAutoGeneratedKeys(
328: Persist persist) {
329:
330: TableMapping mapping = (TableMapping) persist
331: .getMapping(Simple.class);
332: if (mapping.supportsGetGeneratedKeys()) {
333:
334: // some data to insert
335: int intCol = DynamicBean
336: .randomInt(0, Integer.MAX_VALUE / 2);
337: String stringCol = DynamicBean.randomString(255);
338:
339: // insert with explicit auto generated keys and check result object data
340: String[] autoGeneratedKeys = new String[] { "id" };
341: Result result = persist
342: .executeUpdate(
343: Simple.class,
344: "insert into simple (int_col,string_col) values(?,?)",
345: autoGeneratedKeys, intCol, stringCol);
346: assertEquals(1, result.getGeneratedKeys().size());
347: assertEquals(1, result.getRowsModified());
348:
349: // read object and compare with inserted data
350: Simple simpleRead = persist
351: .read(
352: Simple.class,
353: "select * from simple where int_col=? and string_col=?",
354: intCol, stringCol);
355: assertNotNull(simpleRead);
356: assertEquals(intCol, simpleRead.getIntCol());
357: assertEquals(stringCol, simpleRead.getStringCol());
358:
359: // delete object and check it was removed
360: persist.delete(simpleRead);
361: simpleRead = persist
362: .read(
363: Simple.class,
364: "select * from simple where int_col=? and string_col=?",
365: intCol, stringCol);
366: assertNull(simpleRead);
367: }
368:
369: }
370:
371: /**
372: * Tests setUpdateGeneratedKeys
373: */
374: public static void testSetAutoGeneratedKeys(Persist persist) {
375:
376: TableMapping mapping = (TableMapping) persist
377: .getMapping(Simple.class);
378: if (mapping.supportsGetGeneratedKeys()) {
379:
380: persist.setUpdateAutoGeneratedKeys(true);
381:
382: // insert object with setUpdateAutoGeneratedKeys option
383: Simple simpleInsert = TestSimple.buildSimple();
384: simpleInsert.setId(0);
385: persist.insert(simpleInsert);
386: assertTrue(0 != simpleInsert.getId());
387:
388: // read object using primary key (auto generated)
389: Simple simpleRead = persist.read(Simple.class,
390: "select * from simple where id=?", simpleInsert
391: .getId());
392: assertEquals(simpleInsert, simpleRead);
393:
394: // delete object by primary key and check it was removed
395: persist.delete(simpleRead);
396: simpleRead = persist.readByPrimaryKey(Simple.class,
397: simpleRead.getId());
398: assertNull(simpleRead);
399:
400: persist.setUpdateAutoGeneratedKeys(false);
401:
402: }
403: }
404:
405: // ---------- helpers ----------
406:
407: /**
408: * Returned the database table/column name related with a given bean/field name
409: */
410: private static String dbName(String s) {
411: String name = s.replaceAll("([A-Z])", "_$1").toLowerCase();
412: return name.charAt(0) == '_' ? name.substring(1) : name;
413: }
414:
415: }
|