From a4c59734b2ee69e54feb752159ad2d4b0c70a3ff Mon Sep 17 00:00:00 2001 From: kshackleton1 Date: Thu, 19 Mar 2026 18:36:25 +0000 Subject: [PATCH 1/5] Increase test coverage of JdbcDatabaseMetadata Signed-off-by: kshackleton1 --- .../jdbc/metadata/JdbcDatabaseMetaDataTest.kt | 551 ++++++------------ 1 file changed, 176 insertions(+), 375 deletions(-) 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..64110d7c03 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 @@ -588,455 +588,256 @@ 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 - } + private fun makeTablesCursor(): ICursor { + val n = 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 c = 0 + whenever(it.moveToNext()) doAnswer { ++c == 1 } + whenever(it.columnCount) doReturn n.size + whenever(it.columnNames()) doReturn n + whenever(it.columnIndex(any())) doAnswer { inv -> n.indexOf(inv.getArgument(0)) } + whenever(it.getString(any())) doAnswer { inv -> + if (n.getOrNull(inv.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_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 - } + } + + private fun makePragmaCursor(cols: List>): ICursor { + val n = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") + return mock { + var c = 0 + whenever(it.moveToNext()) doAnswer { ++c <= cols.size } + whenever(it.columnCount) doReturn n.size + whenever(it.columnNames()) doReturn n + whenever(it.columnIndex(any())) doAnswer { inv -> n.indexOf(inv.getArgument(0)) } + whenever(it.getString(any())) doAnswer { inv -> + if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0))?.toString() else null } - whenever(it.position()) doAnswer { - callCount - 1 + whenever(it.getInt(any())) doAnswer { inv -> + if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0)) as? Int ?: 0 else 0 } - whenever(it.type(any())) doAnswer { invocation -> - when (invocation.getArgument(0)) { + whenever(it.position()) doAnswer { c - 1 } + whenever(it.type(any())) doAnswer { inv -> + when (inv.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 - } + whenever(it.isNull(any())) doAnswer { inv -> + if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0)) == null else true } 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 - } + } + + 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 + } + + 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") + + private val pkNames = arrayOf( + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME") + + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") + @Test + fun getColumnsWithVariousColumnTypes() { + val tc = makeTablesCursor() + val pc = 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 uc = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) + val s = 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 + s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc + s.startsWith("PRAGMA table_info") -> pc + s.contains("UNION ALL") -> uc else -> mockCursor } } - metaData.getColumns(null, null, "%", "%").use { - assertNotNull(it) - } + metaData.getColumns(null, null, "%", "%").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 - } - } - 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 - } + fun getColumnsWithIntType() { + val tc = makeTablesCursor() + val pc = makePragmaCursor(listOf(listOf(0, "int_type_col", "INT", 1, "42", 1))) + val uc = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) + val s = it.getArgument(0) when { - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("UNION ALL") -> unionCursor + s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc + s.startsWith("PRAGMA table_info") -> pc + s.contains("UNION ALL") -> uc 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 getColumnsWithColumnNamePatternFiltering() { + val tc = makeTablesCursor() + val pc = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 1, null, 1), + listOf(1, "name", "TEXT", 0, null, 0), + listOf(2, "email", "TEXT", 0, null, 0))) + val uc = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val s = it.getArgument(0) + when { + s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc + s.startsWith("PRAGMA table_info") -> pc + s.contains("UNION ALL") || s.contains("WHERE 1 = 0") -> uc + 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.getColumns(null, null, "%", "na%").use { assertNotNull(it) } + } + + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") + @Test + fun getColumnsWithNullColumnNamePattern() { + val tc = makeTablesCursor() + val pc = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 1, "0", 1), + listOf(1, "name", "TEXT", 0, null, 0))) + val uc = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val s = 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 + s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc + s.startsWith("PRAGMA table_info") -> pc + s.contains("UNION ALL") -> uc else -> mockCursor } } - metaData.getColumns(null, null, "%", "%").use { - assertNotNull(it) - } + metaData.getColumns(null, null, "%", null).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 - } - 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 - } - whenever(mockDatabase.query(any(), any>())) doAnswer { invocation -> - val sql = invocation.getArgument(0) + val tc = 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 ec = makeEmptyCursor(24, colsResultNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val s = it.getArgument(0) when { - sql.contains("sqlite_master") && sql.contains("type IN ('table','view')") -> tablesCursor - sql.contains("WHERE 1 = 0") -> emptyCursor + s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc + s.contains("WHERE 1 = 0") -> ec else -> mockCursor } } - metaData.getColumns(null, null, "%", "%").use { - assertNotNull(it) - } + metaData.getColumns(null, null, "%", "%").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 - } - whenever(it.columnCount) doReturn pragmaColumnNames.size - whenever(it.columnNames()) doReturn pragmaColumnNames - whenever(it.columnIndex(any())) doAnswer { invocation -> - val name = invocation.getArgument(0) - pragmaColumnNames.indexOf(name) - } - 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 -> - val index = invocation.getArgument(0) - when (index) { - 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 - } - } - 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 - } + fun getPrimaryKeysWithMultipleKeys() { + val pc = 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 uc = makeEmptyCursor(6, pkNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val sql = it.getArgument(0) + val s = it.getArgument(0) when { - sql.startsWith("PRAGMA table_info") -> pragmaCursor - sql.contains("WHERE 1 = 0") -> emptyCursor + s.startsWith("PRAGMA table_info") -> pc + s.contains("UNION ALL") -> uc else -> mockCursor } } - metaData.getPrimaryKeys(null, null, "test_table").use { - assertNotNull(it) - } + metaData.getPrimaryKeys(null, null, "test_table").use { assertNotNull(it) } } + @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @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) + fun getPrimaryKeysWithEmptyResult() { + val pc = makePragmaCursor(listOf( + listOf(0, "id", "INTEGER", 0, null, 0), + listOf(1, "name", "TEXT", 0, null, 0))) + val ec = makeEmptyCursor(6, pkNames) + whenever(mockDatabase.query(any(), any>())) doAnswer { + val s = it.getArgument(0) when { - sql.contains("sqlite_master") -> cursor + s.startsWith("PRAGMA table_info") -> pc + s.contains("WHERE 1 = 0") -> ec else -> mockCursor } } - metaData.getTables(null, null, null, null).use { - assertNotNull(it) + metaData.getPrimaryKeys(null, null, "test_table").use { assertNotNull(it) } + } + + @Test + 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 } } + metaData.getTables(null, null, null, null).use { assertNotNull(it) } } @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) + 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 s = it.getArgument(0) + if (s.contains("sqlite_master") && s.contains("AND name GLOB")) { cursor } else { mockCursor } } + metaData.getTables(null, null, "test_%", null).use { assertNotNull(it) } } @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 - } + 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.getIndexInfo(null, null, "test_table", unique = true, approximate = false).use { assertNotNull(it) } } + + @Test + fun getIndexInfoNonUnique() { + whenever(mockDatabase.query(any(), any>())).doReturn(mockCursor) + assertNotNull(metaData.getIndexInfo(null, null, "users", unique = false, approximate = false)) + } } From e27bed9474681ec73e825540485f604b44bb943b Mon Sep 17 00:00:00 2001 From: kshackleton1 Date: Thu, 19 Mar 2026 18:46:15 +0000 Subject: [PATCH 2/5] Increase coverage lower bound threshold Signed-off-by: kshackleton1 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 } } From fe26ef6df1b9566e36b9fb3ce6131c553a6d168c Mon Sep 17 00:00:00 2001 From: kshackleton1 Date: Thu, 19 Mar 2026 18:51:05 +0000 Subject: [PATCH 3/5] Address Detekt Signed-off-by: kshackleton1 --- .../bloomberg/selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt | 1 + 1 file changed, 1 insertion(+) 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 64110d7c03..3e32657208 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 @@ -604,6 +604,7 @@ internal class JdbcDatabaseMetaDataTest { } } + @Suppress("Detekt.CognitiveComplexMethod") private fun makePragmaCursor(cols: List>): ICursor { val n = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") return mock { From aef030b492a0bdcf0e0fea5c3ae56af341c32ce1 Mon Sep 17 00:00:00 2001 From: kshackleton1 Date: Fri, 20 Mar 2026 09:25:31 +0000 Subject: [PATCH 4/5] Address conflicting override Signed-off-by: kshackleton1 --- .../selekt/jdbc/metadata/JdbcDatabaseMetaDataTest.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) 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 3e32657208..c36aa4d99a 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 From 82495159a04f07ae2a1e9f4042b57f5928e16598 Mon Sep 17 00:00:00 2001 From: kshackleton1 Date: Fri, 20 Mar 2026 10:41:07 +0000 Subject: [PATCH 5/5] Consistent format Signed-off-by: kshackleton1 --- .../jdbc/metadata/JdbcDatabaseMetaDataTest.kt | 235 ++++++++++-------- 1 file changed, 128 insertions(+), 107 deletions(-) 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 c36aa4d99a..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 @@ -581,74 +581,12 @@ internal class JdbcDatabaseMetaDataTest { assertTrue(metaData.supportsConvert(Types.INTEGER, Types.VARCHAR)) } - private fun makeTablesCursor(): ICursor { - val n = 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 c = 0 - whenever(it.moveToNext()) doAnswer { ++c == 1 } - whenever(it.columnCount) doReturn n.size - whenever(it.columnNames()) doReturn n - whenever(it.columnIndex(any())) doAnswer { inv -> n.indexOf(inv.getArgument(0)) } - whenever(it.getString(any())) doAnswer { inv -> - if (n.getOrNull(inv.getArgument(0)) == "TABLE_NAME") "test_table" else null - } - whenever(it.isClosed()) doReturn false - } - } - - @Suppress("Detekt.CognitiveComplexMethod") - private fun makePragmaCursor(cols: List>): ICursor { - val n = arrayOf("cid", "name", "type", "notnull", "dflt_value", "pk") - return mock { - var c = 0 - whenever(it.moveToNext()) doAnswer { ++c <= cols.size } - whenever(it.columnCount) doReturn n.size - whenever(it.columnNames()) doReturn n - whenever(it.columnIndex(any())) doAnswer { inv -> n.indexOf(inv.getArgument(0)) } - whenever(it.getString(any())) doAnswer { inv -> - if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0))?.toString() else null - } - whenever(it.getInt(any())) doAnswer { inv -> - if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0)) as? Int ?: 0 else 0 - } - whenever(it.position()) doAnswer { c - 1 } - whenever(it.type(any())) doAnswer { inv -> - when (inv.getArgument(0)) { - 0, 3, 5 -> ColumnType.INTEGER - 4 -> ColumnType.NULL - else -> ColumnType.STRING - } - } - whenever(it.isNull(any())) doAnswer { inv -> - if (c in 1..cols.size) cols[c - 1].getOrNull(inv.getArgument(0)) == null else true - } - whenever(it.isClosed()) doReturn false - } - } - - 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 - } - - 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") - - private val pkNames = arrayOf( - "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME") @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getColumnsWithVariousColumnTypes() { - val tc = makeTablesCursor() - val pc = makePragmaCursor(listOf( + 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), @@ -667,13 +605,13 @@ internal class JdbcDatabaseMetaDataTest { 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 uc = makeEmptyCursor(24, colsResultNames) + val unionCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc - s.startsWith("PRAGMA table_info") -> pc - s.contains("UNION ALL") -> uc + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor else -> mockCursor } } @@ -683,15 +621,15 @@ internal class JdbcDatabaseMetaDataTest { @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getColumnsWithIntType() { - val tc = makeTablesCursor() - val pc = makePragmaCursor(listOf(listOf(0, "int_type_col", "INT", 1, "42", 1))) - val uc = makeEmptyCursor(24, colsResultNames) + 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 s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc - s.startsWith("PRAGMA table_info") -> pc - s.contains("UNION ALL") -> uc + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor else -> mockCursor } } @@ -701,18 +639,18 @@ internal class JdbcDatabaseMetaDataTest { @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getColumnsWithColumnNamePatternFiltering() { - val tc = makeTablesCursor() - val pc = makePragmaCursor(listOf( + 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 uc = makeEmptyCursor(24, colsResultNames) + val unionCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc - s.startsWith("PRAGMA table_info") -> pc - s.contains("UNION ALL") || s.contains("WHERE 1 = 0") -> uc + 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 } } @@ -722,17 +660,17 @@ internal class JdbcDatabaseMetaDataTest { @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getColumnsWithNullColumnNamePattern() { - val tc = makeTablesCursor() - val pc = makePragmaCursor(listOf( + val tableCursor = makeTablesCursor() + val pragmaCursor = makePragmaCursor(listOf( listOf(0, "id", "INTEGER", 1, "0", 1), listOf(1, "name", "TEXT", 0, null, 0))) - val uc = makeEmptyCursor(24, colsResultNames) + val unionCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc - s.startsWith("PRAGMA table_info") -> pc - s.contains("UNION ALL") -> uc + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor else -> mockCursor } } @@ -741,15 +679,15 @@ internal class JdbcDatabaseMetaDataTest { @Test fun getColumnsWithEmptyResult() { - val tc = makeEmptyCursor(10, arrayOf("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + 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 ec = makeEmptyCursor(24, colsResultNames) + val emptyCursor = makeEmptyCursor(24, colsResultNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.contains("sqlite_master") && s.contains("type IN ('table', 'view')") -> tc - s.contains("WHERE 1 = 0") -> ec + arg.contains("sqlite_master") && arg.contains("type IN ('table', 'view')") -> tableCursor + arg.contains("WHERE 1 = 0") -> emptyCursor else -> mockCursor } } @@ -759,16 +697,16 @@ internal class JdbcDatabaseMetaDataTest { @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getPrimaryKeysWithMultipleKeys() { - val pc = makePragmaCursor(listOf( + 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 uc = makeEmptyCursor(6, pkNames) + val unionCursor = makeEmptyCursor(6, pkNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.startsWith("PRAGMA table_info") -> pc - s.contains("UNION ALL") -> uc + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("UNION ALL") -> unionCursor else -> mockCursor } } @@ -778,15 +716,15 @@ internal class JdbcDatabaseMetaDataTest { @Suppress("Detekt.CognitiveComplexMethod", "Detekt.LongMethod") @Test fun getPrimaryKeysWithEmptyResult() { - val pc = makePragmaCursor(listOf( + val pragmaCursor = makePragmaCursor(listOf( listOf(0, "id", "INTEGER", 0, null, 0), listOf(1, "name", "TEXT", 0, null, 0))) - val ec = makeEmptyCursor(6, pkNames) + val emptyCursor = makeEmptyCursor(6, pkNames) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) + val arg = it.getArgument(0) when { - s.startsWith("PRAGMA table_info") -> pc - s.contains("WHERE 1 = 0") -> ec + arg.startsWith("PRAGMA table_info") -> pragmaCursor + arg.contains("WHERE 1 = 0") -> emptyCursor else -> mockCursor } } @@ -810,8 +748,8 @@ internal class JdbcDatabaseMetaDataTest { "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION")) whenever(mockDatabase.query(any(), any>())) doAnswer { - val s = it.getArgument(0) - if (s.contains("sqlite_master") && s.contains("AND name GLOB")) { cursor } else { mockCursor } + val arg = it.getArgument(0) + if (arg.contains("sqlite_master") && arg.contains("AND name GLOB")) { cursor } else { mockCursor } } metaData.getTables(null, null, "test_%", null).use { assertNotNull(it) } } @@ -834,4 +772,87 @@ internal class JdbcDatabaseMetaDataTest { 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.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 -> + columns.indexOf(invocation.getArgument(0)) + } + whenever(it.getString(any())) doAnswer { invocation -> + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0))?.toString() + } else { + null + } + } + whenever(it.getInt(any())) doAnswer { invocation -> + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0)) as? Int ?: 0 + } else { + 0 + } + } + whenever(it.position()) doAnswer { count - 1 } + whenever(it.type(any())) doAnswer { invocation -> + when (invocation.getArgument(0)) { + 0, 3, 5 -> ColumnType.INTEGER + 4 -> ColumnType.NULL + else -> ColumnType.STRING + } + } + whenever(it.isNull(any())) doAnswer { invocation -> + if (count in 1..cols.size) { + cols[count - 1].getOrNull(invocation.getArgument(0)) == null + } else { + true + } + } + whenever(it.isClosed()) doReturn false + } + } + + 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 + } + + 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") + + private val pkNames = arrayOf( + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME") }