package net.ttddyy.dsproxy.proxy; import org.assertj.core.api.ThrowableAssert; import org.junit.Test; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.*; public class ResultSetProxyLogicTest { private static final int NUMBER_OF_COLUMNS = 3; private static final String COLUMN_1_LABEL = "FIRST"; private static final String COLUMN_2_LABEL = "SECOND"; private static final String COLUMN_3_LABEL = "THIRD"; private static final String COLUMN_1_VALUE = "result1"; private static final Integer COLUMN_2_VALUE = 999; private static final Timestamp COLUMN_3_VALUE = new Timestamp(2312413L); @Test public void unsupportedMethodsThrowUnsupportedOperationException() throws Throwable { ResultSet resultSet = exampleResultSet(); final ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); final Method getCursorName = ResultSet.class.getMethod("getCursorName"); assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { resultSetProxyLogic.invoke(getCursorName, null); } }).isInstanceOf(UnsupportedOperationException.class).hasMessage("Method 'public abstract java.lang.String java.sql.ResultSet.getCursorName() throws java.sql.SQLException' is not supported by this proxy"); } @Test public void getTargetReturnsTheResultSetFromTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); Method getTarget = ProxyJdbcObject.class.getMethod("getTarget"); Object result = resultSetProxyLogic.invoke(getTarget, null); assertThat(result).isSameAs(resultSet); } @Test public void getResultSetMetaDataReturnsTheResultSetMetaDataFromTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); Method getMetaData = ResultSet.class.getMethod("getMetaData"); Object result = resultSetProxyLogic.invoke(getMetaData, null); assertThat(result).isSameAs(resultSet.getMetaData()); } @Test public void closeCallsCloseOnTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); invokeClose(resultSetProxyLogic); verify(resultSet).close(); } @Test public void getColumnOnResultSetThatHasBeenConsumedTwiceThrowsException() throws Throwable { ResultSet resultSet = exampleResultSet(); final ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); consumeResultSet(resultSet, resultSetProxyLogic); assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { ResultSetProxyLogicTest.this.invokeGetString(resultSetProxyLogic, 1); } }).isInstanceOf(SQLException.class).hasMessage("Result set exhausted. There were 2 result(s) only"); } @Test public void getColumnOnClosedResultSetThatHasBeenConsumedOnceThrowsException() throws Throwable { ResultSet resultSet = exampleResultSet(); final ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); invokeClose(resultSetProxyLogic); assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { ResultSetProxyLogicTest.this.invokeGetString(resultSetProxyLogic, 1); } }).isInstanceOf(SQLException.class).hasMessage("Already closed"); } @Test public void nextOnUnconsumedResultSetThatHasMoreResultsDelegatesToTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); when(resultSet.next()).thenReturn(true); boolean result = invokeNext(resultSetProxyLogic); assertThat(result).isEqualTo(true); } @Test public void nextOnUnconsumedResultThatHasNoMoreResultsSetDelegatesToTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); when(resultSet.next()).thenReturn(false); boolean result = invokeNext(resultSetProxyLogic); assertThat(result).isEqualTo(false); } @Test public void getColumnByIndexOnUnconsumedResultSetThatHasMoreResultsDelegatesToTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); when(resultSet.next()).thenReturn(true); invokeNext(resultSetProxyLogic); int columnIndex = 1; String columnValue = "result"; when(resultSet.getString(columnIndex)).thenReturn(columnValue); String result = invokeGetString(resultSetProxyLogic, columnIndex); assertThat(result).isEqualTo(columnValue); } @Test public void getColumnByLabelOnUnconsumedResultSetThatHasMoreResultsDelegatesToTheTarget() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); when(resultSet.next()).thenReturn(true); invokeNext(resultSetProxyLogic); when(resultSet.getString(COLUMN_1_LABEL)).thenReturn(COLUMN_1_VALUE); String result = invokeGetString(resultSetProxyLogic, COLUMN_1_LABEL); assertThat(result).isEqualTo(COLUMN_1_VALUE); } @Test public void getColumnByIndexOnConsumedResultSetBeforeCallingNextThrowsSQLException() throws Throwable { ResultSet resultSet = exampleResultSet(); final ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { ResultSetProxyLogicTest.this.invokeGetString(resultSetProxyLogic, 1); } }).isInstanceOf(SQLException.class).hasMessage("Result set not advanced. Call next before any get method!"); } @Test public void getColumnByIndexOnConsumedResultSetThatHasMoreResultsReturnsTheResultThatTheTargetDidTheFirstTime() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); invokeNext(resultSetProxyLogic); String result = invokeGetString(resultSetProxyLogic, 1); assertThat(result).isEqualTo(COLUMN_1_VALUE); } @Test public void getColumnByLabelOnConsumedResultSetThatHasMoreResultsReturnsTheResultThatTheTargetDidTheFirstTime() throws Throwable { ResultSet resultSet = exampleResultSet(); ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); invokeNext(resultSetProxyLogic); String result = invokeGetString(resultSetProxyLogic, COLUMN_1_LABEL); assertThat(result).isEqualTo(COLUMN_1_VALUE); } @Test public void getColumnByLabelOnConsumedResultSetWithUnknownLabelThrowsIllegalArgumentException() throws Throwable { ResultSet resultSet = exampleResultSet(); final ResultSetProxyLogic resultSetProxyLogic = ResultSetProxyLogic.resultSetProxyLogic(resultSet); consumeResultSetAndCallBeforeFirst(resultSet, resultSetProxyLogic); invokeNext(resultSetProxyLogic); assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { invokeGetString(resultSetProxyLogic, "bad"); } }).isInstanceOf(SQLException.class).hasMessage("Unknown column name 'bad'"); } private void consumeResultSetAndCallBeforeFirst(ResultSet resultSet, ResultSetProxyLogic resultSetProxyLogic) throws Throwable { consumeResultSet(resultSet, resultSetProxyLogic); invokeBeforeFirst(resultSetProxyLogic); } private void consumeResultSet(ResultSet resultSet, ResultSetProxyLogic resultSetProxyLogic) throws Throwable { when(resultSet.next()).thenReturn(true, true, false); when(resultSet.getString(1)).thenReturn(COLUMN_1_VALUE); when(resultSet.getInt(2)).thenReturn(COLUMN_2_VALUE); when(resultSet.getTimestamp(3)).thenReturn(COLUMN_3_VALUE); when(resultSet.getString(COLUMN_1_LABEL)).thenReturn(COLUMN_1_VALUE); when(resultSet.getInt(COLUMN_2_LABEL)).thenReturn(COLUMN_2_VALUE); when(resultSet.getTimestamp(COLUMN_3_LABEL)).thenReturn(COLUMN_3_VALUE); assertThat(invokeNext(resultSetProxyLogic)).isTrue(); assertThat(invokeGetString(resultSetProxyLogic, COLUMN_1_LABEL)).isEqualTo(COLUMN_1_VALUE); assertThat(invokeGetInt(resultSetProxyLogic, 2)).isEqualTo(COLUMN_2_VALUE); assertThat(invokeGetTimestamp(resultSetProxyLogic, COLUMN_3_LABEL)).isEqualTo(COLUMN_3_VALUE); assertThat(invokeNext(resultSetProxyLogic)).isTrue(); assertThat(invokeGetString(resultSetProxyLogic, 1)).isEqualTo(COLUMN_1_VALUE); assertThat(invokeGetInt(resultSetProxyLogic, COLUMN_2_LABEL)).isEqualTo(COLUMN_2_VALUE); assertThat(invokeGetTimestamp(resultSetProxyLogic, 3)).isEqualTo(COLUMN_3_VALUE); assertThat(invokeNext(resultSetProxyLogic)).isFalse(); } private void invokeClose(ResultSetProxyLogic resultSetProxyLogic) throws Throwable { Method next = ResultSet.class.getMethod("close"); resultSetProxyLogic.invoke(next, null); } private void invokeBeforeFirst(ResultSetProxyLogic resultSetProxyLogic) throws Throwable { Method beforeFirst = ResultSet.class.getMethod("beforeFirst"); resultSetProxyLogic.invoke(beforeFirst, null); } private boolean invokeNext(ResultSetProxyLogic resultSetProxyLogic) throws Throwable { Method next = ResultSet.class.getMethod("next"); return (Boolean) resultSetProxyLogic.invoke(next, null); } private String invokeGetString(ResultSetProxyLogic resultSetProxyLogic, int columnIndex) throws Throwable { Method getString = ResultSet.class.getMethod("getString", int.class); return (String) resultSetProxyLogic.invoke(getString, new Object[]{columnIndex}); } private int invokeGetInt(ResultSetProxyLogic resultSetProxyLogic, int columnIndex) throws Throwable { Method getInt = ResultSet.class.getMethod("getInt", int.class); return (Integer) resultSetProxyLogic.invoke(getInt, new Object[]{columnIndex}); } private Timestamp invokeGetTimestamp(ResultSetProxyLogic resultSetProxyLogic, int columnIndex) throws Throwable { Method getTimestamp = ResultSet.class.getMethod("getTimestamp", int.class); return (Timestamp) resultSetProxyLogic.invoke(getTimestamp, new Object[]{columnIndex}); } private String invokeGetString(ResultSetProxyLogic resultSetProxyLogic, String columnLabel) throws Throwable { Method getString = ResultSet.class.getMethod("getString", String.class); return (String) resultSetProxyLogic.invoke(getString, new Object[]{columnLabel}); } private int invokeGetInt(ResultSetProxyLogic resultSetProxyLogic, String columnLabel) throws Throwable { Method getInt = ResultSet.class.getMethod("getInt", String.class); return (Integer) resultSetProxyLogic.invoke(getInt, new Object[]{columnLabel}); } private Timestamp invokeGetTimestamp(ResultSetProxyLogic resultSetProxyLogic, String columnLabel) throws Throwable { Method getTimestamp = ResultSet.class.getMethod("getTimestamp", String.class); return (Timestamp) resultSetProxyLogic.invoke(getTimestamp, new Object[]{columnLabel}); } private ResultSet exampleResultSet() throws SQLException { ResultSet resultSet = mock(ResultSet.class); ResultSetMetaData resultSetMetaData = exampleResultSetMetaData(); when(resultSet.getMetaData()).thenReturn(resultSetMetaData); return resultSet; } private ResultSetMetaData exampleResultSetMetaData() throws SQLException { ResultSetMetaData metaData = mock(ResultSetMetaData.class); when(metaData.getColumnCount()).thenReturn(NUMBER_OF_COLUMNS); when(metaData.getColumnLabel(1)).thenReturn(COLUMN_1_LABEL); when(metaData.getColumnLabel(2)).thenReturn(COLUMN_2_LABEL); when(metaData.getColumnLabel(3)).thenReturn(COLUMN_3_LABEL); return metaData; } }