0001: /*
0002:
0003: Derby - Class org.apache.derbyTesting.functionTests.util
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: /**
0023: * <p>
0024: * This class factors out utility methods (including assertion machinery)
0025: * for re-use by Derby JUnit tests. JUnit tests should extend this class.
0026: * </p>
0027: *
0028: * @author Rick
0029: */package org.apache.derbyTesting.functionTests.util;
0030:
0031: import java.io.*;
0032: import java.math.*;
0033: import java.sql.*;
0034: import java.util.*;
0035:
0036: import junit.framework.*;
0037:
0038: import org.apache.derby.tools.ij;
0039:
0040: public class DerbyJUnitTest extends TestCase {
0041: /////////////////////////////////////////////////////////////
0042: //
0043: // CONSTANTS
0044: //
0045: /////////////////////////////////////////////////////////////
0046:
0047: /** If you set this startup property to true, you will get chatty output. */
0048: public static final String DEBUG_FLAG = "drb.tests.debug";
0049:
0050: public static final int SUCCESS_EXIT = 0;
0051: public static final int FAILURE_EXIT = 1;
0052:
0053: public static final String DEFAULT_USER_NAME = "APP";
0054: public static final String DEFAULT_PASSWORD = "APP";
0055: public static final String DEFAULT_DATABASE_NAME = "wombat";
0056:
0057: // because java.sql.Types.BOOLEAN doesn't exist in jdbc 2.0
0058: protected static final int JDBC_BOOLEAN = 16;
0059:
0060: //
0061: // For dropping schema objects
0062: //
0063: private static final String TABLE = "table";
0064: private static final String FUNCTION = "function";
0065: private static final String PROCEDURE = "procedure";
0066:
0067: //
0068: // These are properties for the Derby connection URL.
0069: //
0070: private static final String SERVER_URL = "jdbc:derby://localhost:1527/";
0071: private static final String CREATE_PROPERTY = "create=true";
0072:
0073: //
0074: // Indexes into the array of client-specific strings. E.g., DB2JCC_CLIENT,
0075: // DERBY_CLIENT, and EMBEDDED_CLIENT.
0076: //
0077: public static final int DATABASE_URL = 0;
0078: public static final int DRIVER_NAME = DATABASE_URL + 1;
0079: public static final int FRAMEWORK_NAME = DRIVER_NAME + 1;
0080:
0081: // indexed by DATABASE_URL and DRIVER_NAME
0082: private static final String[] DB2JCC_CLIENT = {
0083: "jdbc:derby:net://localhost:1527/",
0084: "com.ibm.db2.jcc.DB2Driver", "DerbyNet" };
0085: private static final String[] DERBY_CLIENT = {
0086: "jdbc:derby://localhost:1527/",
0087: "org.apache.derby.jdbc.ClientDriver", "DerbyNetClient" };
0088: private static final String[] EMBEDDED_CLIENT = { "jdbc:derby:",
0089: "org.apache.derby.jdbc.EmbeddedDriver", "embedded" };
0090:
0091: public static final String[][] LEGAL_CLIENTS = { DB2JCC_CLIENT,
0092: DERBY_CLIENT, EMBEDDED_CLIENT };
0093:
0094: /////////////////////////////////////////////////////////////
0095: //
0096: // STATE
0097: //
0098: /////////////////////////////////////////////////////////////
0099:
0100: private static boolean _debug; // if true, we print chatty diagnostics
0101:
0102: private static PrintStream _outputStream = System.out; // where to print debug output
0103:
0104: private static String _databaseName; // sandbox for tests
0105: private static String[] _defaultClientSettings; // one of the clients in
0106: // LEGAL_CLIENTS
0107: private static boolean _initializedForTestHarness;
0108:
0109: /////////////////////////////////////////////////////////////
0110: //
0111: // CONSTRUCTOR
0112: //
0113: /////////////////////////////////////////////////////////////
0114:
0115: /**
0116: * <p>
0117: * Vacuous constructor for JUnit machinery.
0118: * </p>
0119: */
0120: public DerbyJUnitTest() {
0121: }
0122:
0123: /////////////////////////////////////////////////////////////
0124: //
0125: // PUBLIC BEHAVIOR
0126: //
0127: /////////////////////////////////////////////////////////////
0128:
0129: /**
0130: * <p>
0131: * Run under the old harness.
0132: * </p>
0133: */
0134: public static void runUnderOldHarness(String[] args, Test suite)
0135: throws Exception {
0136: int exitStatus = FAILURE_EXIT;
0137:
0138: initializeForOldHarness(args);
0139:
0140: TestResult result = junit.textui.TestRunner.run(suite);
0141:
0142: exitStatus = result.errorCount() + result.failureCount();
0143:
0144: Runtime.getRuntime().exit(exitStatus);
0145: }
0146:
0147: /**
0148: * <p>
0149: * Initialize a test suite to run under the old test harness.
0150: * </p>
0151: */
0152: public static void initializeForOldHarness(String[] args)
0153: throws Exception {
0154: if (_initializedForTestHarness) {
0155: return;
0156: }
0157:
0158: parseDebug();
0159: setDatabaseName(DEFAULT_DATABASE_NAME);
0160: findClientFromProperties();
0161:
0162: // create database
0163: ij.getPropertyArg(args);
0164: Connection conn = ij.startJBMS();
0165:
0166: _initializedForTestHarness = true;
0167: }
0168:
0169: /**
0170: * <p>
0171: * Return true if we're using the embedded driver.
0172: * </p>
0173: */
0174: public boolean usingEmbeddedClient() {
0175: return (_defaultClientSettings == EMBEDDED_CLIENT);
0176: }
0177:
0178: /**
0179: * <p>
0180: * Return true if we're using the derby client
0181: * </p>
0182: */
0183: public boolean usingDerbyClient() {
0184: return (_defaultClientSettings == DERBY_CLIENT);
0185: }
0186:
0187: /**
0188: * <p>
0189: * Return true if we're using the db2 client
0190: * </p>
0191: */
0192: public boolean usingDB2Client() {
0193: return (_defaultClientSettings == DB2JCC_CLIENT);
0194: }
0195:
0196: /**
0197: * <p>
0198: * Get the client we're using.
0199: * </p>
0200: */
0201: public static String[] getClientSettings() {
0202: return _defaultClientSettings;
0203: }
0204:
0205: /**
0206: * <p>
0207: * Set the client we're going to use.
0208: * </p>
0209: */
0210: public static void setClient(String[] client) {
0211: _defaultClientSettings = client;
0212: }
0213:
0214: /**
0215: * <p>
0216: * Set the database name.
0217: * </p>
0218: */
0219: public static void setDatabaseName(String databaseName) {
0220: _databaseName = databaseName;
0221: }
0222:
0223: /**
0224: * <p>
0225: * Force the debugging state. Useful for debugging under the test harness.
0226: * </p>
0227: */
0228: public static void setDebug(boolean value) {
0229: _debug = value;
0230: }
0231:
0232: /**
0233: * <p>
0234: * Look for the system property which tells us whether to run
0235: * chattily.
0236: * </p>
0237: */
0238: public static boolean parseDebug() {
0239: _debug = Boolean.getBoolean(DEBUG_FLAG);
0240:
0241: return true;
0242: }
0243:
0244: /**
0245: * <p>
0246: * Debug code to print chatty informational messages.
0247: * </p>
0248: */
0249: public static void println(String text) {
0250: if (_debug) {
0251: alarm(text);
0252: }
0253: }
0254:
0255: /**
0256: * <p>
0257: * Print a message regardless of whether we are running in debug mode.
0258: * </p>
0259: */
0260: public static void alarm(String text) {
0261: _outputStream.println(text);
0262: _outputStream.flush();
0263: }
0264:
0265: /**
0266: * <p>
0267: * Print out a stack trace.
0268: * </p>
0269: */
0270: public static void printStackTrace(Throwable t) {
0271: while (t != null) {
0272: t.printStackTrace(_outputStream);
0273:
0274: if (t instanceof SQLException) {
0275: t = ((SQLException) t).getNextException();
0276: } else {
0277: break;
0278: }
0279: }
0280: }
0281:
0282: /**
0283: * <p>
0284: * Determine the client to use based on system properties.
0285: * </p>
0286: */
0287: public static void findClientFromProperties() throws Exception {
0288: Properties systemProps = System.getProperties();
0289: String frameworkName = systemProps.getProperty("framework",
0290: EMBEDDED_CLIENT[FRAMEWORK_NAME]);
0291: int count = LEGAL_CLIENTS.length;
0292:
0293: for (int i = 0; i < count; i++) {
0294: String[] candidate = LEGAL_CLIENTS[i];
0295:
0296: if (candidate[FRAMEWORK_NAME].equals(frameworkName)) {
0297: _defaultClientSettings = candidate;
0298: return;
0299: }
0300: }
0301:
0302: throw new Exception("Unrecognized framework: " + frameworkName);
0303: }
0304:
0305: /**
0306: * <p>
0307: * Return a meaningful exit status so that calling scripts can take
0308: * evasive action.
0309: * </p>
0310: */
0311: public void exit(int exitStatus) {
0312: Runtime.getRuntime().exit(exitStatus);
0313: }
0314:
0315: /////////////////////////////////////////////////////////////
0316: //
0317: // CONNECTION MANAGEMENT
0318: //
0319: /////////////////////////////////////////////////////////////
0320:
0321: /**
0322: * <p>
0323: * Load a client driver, given its particulars.
0324: * </p>
0325: */
0326: protected static boolean faultInDriver(String[] clientSettings) {
0327: String currentClientName = clientSettings[DRIVER_NAME];
0328:
0329: try {
0330: Class.forName(currentClientName);
0331:
0332: return true;
0333: } catch (Exception e) {
0334: println("Could not find " + currentClientName);
0335: return false;
0336: }
0337: }
0338:
0339: /**
0340: * <p>
0341: * Get a connection to a database, using the default client.
0342: * </p>
0343: */
0344: protected static Connection getConnection() throws Exception {
0345: return getConnection(_defaultClientSettings, _databaseName,
0346: new Properties());
0347: }
0348:
0349: /**
0350: * <p>
0351: * Get a connection to a database, using the specified client.
0352: * </p>
0353: */
0354: protected static Connection getConnection(String[] clientSettings,
0355: String databaseName, Properties properties)
0356: throws Exception {
0357: faultInDriver(clientSettings);
0358:
0359: properties.put("user", DEFAULT_USER_NAME);
0360: properties.put("password", DEFAULT_PASSWORD);
0361: properties
0362: .put("retreiveMessagesFromServerOnGetMessage", "true");
0363:
0364: Connection conn = DriverManager.getConnection(makeDatabaseURL(
0365: clientSettings, databaseName), properties);
0366:
0367: println("Connection is a " + conn.getClass().getName());
0368:
0369: return conn;
0370: }
0371:
0372: /**
0373: * <p>
0374: * Cobble together a connection URL.
0375: * </p>
0376: */
0377: private static String makeDatabaseURL(String[] clientSettings,
0378: String databaseName) {
0379: return clientSettings[DATABASE_URL] + databaseName;
0380: }
0381:
0382: /**
0383: * <p>
0384: * Create an empty database.
0385: * </p>
0386: */
0387: protected void createDB(String databaseName) throws Exception {
0388: String[] clientSettings = getClientSettings();
0389: String dbURL = makeDatabaseURL(clientSettings, databaseName);
0390:
0391: dbURL = dbURL + ';' + CREATE_PROPERTY;
0392:
0393: Properties properties = new Properties();
0394:
0395: properties.put("user", DEFAULT_USER_NAME);
0396: properties.put("password", DEFAULT_PASSWORD);
0397:
0398: faultInDriver(clientSettings);
0399:
0400: Connection conn = DriverManager
0401: .getConnection(dbURL, properties);
0402:
0403: conn.close();
0404: }
0405:
0406: ///////////////
0407: //
0408: // SQL MINIONS
0409: //
0410: ///////////////
0411:
0412: /**
0413: * <p>
0414: * Execute DDL statement.
0415: * </p>
0416: */
0417: protected static void executeDDL(Connection conn, String text)
0418: throws SQLException {
0419: PreparedStatement ps = null;
0420:
0421: try {
0422: ps = prepare(conn, text);
0423:
0424: ps.execute();
0425: } finally {
0426: close(ps);
0427: }
0428: }
0429:
0430: /**
0431: * <p>
0432: * Execute a SQL statement, given by the text argument. This thin
0433: * wrapper around the JDBC machinery logs the statement text when
0434: * running in debug mode.
0435: * </p>
0436: */
0437: protected static void execute(Connection conn, String text)
0438: throws SQLException {
0439: PreparedStatement ps = prepare(conn, text);
0440:
0441: ps.execute();
0442: close(ps);
0443: }
0444:
0445: /**
0446: * <p>
0447: * Prepare a SQL statement, given by the text argument. This thin
0448: * wrapper around the JDBC machinery logs the statement text when
0449: * running in debug mode.
0450: * </p>
0451: */
0452: protected static PreparedStatement prepare(Connection conn,
0453: String text) throws SQLException {
0454: println("Preparing: " + text);
0455:
0456: return conn.prepareStatement(text);
0457: }
0458:
0459: /**
0460: * <p>
0461: * Prepare a SQL call statement, given by the text argument. This thin
0462: * wrapper around the JDBC machinery logs the statement text when
0463: * running in debug mode.
0464: * </p>
0465: */
0466: protected static CallableStatement prepareCall(Connection conn,
0467: String text) throws SQLException {
0468: println("Preparing procedure call: '" + text + "'");
0469:
0470: CallableStatement cs = conn.prepareCall(text);
0471:
0472: return cs;
0473: }
0474:
0475: /**
0476: * <p>
0477: * Scour out all the rows from a table.
0478: * </p>
0479: */
0480: protected static void truncateTable(Connection conn, String name)
0481: throws SQLException {
0482: PreparedStatement ps = prepare(conn, "delete from " + name);
0483:
0484: ps.execute();
0485: }
0486:
0487: /**
0488: * <p>
0489: * Drop a table regardless of whether it exists. If the table does not
0490: * exist, don't log an error unless
0491: * running in debug mode. This method is to be used for reinitializing
0492: * a schema in case a previous test run failed to clean up after itself.
0493: * Do not use this method if you need to verify that the table really exists.
0494: * </p>
0495: */
0496: protected static void dropTable(Connection conn, String name) {
0497: dropSchemaObject(conn, TABLE, name);
0498: }
0499:
0500: /**
0501: * <p>
0502: * Drop a function regardless of whether it exists. If the function does not
0503: * exist, don't log an error unless
0504: * running in debug mode. This method is to be used for reinitializing
0505: * a schema in case a previous test run failed to clean up after itself.
0506: * Do not use this method if you need to verify that the function really exists.
0507: * </p>
0508: */
0509: protected static void dropFunction(Connection conn, String name) {
0510: dropSchemaObject(conn, FUNCTION, name);
0511: }
0512:
0513: /**
0514: * <p>
0515: * Drop a procedure regardless of whether it exists. If the procedure does
0516: * not exist, don't log an error unless
0517: * running in debug mode. This method is to be used for reinitializing
0518: * a schema in case a previous test run failed to clean up after itself.
0519: * Do not use this method if you need to verify that the procedure really exists.
0520: * </p>
0521: */
0522: protected static void dropProcedure(Connection conn, String name) {
0523: dropSchemaObject(conn, PROCEDURE, name);
0524: }
0525:
0526: /**
0527: * <p>
0528: * Drop a schema object regardless of whether it exists. If the object does
0529: * not exist, don't log an error unless
0530: * running in debug mode. This method is to be used for reinitializing
0531: * a schema in case a previous test run failed to clean up after itself.
0532: * Do not use this method if you need to verify that the object really exists.
0533: * </p>
0534: */
0535: protected static void dropSchemaObject(Connection conn,
0536: String genus, String objectName) {
0537: PreparedStatement ps = null;
0538:
0539: try {
0540: ps = prepare(conn, "drop " + genus + " " + objectName);
0541:
0542: ps.execute();
0543: } catch (SQLException e) {
0544: if (_debug) {
0545: printStackTrace(e);
0546: }
0547: }
0548:
0549: close(ps);
0550: }
0551:
0552: /**
0553: * <p>
0554: * Close a ResultSet. This method factors out the check for whether
0555: * the ResultSet was created in the first place. This tidies up the
0556: * caller's cleanup logic. If an error occurs, print it. Because this
0557: * method swallows the exception after printing it, do not call this
0558: * method if you want your test to halt on error.
0559: * </p>
0560: */
0561: protected static void close(ResultSet rs) {
0562: try {
0563: if (rs != null) {
0564: rs.close();
0565: }
0566: } catch (SQLException e) {
0567: printStackTrace(e);
0568: }
0569: }
0570:
0571: /**
0572: * <p>
0573: * Close a Statement. This method factors out the check for whether
0574: * the Statement was created in the first place. This tidies up the
0575: * caller's cleanup logic. If an error occurs, print it. Because this
0576: * method swallows the exception after printing it, do not call this
0577: * method if you want your test to halt on error.
0578: * </p>
0579: */
0580: protected static void close(Statement statement) {
0581: try {
0582: if (statement != null) {
0583: statement.close();
0584: }
0585: } catch (SQLException e) {
0586: printStackTrace(e);
0587: }
0588: }
0589:
0590: /**
0591: * <p>
0592: * Close a Connection. This method factors out the check for whether
0593: * the Connection was created in the first place. This tidies up the
0594: * caller's cleanup logic. If an error occurs, print it. Because this
0595: * method swallows the exception after printing it, do not call this
0596: * method if you want your test to halt on error.
0597: * </p>
0598: */
0599: protected static void close(Connection conn) {
0600: try {
0601: if (conn != null) {
0602: conn.close();
0603: }
0604: } catch (SQLException e) {
0605: printStackTrace(e);
0606: }
0607: }
0608:
0609: /**
0610: * <p>
0611: * Read a column from a ResultSet given its column name and expected jdbc
0612: * type. This method is useful if you are want to verify the getXXX() logic
0613: * most naturally fitting the declared SQL type.
0614: * </p>
0615: */
0616: protected Object getColumn(ResultSet rs, String columnName,
0617: int jdbcType) throws Exception {
0618: Object retval = null;
0619:
0620: switch (jdbcType) {
0621: case JDBC_BOOLEAN:
0622: retval = new Boolean(rs.getBoolean(columnName));
0623: break;
0624:
0625: case Types.BIGINT:
0626: retval = new Long(rs.getLong(columnName));
0627: break;
0628:
0629: case Types.BLOB:
0630: retval = rs.getBlob(columnName);
0631: break;
0632:
0633: case Types.CHAR:
0634: case Types.LONGVARCHAR:
0635: case Types.VARCHAR:
0636: retval = rs.getString(columnName);
0637: break;
0638:
0639: case Types.BINARY:
0640: case Types.LONGVARBINARY:
0641: case Types.VARBINARY:
0642: retval = rs.getBytes(columnName);
0643: break;
0644:
0645: case Types.CLOB:
0646: retval = rs.getClob(columnName);
0647: break;
0648:
0649: case Types.DATE:
0650: retval = rs.getDate(columnName);
0651: break;
0652:
0653: case Types.DECIMAL:
0654: case Types.NUMERIC:
0655: retval = rs.getBigDecimal(columnName);
0656: break;
0657:
0658: case Types.DOUBLE:
0659: retval = new Double(rs.getDouble(columnName));
0660: break;
0661:
0662: case Types.REAL:
0663: retval = new Float(rs.getFloat(columnName));
0664: break;
0665:
0666: case Types.INTEGER:
0667: retval = new Integer(rs.getInt(columnName));
0668: break;
0669:
0670: case Types.SMALLINT:
0671: retval = new Short(rs.getShort(columnName));
0672: break;
0673:
0674: case Types.TIME:
0675: retval = rs.getTime(columnName);
0676: break;
0677:
0678: case Types.TIMESTAMP:
0679: retval = rs.getTimestamp(columnName);
0680: break;
0681:
0682: default:
0683: fail("Unknown jdbc type " + jdbcType
0684: + " used to retrieve column: " + columnName);
0685: break;
0686: }
0687:
0688: if (rs.wasNull()) {
0689: retval = null;
0690: }
0691:
0692: return retval;
0693: }
0694:
0695: /**
0696: * <p>
0697: * Read a column from a ResultSet given its column position
0698: * and an expected Java type. This method is useful when
0699: * comparing ResultSets against expected values.
0700: * </p>
0701: *
0702: * @param rs The ResultSet to read.
0703: * @param param The column number (1-based)
0704: * @param value An object whose type is what we expect the column to be.
0705: */
0706: protected Object getColumn(ResultSet rs, int param, Object value)
0707: throws Exception {
0708: Object retval;
0709:
0710: if (value == null) {
0711: retval = rs.getObject(param);
0712: } else if (value instanceof Boolean) {
0713: retval = new Boolean(rs.getBoolean(param));
0714: } else if (value instanceof Byte) {
0715: retval = new Byte(rs.getByte(param));
0716: } else if (value instanceof Short) {
0717: retval = new Short(rs.getShort(param));
0718: } else if (value instanceof Integer) {
0719: retval = new Integer(rs.getInt(param));
0720: } else if (value instanceof Long) {
0721: retval = new Long(rs.getLong(param));
0722: } else if (value instanceof Float) {
0723: retval = new Float(rs.getFloat(param));
0724: } else if (value instanceof Double) {
0725: retval = new Double(rs.getDouble(param));
0726: } else if (value instanceof String) {
0727: retval = rs.getString(param);
0728: } else if (value instanceof BigDecimal) {
0729: retval = rs.getBigDecimal(param);
0730: } else {
0731: retval = rs.getObject(param);
0732: }
0733:
0734: if (rs.wasNull()) {
0735: retval = null;
0736: }
0737:
0738: return retval;
0739: }
0740:
0741: /**
0742: * <p>
0743: * Read an output argument from a CallableStatement given its 1-based
0744: * argument position and expected jdbc type. This is useful for
0745: * exercising the getXXX() methods most natural to a declared SQL type.
0746: * </p>
0747: */
0748: protected Object getOutArg(CallableStatement cs, int arg,
0749: int jdbcType) throws Exception {
0750: Object retval = null;
0751:
0752: switch (jdbcType) {
0753: case JDBC_BOOLEAN:
0754: retval = new Boolean(cs.getBoolean(arg));
0755: break;
0756:
0757: case Types.BIGINT:
0758: retval = new Long(cs.getLong(arg));
0759: break;
0760:
0761: case Types.BLOB:
0762: retval = cs.getBlob(arg);
0763: break;
0764:
0765: case Types.CHAR:
0766: case Types.LONGVARCHAR:
0767: case Types.VARCHAR:
0768: retval = cs.getString(arg);
0769: break;
0770:
0771: case Types.BINARY:
0772: case Types.LONGVARBINARY:
0773: case Types.VARBINARY:
0774: retval = cs.getBytes(arg);
0775: break;
0776:
0777: case Types.CLOB:
0778: retval = cs.getClob(arg);
0779: break;
0780:
0781: case Types.DATE:
0782: retval = cs.getDate(arg);
0783: break;
0784:
0785: case Types.DECIMAL:
0786: case Types.NUMERIC:
0787: retval = cs.getBigDecimal(arg);
0788: break;
0789:
0790: case Types.DOUBLE:
0791: retval = new Double(cs.getDouble(arg));
0792: break;
0793:
0794: case Types.REAL:
0795: retval = new Float(cs.getFloat(arg));
0796: break;
0797:
0798: case Types.INTEGER:
0799: retval = new Integer(cs.getInt(arg));
0800: break;
0801:
0802: case Types.SMALLINT:
0803: retval = new Short(cs.getShort(arg));
0804: break;
0805:
0806: case Types.TIME:
0807: retval = cs.getTime(arg);
0808: break;
0809:
0810: case Types.TIMESTAMP:
0811: retval = cs.getTimestamp(arg);
0812: break;
0813:
0814: default:
0815: fail("Unknown jdbc type " + jdbcType
0816: + " used to retrieve column: " + arg);
0817: break;
0818: }
0819:
0820: if (cs.wasNull()) {
0821: retval = null;
0822: }
0823:
0824: return retval;
0825: }
0826:
0827: /**
0828: * <p>
0829: * Stuff a PreparedStatement parameter given its 1-based parameter position
0830: * and expected jdbc type. This method is useful for testing the setXXX()
0831: * methods most natural for a declared SQL type.
0832: * </p>
0833: */
0834: protected void setParameter(PreparedStatement ps, int param,
0835: int jdbcType, Object value) throws Exception {
0836: if (value == null) {
0837: ps.setNull(param, jdbcType);
0838:
0839: return;
0840: }
0841:
0842: switch (jdbcType) {
0843: case JDBC_BOOLEAN:
0844: ps.setBoolean(param, ((Boolean) value).booleanValue());
0845: break;
0846:
0847: case Types.BIGINT:
0848: ps.setLong(param, ((Long) value).longValue());
0849: break;
0850:
0851: case Types.BLOB:
0852: ps.setBlob(param, ((Blob) value));
0853: break;
0854:
0855: case Types.CHAR:
0856: case Types.LONGVARCHAR:
0857: case Types.VARCHAR:
0858: ps.setString(param, ((String) value));
0859: break;
0860:
0861: case Types.BINARY:
0862: case Types.LONGVARBINARY:
0863: case Types.VARBINARY:
0864: ps.setBytes(param, (byte[]) value);
0865: break;
0866:
0867: case Types.CLOB:
0868: ps.setClob(param, ((Clob) value));
0869: break;
0870:
0871: case Types.DATE:
0872: ps.setDate(param, ((java.sql.Date) value));
0873: break;
0874:
0875: case Types.DECIMAL:
0876: case Types.NUMERIC:
0877: ps.setBigDecimal(param, ((BigDecimal) value));
0878: break;
0879:
0880: case Types.DOUBLE:
0881: ps.setDouble(param, ((Double) value).doubleValue());
0882: break;
0883:
0884: case Types.REAL:
0885: ps.setFloat(param, ((Float) value).floatValue());
0886: break;
0887:
0888: case Types.INTEGER:
0889: ps.setInt(param, ((Integer) value).intValue());
0890: break;
0891:
0892: case Types.SMALLINT:
0893: ps.setShort(param, ((Short) value).shortValue());
0894: break;
0895:
0896: case Types.TIME:
0897: ps.setTime(param, (Time) value);
0898: break;
0899:
0900: case Types.TIMESTAMP:
0901: ps.setTimestamp(param, (Timestamp) value);
0902: break;
0903:
0904: default:
0905: fail("Unknown jdbc type: " + jdbcType);
0906: break;
0907: }
0908:
0909: }
0910:
0911: /**
0912: * <p>
0913: * Stuff a PreparedStatement parameter given its 1-based parameter position.
0914: * The appropriate setXXX() method is determined by the Java type of the
0915: * value being stuffed. This method is useful for testing setXXX() methods
0916: * other than the most natural fit for the declared SQL type.
0917: * </p>
0918: */
0919: protected void setParameter(PreparedStatement ps, int param,
0920: Object value) throws Exception {
0921: if (value == null) {
0922: ps.setObject(param, null);
0923:
0924: return;
0925: }
0926:
0927: if (value instanceof Boolean) {
0928: ps.setBoolean(param, ((Boolean) value).booleanValue());
0929: } else if (value instanceof Byte) {
0930: ps.setByte(param, ((Byte) value).byteValue());
0931: } else if (value instanceof Short) {
0932: ps.setShort(param, ((Short) value).shortValue());
0933: } else if (value instanceof Integer) {
0934: ps.setInt(param, ((Integer) value).intValue());
0935: } else if (value instanceof Long) {
0936: ps.setLong(param, ((Long) value).longValue());
0937: } else if (value instanceof Float) {
0938: ps.setFloat(param, ((Float) value).floatValue());
0939: } else if (value instanceof Double) {
0940: ps.setDouble(param, ((Double) value).doubleValue());
0941: } else if (value instanceof String) {
0942: ps.setString(param, ((String) value));
0943: } else {
0944: ps.setObject(param, value);
0945: }
0946: }
0947:
0948: ////////////////////
0949: //
0950: // QUERY GENERATION
0951: //
0952: ////////////////////
0953:
0954: /**
0955: * <p>
0956: * Single quote a string. This is a helper routine for use in generating
0957: * SQL text.
0958: * </p>
0959: */
0960: protected String singleQuote(String text) {
0961: return "'" + text + "'";
0962: }
0963:
0964: /////////////////////////////////////////////////////////////
0965: //
0966: // EXTRA ASSERTIONS
0967: //
0968: /////////////////////////////////////////////////////////////
0969:
0970: /**
0971: * <p>
0972: * Assert the values of a whole row.
0973: * </p>
0974: */
0975: public void assertRow(ResultSet rs, Object[] expectedRow)
0976: throws Exception {
0977: int count = expectedRow.length;
0978:
0979: for (int i = 0; i < count; i++) {
0980: int columnNumber = i + 1;
0981: Object expected = expectedRow[i];
0982: Object actual = getColumn(rs, columnNumber, expected);
0983:
0984: compareObjects("Column number " + columnNumber, expected,
0985: actual);
0986: }
0987: }
0988:
0989: /**
0990: * <p>
0991: * Assert a scalar result from a query.
0992: * </p>
0993: */
0994: public void assertScalar(Connection conn, String queryText,
0995: Object expectedResult) throws Exception {
0996: PreparedStatement ps = prepare(conn, queryText);
0997: ResultSet rs = ps.executeQuery();
0998:
0999: rs.next();
1000:
1001: assertColumnEquals(queryText, rs, 1, expectedResult);
1002:
1003: close(rs);
1004: close(ps);
1005: }
1006:
1007: /**
1008: * <p>
1009: * Assert the values in a ResultSet for a given column across all rows.
1010: * </p>
1011: */
1012: public void assertColumnEquals(ResultSet rs, int columnNumber,
1013: Object[] expectedValues) throws Exception {
1014: int count = expectedValues.length;
1015:
1016: for (int i = 0; i < count; i++) {
1017: rs.next();
1018: assertColumnEquals(Integer.toString(i), rs, columnNumber,
1019: expectedValues[i]);
1020: }
1021: }
1022:
1023: /**
1024: * <p>
1025: * Assert a column's value.
1026: * </p>
1027: */
1028: public void assertColumnEquals(String message, ResultSet rs,
1029: int columnNumber, Object expectedValue) throws Exception {
1030: Object actualValue = getColumn(rs, columnNumber, expectedValue);
1031:
1032: compareObjects(message, expectedValue, actualValue);
1033: }
1034:
1035: /**
1036: * <p>
1037: * Assert two objects are equal, allowing nulls to be equal.
1038: * </p>
1039: */
1040: public void compareObjects(String message, Object left, Object right)
1041: throws Exception {
1042: message = message + "\n\t expected = " + left
1043: + "\n\t actual = " + right;
1044:
1045: if (left == null) {
1046: assertNull(message, right);
1047: } else {
1048: assertNotNull(message, right);
1049:
1050: if (left instanceof byte[]) {
1051: compareBytes(message, left, right);
1052: } else if (left instanceof java.util.Date) {
1053: compareDates(message, left, right);
1054: } else {
1055: assertTrue(message, left.equals(right));
1056: }
1057: }
1058: }
1059:
1060: /**
1061: * <p>
1062: * Assert two byte arrays are equal, allowing nulls to be equal.
1063: * </p>
1064: */
1065: public void compareBytes(String message, Object left, Object right)
1066: throws Exception {
1067: if (left == null) {
1068: assertNull(message, right);
1069: } else {
1070: assertNotNull(right);
1071: }
1072:
1073: if (!(left instanceof byte[])) {
1074: fail(message);
1075: }
1076: if (!(right instanceof byte[])) {
1077: fail(message);
1078: }
1079:
1080: byte[] leftBytes = (byte[]) left;
1081: byte[] rightBytes = (byte[]) right;
1082: int count = leftBytes.length;
1083:
1084: assertEquals(message, count, rightBytes.length);
1085:
1086: for (int i = 0; i < count; i++) {
1087: assertEquals(message + "[ " + i + " ]", leftBytes[i],
1088: rightBytes[i]);
1089: }
1090: }
1091:
1092: /**
1093: * <p>
1094: * Assert two Dates are equal, allowing nulls to be equal.
1095: * </p>
1096: */
1097: public void compareDates(String message, Object left, Object right)
1098: throws Exception {
1099: if (left == null) {
1100: assertNull(message, right);
1101: } else {
1102: assertNotNull(right);
1103: }
1104:
1105: if (!(left instanceof java.util.Date)) {
1106: fail(message);
1107: }
1108: if (!(right instanceof java.util.Date)) {
1109: fail(message);
1110: }
1111:
1112: assertEquals(message, left.toString(), right.toString());
1113: }
1114:
1115: }
|