#include "sqliteInt.h" #include "unity.h" #include #include /* Wrapper provided by the SQLite build for static function renameTableTest */ extern void test_renameTableTest(sqlite3_context*, int, sqlite3_value**); static sqlite3 *gDb = NULL; /* Bridge function to invoke the wrapper from SQL */ static void unit_rename_table_test(sqlite3_context *ctx, int argc, sqlite3_value **argv){ /* Directly forward to the provided test_ wrapper */ test_renameTableTest(ctx, argc, argv); } static void exec_ok(const char *sql){ char *errmsg = NULL; int rc = sqlite3_exec(gDb, sql, 0, 0, &errmsg); if( rc!=SQLITE_OK ){ const char *msg = errmsg ? errmsg : "exec failed"; TEST_FAIL_MESSAGE(msg); } sqlite3_free(errmsg); } /* Helper to call the unit function; returns the sqlite3_step rc. ** If SQLITE_ROW, *pColType is set to the type of column 0. */ static int call_unit_fn( const char *zDb, const char *zInput, const char *zType, const char *zName, int isTemp, const char *zWhen, int bNoDQS, sqlite3_stmt **ppStmt, int *pColType ){ char *sql = sqlite3_mprintf( "SELECT unit_rename_table_test(%Q,%Q,%Q,%Q,%d,%Q,%d)", zDb, zInput, zType, zName, isTemp, zWhen, bNoDQS ); TEST_ASSERT_NOT_NULL(sql); sqlite3_stmt *stmt = NULL; int rc = sqlite3_prepare_v2(gDb, sql, -1, &stmt, 0); sqlite3_free(sql); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); rc = sqlite3_step(stmt); if( rc==SQLITE_ROW ){ if( pColType ) *pColType = sqlite3_column_type(stmt, 0); } if( ppStmt ) *ppStmt = stmt; else sqlite3_finalize(stmt); return rc; } void setUp(void) { int rc = sqlite3_open(":memory:", &gDb); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Register the 7-arg unit test SQL function */ rc = sqlite3_create_function(gDb, "unit_rename_table_test", 7, SQLITE_UTF8, NULL, unit_rename_table_test, NULL, NULL); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } void tearDown(void) { if( gDb ){ sqlite3_close(gDb); gDb = NULL; } } /* 1) Valid CREATE TABLE -> returns NULL */ void test_renameTableTest_create_table_returns_null(void){ int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", "CREATE TABLE t1(a)", "table", "t1", 0, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_NULL, colType); sqlite3_finalize(stmt); } /* 2) Invalid SQL with writable_schema OFF -> raises error with contextual message */ void test_renameTableTest_invalid_sql_raises_error_without_writable_schema(void){ /* Missing closing parenthesis */ sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", "CREATE TABLE t1(a", "table", "t1", 0, "when", 0, &stmt, NULL); TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc); sqlite3_finalize(stmt); const char *errmsg = sqlite3_errmsg(gDb); TEST_ASSERT_NOT_NULL(errmsg); TEST_ASSERT_NOT_NULL(strstr(errmsg, "error in table t1 when:")); } /* 3) Invalid SQL with writable_schema ON -> returns NULL instead of error */ void test_renameTableTest_invalid_sql_returns_null_with_writable_schema(void){ exec_ok("PRAGMA writable_schema=ON"); int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", "CREATE TABLE t1(a", "table", "t1", 0, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_NULL, colType); sqlite3_finalize(stmt); exec_ok("PRAGMA writable_schema=OFF"); } /* 4) Trigger on main.t1, zDb='main' -> returns 1 */ void test_renameTableTest_trigger_on_main_returns_1_in_main_db(void){ exec_ok("CREATE TABLE t1(x)"); const char *trigSql = "CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END"; int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", trigSql, "trigger", "tr1", 0, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, colType); TEST_ASSERT_EQUAL_INT(1, sqlite3_column_int(stmt, 0)); sqlite3_finalize(stmt); } /* 5) Trigger on main.t1, zDb='temp' -> returns NULL (no match) */ void test_renameTableTest_trigger_on_main_returns_null_in_temp_db(void){ exec_ok("CREATE TABLE t1(x)"); const char *trigSql = "CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END"; int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("temp", trigSql, "trigger", "tr1", 1, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_NULL, colType); sqlite3_finalize(stmt); } /* 6) Trigger on temp.t2, zDb='temp' -> returns 1 */ void test_renameTableTest_trigger_on_temp_returns_1_in_temp_db(void){ exec_ok("CREATE TEMP TABLE t2(y)"); const char *trigSql = "CREATE TRIGGER tr2 AFTER INSERT ON t2 BEGIN SELECT 1; END"; int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("temp", trigSql, "trigger", "tr2", 1, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, colType); TEST_ASSERT_EQUAL_INT(1, sqlite3_column_int(stmt, 0)); sqlite3_finalize(stmt); } /* 7) View with double-quoted string: with DQS enabled (bNoDQS=0) -> returns NULL */ void test_renameTableTest_view_dqs_enabled_returns_null(void){ const char *viewSql = "CREATE VIEW v1 AS SELECT \"string\""; int colType = -1; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", viewSql, "view", "v1", 0, "when", 0, &stmt, &colType); TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc); TEST_ASSERT_EQUAL_INT(SQLITE_NULL, colType); sqlite3_finalize(stmt); } /* 8) Same view with DQS disabled (bNoDQS=1) -> unresolved identifier error */ void test_renameTableTest_view_dqs_disabled_raises_error(void){ const char *viewSql = "CREATE VIEW v1 AS SELECT \"string\""; sqlite3_stmt *stmt = NULL; int rc = call_unit_fn("main", viewSql, "view", "v1", 0, "when", 1, &stmt, NULL); TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc); sqlite3_finalize(stmt); const char *errmsg = sqlite3_errmsg(gDb); TEST_ASSERT_NOT_NULL(errmsg); TEST_ASSERT_NOT_NULL(strstr(errmsg, "error in view v1 when:")); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameTableTest_create_table_returns_null); RUN_TEST(test_renameTableTest_invalid_sql_raises_error_without_writable_schema); RUN_TEST(test_renameTableTest_invalid_sql_returns_null_with_writable_schema); RUN_TEST(test_renameTableTest_trigger_on_main_returns_1_in_main_db); RUN_TEST(test_renameTableTest_trigger_on_main_returns_null_in_temp_db); RUN_TEST(test_renameTableTest_trigger_on_temp_returns_1_in_temp_db); RUN_TEST(test_renameTableTest_view_dqs_enabled_returns_null); RUN_TEST(test_renameTableTest_view_dqs_disabled_raises_error); return UNITY_END(); }