diff --git a/README.rst b/README.rst index 28e9eb8..13ab23c 100644 --- a/README.rst +++ b/README.rst @@ -159,6 +159,9 @@ Changelog ========= - Next version - unreleased + + - Don't fail on dates before 1900 on Python < 3. + - 1.1.0 - 2017-03-19 - Support BIT and TINYINT type mappings (thanks @Mokubyow for diff --git a/jaydebeapi/__init__.py b/jaydebeapi/__init__.py index bb77016..4e1c597 100644 --- a/jaydebeapi/__init__.py +++ b/jaydebeapi/__init__.py @@ -595,8 +595,12 @@ def _to_date(rs, col): java_val = rs.getDate(col) if not java_val: return - d = datetime.datetime.strptime(str(java_val)[:10], "%Y-%m-%d") - return d.strftime("%Y-%m-%d") + # The following code requires Python 3.3+ on dates before year 1900. + # d = datetime.datetime.strptime(str(java_val)[:10], "%Y-%m-%d") + # return d.strftime("%Y-%m-%d") + # Workaround / simpler soltution (see + # https://github.com/baztian/jaydebeapi/issues/18): + return str(java_val)[:10] def _to_binary(rs, col): java_val = rs.getObject(col) diff --git a/mockdriver/pom.xml b/mockdriver/pom.xml index 8a78498..e261790 100644 --- a/mockdriver/pom.xml +++ b/mockdriver/pom.xml @@ -7,6 +7,11 @@ <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> + <properties> + <maven.compiler.source>1.7</maven.compiler.source> + <maven.compiler.target>1.7</maven.compiler.target> + </properties> + <dependencies> <dependency> <groupId>org.mockito</groupId> diff --git a/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java b/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java index 8ed0703..6c959fd 100644 --- a/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java +++ b/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java @@ -2,73 +2,98 @@ import java.lang.reflect.Field; import java.sql.Connection; +import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Types; +import java.util.Calendar; import org.mockito.Mockito; public abstract class MockConnection implements Connection { - ResultSet mockResultSet; + ResultSet mockResultSet; - public final void mockExceptionOnCommit(String className, String exceptionMessage) throws SQLException { - Throwable exception = createException(className, exceptionMessage); - Mockito.doThrow(exception).when(this).commit(); + private static Throwable createException(String className, String exceptionMessage) { + try { + return (Throwable) Class.forName(className).getConstructor(String.class) + .newInstance(exceptionMessage); + } catch (Exception e) { + throw new RuntimeException("Couldn't initialize class " + className + ".", e); } + } - public final void mockExceptionOnRollback(String className, String exceptionMessage) throws SQLException { - Throwable exception = createException(className, exceptionMessage); - Mockito.doThrow(exception).when(this).rollback(); + private static int extractTypeCodeForName(String sqlTypesName) { + try { + Field field = Types.class.getField(sqlTypesName); + return field.getInt(null); + } catch (NoSuchFieldException e) { + throw new IllegalArgumentException("Type " + sqlTypesName + " not found in Types class.", e); + } catch (SecurityException e) { + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); } + } - public final void mockExceptionOnExecute(String className, String exceptionMessage) throws SQLException { - PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); - Throwable exception = createException(className, exceptionMessage); - Mockito.when(mockPreparedStatement.execute()).thenThrow(exception); - Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); - } + public final void mockExceptionOnCommit(String className, String exceptionMessage) + throws SQLException { + Throwable exception = createException(className, exceptionMessage); + Mockito.doThrow(exception).when(this).commit(); + } - public final void mockType(String sqlTypesName) throws SQLException { - PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); - Mockito.when(mockPreparedStatement.execute()).thenReturn(true); - mockResultSet = Mockito.mock(ResultSet.class, "ResultSet(for type " + sqlTypesName + ")"); - Mockito.when(mockPreparedStatement.getResultSet()).thenReturn(mockResultSet); - Mockito.when(mockResultSet.next()).thenReturn(true); - ResultSetMetaData mockMetaData = Mockito.mock(ResultSetMetaData.class); - Mockito.when(mockResultSet.getMetaData()).thenReturn(mockMetaData); - Mockito.when(mockMetaData.getColumnCount()).thenReturn(1); - int sqlTypeCode = extractTypeCodeForName(sqlTypesName); - Mockito.when(mockMetaData.getColumnType(1)).thenReturn(sqlTypeCode); - Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); - } + public final void mockExceptionOnRollback(String className, String exceptionMessage) + throws SQLException { + Throwable exception = createException(className, exceptionMessage); + Mockito.doThrow(exception).when(this).rollback(); + } - public final ResultSet verifyResultSet() { - return Mockito.verify(mockResultSet); - } + public final void mockExceptionOnExecute(String className, String exceptionMessage) + throws SQLException { + PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); + Throwable exception = createException(className, exceptionMessage); + Mockito.when(mockPreparedStatement.execute()).thenThrow(exception); + Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); + } - private static Throwable createException(String className, String exceptionMessage) { - try { - return (Throwable) Class.forName(className).getConstructor(String.class).newInstance(exceptionMessage); - } catch (Exception e) { - throw new RuntimeException("Couldn't initialize class " + className + ".", e); - } - } + public final void mockDateResult(int year, int month, int day) throws SQLException { + PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); + Mockito.when(mockPreparedStatement.execute()).thenReturn(true); + mockResultSet = Mockito.mock(ResultSet.class, "ResultSet(for date)"); + Mockito.when(mockPreparedStatement.getResultSet()).thenReturn(mockResultSet); + Mockito.when(mockResultSet.next()).thenReturn(true); + ResultSetMetaData mockMetaData = Mockito.mock(ResultSetMetaData.class); + Mockito.when(mockResultSet.getMetaData()).thenReturn(mockMetaData); + Mockito.when(mockMetaData.getColumnCount()).thenReturn(1); + Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, month - 1); + cal.set(Calendar.DAY_OF_MONTH, day); + Date ancientDate = new Date(cal.getTime().getTime()); + Mockito.when(mockResultSet.getDate(1)).thenReturn(ancientDate); + Mockito.when(mockMetaData.getColumnType(1)).thenReturn(Types.DATE); + Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); + } - private static int extractTypeCodeForName(String sqlTypesName) { - try { - Field field = Types.class.getField(sqlTypesName); - return field.getInt(null); - } catch (NoSuchFieldException e) { - throw new IllegalArgumentException("Type " + sqlTypesName + " not found in Types class.", e); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } + public final void mockType(String sqlTypesName) throws SQLException { + PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); + Mockito.when(mockPreparedStatement.execute()).thenReturn(true); + mockResultSet = Mockito.mock(ResultSet.class, "ResultSet(for type " + sqlTypesName + ")"); + Mockito.when(mockPreparedStatement.getResultSet()).thenReturn(mockResultSet); + Mockito.when(mockResultSet.next()).thenReturn(true); + ResultSetMetaData mockMetaData = Mockito.mock(ResultSetMetaData.class); + Mockito.when(mockResultSet.getMetaData()).thenReturn(mockMetaData); + Mockito.when(mockMetaData.getColumnCount()).thenReturn(1); + int sqlTypeCode = extractTypeCodeForName(sqlTypesName); + Mockito.when(mockMetaData.getColumnType(1)).thenReturn(sqlTypeCode); + Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); + } + public final ResultSet verifyResultSet() { + return Mockito.verify(mockResultSet); + } } diff --git a/test/test_mock.py b/test/test_mock.py index 6dcb702..09443a1 100644 --- a/test/test_mock.py +++ b/test/test_mock.py @@ -50,6 +50,13 @@ def test_all_db_api_type_objects_have_valid_mapping(self): 'getObject')) verify_get(1) + def test_ancient_date_mapped(self): + self.conn.jconn.mockDateResult(1899, 12, 31) + cursor = self.conn.cursor() + cursor.execute("dummy stmt") + result = cursor.fetchone() + self.assertEquals(result[0], "1899-12-31") + def test_sql_exception_on_execute(self): self.conn.jconn.mockExceptionOnExecute("java.sql.SQLException", "expected") cursor = self.conn.cursor()