/*
* $Id$
*
* Copyright 2006, The jCoderZ.org Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the jCoderZ.org Project nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jcoderz.commons.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import junit.framework.TestCase;
/**
* Tests the DbUtil class.
* @author Albrecht Messner
*/
public class DbUtilTest
extends TestCase
{
private static final int TEST_BATCH_SIZE = 10;
private static final int TEST_LOOPS = 50;
private static final String WRONG_TYPE_CODE = "Wrong type code";
private static final String WRONG_METHOD_CALLED
= "Wrong method called on prepared statement";
/**
* Tests whether a java.sql.Statement, Connection or ResultSet is
* closed correctly.
* @throws Exception if the testcase fails
*/
public void testCloseObject ()
throws Exception
{
final Class[] testInterfaces = {
Statement.class,
Connection.class,
ResultSet.class
};
for (int i = 0; i < testInterfaces.length; i++)
{
final TestInvocationHandler invHandler = new TestInvocationHandler();
final Object obj = Proxy.newProxyInstance(
Statement.class.getClassLoader(),
new Class[] {testInterfaces[i]},
invHandler);
if (obj instanceof Statement)
{
DbUtil.close((Statement) obj);
}
else if (obj instanceof Connection)
{
DbUtil.close((Connection) obj);
}
else
{
DbUtil.close((ResultSet) obj);
}
assertTrue("Close should have been called on the Statement object",
invHandler.isCloseCalled());
}
}
/**
* Tests the setters for various data types on a prepared statement.
* @throws Exception if the testcase fails
*/
public void testParameterSetters ()
throws Exception
{
final TestInvocationHandler invHandler = new TestInvocationHandler();
final PreparedStatement pstmt
= (PreparedStatement) Proxy.newProxyInstance(
PreparedStatement.class.getClassLoader(),
new Class[] {PreparedStatement.class},
invHandler);
final String s1 = "Hello World";
DbUtil.setCharOrNull(pstmt, 0, s1);
assertEquals(WRONG_METHOD_CALLED,
"setString", invHandler.getLastMethod());
DbUtil.setVarcharOrNull(pstmt, 0, s1);
assertEquals(WRONG_METHOD_CALLED,
"setString", invHandler.getLastMethod());
DbUtil.setClobOrNull(pstmt, 0, s1);
assertEquals(WRONG_METHOD_CALLED,
"setCharacterStream", invHandler.getLastMethod());
final Integer i = new Integer(0);
DbUtil.setIntegerOrNull(pstmt, 0, i);
assertEquals(WRONG_METHOD_CALLED,
"setInt", invHandler.getLastMethod());
final Long l = new Long(0);
DbUtil.setLongOrNull(pstmt, 0, l);
assertEquals(WRONG_METHOD_CALLED,
"setLong", invHandler.getLastMethod());
final Timestamp tstamp = new Timestamp(0);
DbUtil.setTimestampOrNull(pstmt, 0, tstamp);
assertEquals(WRONG_METHOD_CALLED,
"setTimestamp", invHandler.getLastMethod());
}
/**
* Tests the parameter setters with null parameters.
* @throws Exception if the testcase fails
*/
public void testSetNullParameters ()
throws Exception
{
final TestInvocationHandler invHandler = new TestInvocationHandler();
final PreparedStatement pstmt
= (PreparedStatement) Proxy.newProxyInstance(
PreparedStatement.class.getClassLoader(),
new Class[] {PreparedStatement.class},
invHandler);
DbUtil.setCharOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE, invHandler.getTypeCode(), Types.CHAR);
DbUtil.setClobOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE, invHandler.getTypeCode(), Types.CLOB);
DbUtil.setIntegerOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE, invHandler.getTypeCode(), Types.INTEGER);
DbUtil.setLongOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE, invHandler.getTypeCode(), Types.INTEGER);
DbUtil.setTimestampOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE,
invHandler.getTypeCode(), Types.TIMESTAMP);
DbUtil.setVarcharOrNull(pstmt, 0, null);
assertEquals(WRONG_TYPE_CODE, invHandler.getTypeCode(), Types.VARCHAR);
}
/**
* Tests closing of a null java.sql.Statement, Connection and ResultSet.
*/
public void testCloseNullObjects ()
{
try
{
final Statement stmt = null;
DbUtil.close(stmt);
final Connection con = null;
DbUtil.close(con);
final ResultSet rset = null;
DbUtil.close(rset);
}
catch (Exception x)
{
fail("No exception expected when closing a null object");
}
}
public void xtestLimitedBatchSizePreparedStatement ()
throws Exception
{
final PreparedStatementHandler pstmtHandler
= new PreparedStatementHandler();
final PreparedStatement pstmt
= (PreparedStatement) Proxy.newProxyInstance(
PreparedStatement.class.getClassLoader(),
new Class[] {PreparedStatement.class},
pstmtHandler);
final PreparedStatement wrappedPstmt
= DbUtil.getLimitedBatchSizePreparedStatement(
pstmt, TEST_BATCH_SIZE);
int batchCount = 0;
for (int i = 0; i < TEST_LOOPS; i++)
{
wrappedPstmt.addBatch();
batchCount++;
if (batchCount == TEST_BATCH_SIZE + 1)
{
assertTrue("Batch update not called",
pstmtHandler.isExecuteBatchCalled());
assertEquals("Wrong batch count",
pstmtHandler.getLastUpdatedCount(), TEST_BATCH_SIZE);
batchCount = 1;
}
}
final int[] updateCount = wrappedPstmt.executeBatch();
assertEquals("Wrong update counts.", TEST_LOOPS, updateCount.length);
for (int i = 0; i < updateCount.length; i++)
{
assertEquals(
"Wrong update count", Statement.SUCCESS_NO_INFO, updateCount[i]);
}
}
private static final class TestInvocationHandler
implements InvocationHandler
{
private boolean mCloseCalled = false;
private String mLastMethod;
private int mTypeCode = 0;
public Object invoke (Object proxy, Method method, Object[] args)
throws Throwable
{
if (method.getName().equals("close"))
{
mCloseCalled = true;
}
else if (method.getName().equals("setNull"))
{
final Integer arg2 = (Integer) args[1];
mTypeCode = arg2.intValue();
}
mLastMethod = method.getName();
return null;
}
public boolean isCloseCalled ()
{
return mCloseCalled;
}
public String getLastMethod ()
{
return mLastMethod;
}
public int getTypeCode ()
{
return mTypeCode;
}
}
private static final class PreparedStatementHandler
implements InvocationHandler
{
private int mBatchCount = 0;
private boolean mExecuteBatchCalled = false;
private boolean mClearBatchCalled = true;
private int mLastUpdated = 0;
/** {@inheritDoc} */
public Object invoke (Object proxy, Method method, Object[] args)
throws Throwable
{
final Object result;
if (method.getName().equals("addBatch"))
{
mBatchCount++;
result = null;
}
else if (method.getName().equals("executeBatch"))
{
mExecuteBatchCalled = true;
mLastUpdated = mBatchCount;
mBatchCount = 0;
result = new int[mLastUpdated];
Arrays.fill((int[]) result, Statement.SUCCESS_NO_INFO);
}
else if (method.getName().equals("clearBatch"))
{
mClearBatchCalled = true;
result = null;
}
else
{
throw new UnsupportedOperationException(method.getName());
}
return result;
}
/**
* @return Returns the executeBatchCalled.
*/
public boolean isExecuteBatchCalled ()
{
return mExecuteBatchCalled;
}
/**
*
*/
public void resetExecuteBatchCalled ()
{
mExecuteBatchCalled = false;
}
/**
* @return Returns the batchCount.
*/
public int getLastUpdatedCount ()
{
return mLastUpdated;
}
/**
* @return Returns the clearBatchCalled.
*/
public boolean isClearBatchCalled ()
{
return mClearBatchCalled;
}
/**
*
*/
public void resetClearBatchCalled ()
{
mClearBatchCalled = false;
}
}
}