diff --git a/build.gradle.kts b/build.gradle.kts index d664cbb961..8eb883e885 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -223,7 +223,7 @@ koverReport { verify { rule("Minimal coverage") { bound { - minValue = 92 + minValue = 93 aggregation = AggregationType.COVERED_PERCENTAGE } } diff --git a/selekt-jdbc/src/test/kotlin/com/bloomberg/selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt b/selekt-jdbc/src/test/kotlin/com/bloomberg/selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt index 66252cd0bc..db2951e75f 100644 --- a/selekt-jdbc/src/test/kotlin/com/bloomberg/selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt +++ b/selekt-jdbc/src/test/kotlin/com/bloomberg/selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt @@ -440,16 +440,9 @@ internal class JdbcDatabaseMetaDataTest { assertNotNull(metaData.getIndexInfo(null, null, "users", unique = true, approximate = false)) } - @Test - fun getIndexInfoNonUnique() { - whenever(mockDatabase.query(any(), any>())).doReturn(mockCursor) - assertNotNull(metaData.getIndexInfo(null, null, "users", unique = false, approximate = false)) - } - @Test fun unwrapToSQLDatabase() { - val unwrapped = metaData.unwrap(SQLDatabase::class.java) - assertSame(mockDatabase, unwrapped) + assertSame(mockDatabase, metaData.unwrap(SQLDatabase::class.java)) } @Test @@ -588,455 +581,278 @@ internal class JdbcDatabaseMetaDataTest { assertTrue(metaData.supportsConvert(Types.INTEGER, Types.VARCHAR)) } + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getColumnsWithVariousColumnTypes() { - val tablesColumnNames = arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", - "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") - val tablesCursor = mock { - var callCount = 0 - whenever(it.moveToNext()) doAnswer { - ++callCount == 1 - } - whenever(it.columnCount) doReturn tablesColumnNames.size - whenever(it.columnNames()) doReturn tablesColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - val name = invocation.getArgument(0) - tablesColumnNames.indexOf(name) - } - whenever(it.getString(any())) doAnswer { invocation -> - when (tablesColumnNames.getOrNull(invocation.getArgument(0))) { - "TABLE_NAME" -> "test_table" - else -> null - } + val tableCursor = makeTablesCursor() + val pragmaCursor = makePragmaCursor(listOf( + listOf(0, "int_col", "INTEGER", 0, null, 0), + listOf(1, "text_col", "TEXT", 0, null, 0), + listOf(2, "real_col", "REAL", 0, null, 0), + listOf(3, "blob_col", "BLOB", 0, null, 0), + listOf(4, "numeric_col", "NUMERIC", 0, null, 0), + listOf(5, "varchar_col", "VARCHAR", 0, null, 0), + listOf(6, "smallint_col", "SMALLINT", 0, null, 0), + listOf(7, "bigint_col", "BIGINT", 0, null, 0), + listOf(8, "double_col", "DOUBLE", 0, null, 0), + listOf(9, "float_col", "FLOAT", 0, null, 0), + listOf(10, "decimal_col", "DECIMAL", 0, null, 0), + listOf(11, "char_col", "CHAR", 0, null, 0), + listOf(12, "clob_col", "CLOB", 0, null, 0), + listOf(13, "null_col", "NULL", 0, null, 0), + listOf(14, "unknown_col", "UNKNOWN", 0, null, 0), + listOf(15, "mediumint_col", "MEDIUMINT", 0, null, 0), + listOf(16, "doubleprecision_col", "DOUBLE PRECISION", 0, null, 0), + listOf(17, "character_col", "CHARACTER", 0, null, 0))) + val unionCursor = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) + when { + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor + else -> mockCursor } - whenever(it.isClosed()) doReturn false } - val pragmaColumnNames = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") - val pragmaCursor = mock { - var callCount = 0 - val columns = listOf( - listOf(0, "int_col", "INTEGER", 0, null, 0), - listOf(1, "text_col", "TEXT", 0, null, 0), - listOf(2, "real_col", "REAL", 0, null, 0), - listOf(3, "blob_col", "BLOB", 0, null, 0), - listOf(4, "numeric_col", "NUMERIC", 0, null, 0), - listOf(5, "varchar_col", "VARCHAR", 0, null, 0), - listOf(6, "smallint_col", "SMALLINT", 0, null, 0), - listOf(7, "bigint_col", "BIGINT", 0, null, 0), - listOf(8, "double_col", "DOUBLE", 0, null, 0), - listOf(9, "float_col", "FLOAT", 0, null, 0), - listOf(10, "decimal_col", "DECIMAL", 0, null, 0), - listOf(11, "char_col", "CHAR", 0, null, 0), - listOf(12, "clob_col", "CLOB", 0, null, 0), - listOf(13, "null_col", "NULL", 0, null, 0), - listOf(14, "unknown_col", "UNKNOWN", 0, null, 0), - listOf(15, "mediumint_col", "MEDIUMINT", 0, null, 0), - listOf(16, "doubleprecision_col", "DOUBLE PRECISION", 0, null, 0), - listOf(17, "character_col", "CHARACTER", 0, null, 0) - ) - whenever(it.moveToNext()) doAnswer { - ++callCount <= columns.size - } - whenever(it.columnCount) doReturn pragmaColumnNames.size - whenever(it.columnNames()) doReturn pragmaColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - pragmaColumnNames.indexOf(invocation.getArgument(0)) - } - whenever(it.getString(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0))?.toString() - } else { - null - } - } - whenever(it.getInt(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 - } else { - 0 - } - } - whenever(it.position()) doAnswer { - callCount - 1 - } - whenever(it.type(any())) doAnswer { invocation -> - when (invocation.getArgument(0)) { - 0, 3, 5 -> ColumnType.INTEGER - 1, 2 -> ColumnType.STRING - 4 -> ColumnType.NULL - else -> ColumnType.STRING - } - } - whenever(it.isNull(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) == null - } else { - true - } + metaData.getColumns(null, null, "%", "%").use { assertNotNull(it) } + } + + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") + @Test + fun getColumnsWithIntType() { + val tableCursor = makeTablesCursor() + val pragmaCursor = makePragmaCursor(listOf(listOf(0, "int_type_col", "INT", 1, "42", 1))) + val unionCursor = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) + when { + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor + else -> mockCursor } - whenever(it.isClosed()) doReturn false - } - val unionCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 24 - whenever(it.columnNames()) doReturn arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", - "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", - "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", - "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", - "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN" - ) - whenever(it.isClosed()) doReturn false } + metaData.getColumns(null, null, "%", "%").use { assertNotNull(it) } + } + + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") + @Test + fun getColumnsWithColumnNamePatternFiltering() { + val tableCursor = makeTablesCursor() + val pragmaCursor = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 1, null, 1), + listOf(1, "name", "TEXT", 0, null, 0), + listOf(2, "email", "TEXT", 0, null, 0))) + val unionCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) + val arg = it.getArgument(0) when { - sql.contains("sqlite_master") && sql.contains("type IN ('table','view')") -> tablesCursor - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("UNION ALL") -> unionCursor + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") || arg.contains("WHERE 1 = 0") -> unionCursor else -> mockCursor } } - metaData.getColumns(null, null, "%", "%").use { - assertNotNull(it) - } + metaData.getColumns(null, null, "%", "na%").use { assertNotNull(it) } } @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test - fun getPrimaryKeysWithMultipleKeys() { - val pragmaColumnNames = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") - val pragmaCursor = mock { - var callCount = 0 - val columns = listOf( - listOf(0, "id", "INTEGER", 1, null, 1), - listOf(1, "sub_id", "INTEGER", 1, null, 2), - listOf(2, "name", "TEXT", 0, null, 0) - ) - whenever(it.moveToNext()) doAnswer { - ++callCount <= columns.size - } - whenever(it.columnCount) doReturn pragmaColumnNames.size - whenever(it.columnNames()) doReturn pragmaColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - pragmaColumnNames.indexOf(invocation.getArgument(0)) - } - whenever(it.getString(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0))?.toString() - } else { - null - } - } - whenever(it.getInt(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 - } else { - 0 - } - } - whenever(it.position()) doAnswer { - callCount - 1 - } - whenever(it.type(any())) doAnswer { invocation -> - when (invocation.getArgument(0)) { - 0, 3, 5 -> ColumnType.INTEGER - 1, 2 -> ColumnType.STRING - 4 -> ColumnType.NULL - else -> ColumnType.STRING - } - } - whenever(it.isNull(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) == null - } else { - true - } + fun getColumnsWithNullColumnNamePattern() { + val tableCursor = makeTablesCursor() + val pragmaCursor = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 1, "0", 1), + listOf(1, "name", "TEXT", 0, null, 0))) + val unionCursor = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) + when { + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor + else -> mockCursor } - whenever(it.isClosed()) doReturn false - } - val unionCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 6 - whenever(it.columnNames()) doReturn arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME" - ) - whenever(it.isClosed()) doReturn false } + metaData.getColumns(null, null, "%", null).use { assertNotNull(it) } + } + + @Test + fun getColumnsWithEmptyResult() { + val tableCursor = makeEmptyCursor(10, arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", + "SELF_REFERENCING_COL_NAME", "REF_GENERATION")) + val emptyCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) + val arg = it.getArgument(0) when { - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("UNION ALL") -> unionCursor + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.contains("WHERE 1 = 0") -> emptyCursor else -> mockCursor } } - metaData.getPrimaryKeys(null, null, "test_table").use { - assertNotNull(it) - } + metaData.getColumns(null, null, "%", "%").use { assertNotNull(it) } } @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test - fun getColumnsWithIntType() { - val tablesColumnNames = arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", - "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") - val tablesCursor = mock { - var callCount = 0 - whenever(it.moveToNext()) doAnswer { - callCount++ - callCount == 1 - } - whenever(it.columnCount) doReturn tablesColumnNames.size - whenever(it.columnNames()) doReturn tablesColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - tablesColumnNames.indexOf(invocation.getArgument(0)) - } - whenever(it.getString(any())) doAnswer { invocation -> - when (tablesColumnNames.getOrNull(invocation.getArgument(0))) { - "TABLE_NAME" -> "test_table" - else -> null - } - } - whenever(it.isClosed()) doReturn false - } - val pragmaColumnNames = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") - val pragmaCursor = mock { - var callCount = 0 - val columns = listOf(listOf(0, "int_type_col", "INT", 1, "42", 1)) - whenever(it.moveToNext()) doAnswer { - ++callCount <= columns.size - } - whenever(it.columnCount) doReturn pragmaColumnNames.size - whenever(it.columnNames()) doReturn pragmaColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - pragmaColumnNames.indexOf(invocation.getArgument(0)) - } - whenever(it.getString(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0))?.toString() - } else { - null - } - } - whenever(it.getInt(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 - } else { - 0 - } - } - whenever(it.position()) doAnswer { - callCount - 1 - } - whenever(it.type(any())) doAnswer { invocation -> - when (invocation.getArgument(0)) { - 0, 3, 5 -> ColumnType.INTEGER - 1, 2 -> ColumnType.STRING - 4 -> ColumnType.STRING - else -> ColumnType.STRING - } + fun getPrimaryKeysWithMultipleKeys() { + val pragmaCursor = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 1, null, 1), + listOf(1, "sub_id", "INTEGER", 1, null, 2), + listOf(2, "name", "TEXT", 0, null, 0))) + val unionCursor = makeEmptyCursor(6, pkNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) + when { + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor + else -> mockCursor } - whenever(it.isClosed()) doReturn false - } - val unionCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 24 - whenever(it.columnNames()) doReturn arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", - "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", - "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", - "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", - "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN" - ) - whenever(it.isClosed()) doReturn false } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) + metaData.getPrimaryKeys(null, null, "test_table").use { assertNotNull(it) } + } + + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") + @Test + fun getPrimaryKeysWithEmptyResult() { + val pragmaCursor = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 0, null, 0), + listOf(1, "name", "TEXT", 0, null, 0))) + val emptyCursor = makeEmptyCursor(6, pkNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) when { - sql.contains("sqlite_master") && sql.contains("type IN ('table','view')") -> tablesCursor - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("UNION ALL") -> unionCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("WHERE 1 = 0") -> emptyCursor else -> mockCursor } } - metaData.getColumns(null, null, "%", "%").use { - assertNotNull(it) - } + metaData.getPrimaryKeys(null, null, "test_table").use { assertNotNull(it) } } @Test - fun getColumnsWithEmptyResult() { - val tablesColumnNames = arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", - "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") - val tablesCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn tablesColumnNames.size - whenever(it.columnNames()) doReturn tablesColumnNames - whenever(it.isClosed()) doReturn false + fun getTablesWithNullPattern() { + val cursor = makeEmptyCursor(10, arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", + "SELF_REFERENCING_COL_NAME", "REF_GENERATION")) + whenever(mockDatabase.query(any(), any>())) doAnswer { + if (it.getArgument(0).contains("sqlite_master")) { cursor } else { mockCursor } } - val emptyCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 24 - whenever(it.columnNames()) doReturn arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", - "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", - "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", - "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", - "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN" - ) - whenever(it.isClosed()) doReturn false + metaData.getTables(null, null, null, null).use { assertNotNull(it) } + } + + @Test + fun getTablesWithSpecificPattern() { + val cursor = makeEmptyCursor(10, arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", + "SELF_REFERENCING_COL_NAME", "REF_GENERATION")) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val arg = it.getArgument(0) + if (arg.contains("sqlite_master") && arg.contains("AND name GLOB")) { cursor } else { mockCursor } } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) - when { - sql.contains("sqlite_master") && sql.contains("type IN ('table','view')") -> tablesCursor - sql.contains("WHERE 1 = 0") -> emptyCursor - else -> mockCursor - } + metaData.getTables(null, null, "test_%", null).use { assertNotNull(it) } + } + + @Test + fun getIndexInfoWithUniqueFlag() { + val cursor = makeEmptyCursor(13, arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", "TYPE", "ORDINAL_POSITION", + "COLUMN_NAME", "ASC_OR_DESC", "CARDINALITY", "PAGES", "FILTER_CONDITION")) + whenever(mockDatabase.query(any(), any>())) doAnswer { + if (it.getArgument(0).contains("AND \"unique\" = 1")) { cursor } else { mockCursor } } - metaData.getColumns(null, null, "%", "%").use { + metaData.getIndexInfo(null, null, "test_table", unique = true, approximate = false).use { assertNotNull(it) } } - @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test - fun getPrimaryKeysWithEmptyResult() { - val pragmaColumnNames = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") - val pragmaCursor = mock { - var callCount = 0 - val columns = listOf( - listOf(0, "id", "INTEGER", 0, null, 0), - listOf(1, "name", "TEXT", 0, null, 0) - ) - whenever(it.moveToNext()) doAnswer { - ++callCount <= columns.size + fun getIndexInfoNonUnique() { + whenever(mockDatabase.query(any(), any>())).doReturn(mockCursor) + assertNotNull(metaData.getIndexInfo(null, null, "users", unique = false, approximate = false)) + } + + private fun makeTablesCursor(): ICursor { + val columns = arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", + "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") + return mock { + var count = 0 + whenever(it.moveToNext()) doAnswer { ++count == 1 } + whenever(it.columnCount) doReturn columns.size + whenever(it.columnNames()) doReturn columns + whenever(it.columnIndex(any())) doAnswer { invocation -> + columns.indexOf(invocation.getArgument(0)) } - whenever(it.columnCount) doReturn pragmaColumnNames.size - whenever(it.columnNames()) doReturn pragmaColumnNames + whenever(it.getString(any())) doAnswer { invocation -> + if (columns.getOrNull(invocation.getArgument(0)) == "TABLE_NAME") { + "test_table" + } else { + null + } + } + whenever(it.isClosed()) doReturn false + } + } + + @Suppress("Detekt.CognitiveComplexMethod") + private fun makePragmaCursor(cols: List>): ICursor { + val columns = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") + return mock { + var count = 0 + whenever(it.moveToNext()) doAnswer { ++count <= cols.size } + whenever(it.columnCount) doReturn columns.size + whenever(it.columnNames()) doReturn columns whenever(it.columnIndex(any())) doAnswer { invocation -> - val name = invocation.getArgument(0) - pragmaColumnNames.indexOf(name) + columns.indexOf(invocation.getArgument(0)) } whenever(it.getString(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0))?.toString() + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0))?.toString() } else { null } } whenever(it.getInt(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 } else { 0 } } - whenever(it.position()) doAnswer { - callCount - 1 - } + whenever(it.position()) doAnswer { count - 1 } whenever(it.type(any())) doAnswer { invocation -> - val index = invocation.getArgument(0) - when (index) { + when (invocation.getArgument(0)) { 0, 3, 5 -> ColumnType.INTEGER - 1, 2 -> ColumnType.STRING 4 -> ColumnType.NULL else -> ColumnType.STRING } } whenever(it.isNull(any())) doAnswer { invocation -> - if (callCount > 0 && callCount <= columns.size) { - columns[callCount - 1].getOrNull(invocation.getArgument(0)) == null + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0)) == null } else { true } } whenever(it.isClosed()) doReturn false } - val emptyCursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 6 - whenever(it.columnNames()) doReturn arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME" - ) - whenever(it.isClosed()) doReturn false - } - whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) - when { - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("WHERE 1 = 0") -> emptyCursor - else -> mockCursor - } - } - metaData.getPrimaryKeys(null, null, "test_table").use { - assertNotNull(it) - } } - @Test - fun getTablesWithNullPattern() { - val cursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 10 - whenever(it.columnNames()) doReturn arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", - "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") - whenever(it.isClosed()) doReturn false - } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) - when { - sql.contains("sqlite_master") -> cursor - else -> mockCursor - } - } - metaData.getTables(null, null, null, null).use { - assertNotNull(it) - } + private fun makeEmptyCursor(count: Int, names: Array): ICursor = mock { + whenever(it.moveToNext()) doReturn false + whenever(it.columnCount) doReturn count + whenever(it.columnNames()) doReturn names + whenever(it.isClosed()) doReturn false } - @Test - fun getTablesWithSpecificPattern() { - val cursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 10 - whenever(it.columnNames()) doReturn arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", - "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION") - whenever(it.isClosed()) doReturn false - } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) - when { - sql.contains("sqlite_master") && sql.contains("AND name GLOB") -> cursor - else -> mockCursor - } - } - metaData.getTables(null, null, "test_%", null).use { - assertNotNull(it) - } - } + private val colsResultNames = arrayOf( + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", + "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", + "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN") - @Test - fun getIndexInfoWithUniqueFlag() { - val cursor = mock { - whenever(it.moveToNext()) doReturn false - whenever(it.columnCount) doReturn 13 - whenever(it.columnNames()) doReturn arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "NON_UNIQUE", - "INDEX_QUALIFIER", "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", - "CARDINALITY", "PAGES", "FILTER_CONDITION") - whenever(it.isClosed()) doReturn false - } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) - when { - sql.contains("AND \"unique\" = 1") -> cursor - else -> mockCursor - } - } - metaData.getIndexInfo(null, null, "test_table", unique = true, approximate = false).use { - assertNotNull(it) - } - } + private val pkNames = arrayOf( + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME") }