#include "sqliteInt.h" #include "unity.h" #include #include /* Wrapper for the static function under test (provided in build as per instructions) */ extern int test_renameResolveTrigger(Parse *pParse); /* Helpers */ static void execSQL(sqlite3 *db, const char *sql){ int rc = sqlite3_exec(db, sql, 0, 0, 0); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } static void initParseAndTriggerWithTable(sqlite3 **pDb, Parse *pParse, Trigger **ppTrig, const char *zTable){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Ensure a simple table exists */ char sql[256]; sqlite3_snprintf(sizeof(sql), sql, "CREATE TABLE %s(a, b);", zTable); execSQL(db, sql); memset(pParse, 0, sizeof(*pParse)); pParse->db = db; Trigger *pTrig = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); TEST_ASSERT_NOT_NULL(pTrig); Table *pTab = sqlite3FindTable(db, zTable, "main"); TEST_ASSERT_NOT_NULL(pTab); pTrig->pTabSchema = pTab->pSchema; pTrig->table = sqlite3DbStrDup(db, zTable); TEST_ASSERT_NOT_NULL(pTrig->table); pTrig->op = TK_DELETE; /* default op; individual tests may override */ pTrig->pWhen = 0; pTrig->step_list = 0; pParse->pNewTrigger = pTrig; *pDb = db; *ppTrig = pTrig; } static Token makeToken(const char *z){ Token t; t.z = z; t.n = (int)strlen(z); return t; } void setUp(void) { /* Empty setup */ } void tearDown(void) { /* Empty teardown */ } /* Test 1: Basic successful resolution for a simple trigger with no WHEN and no steps */ void test_renameResolveTrigger_basic_ok(void){ sqlite3 *db = 0; Parse sParse; Trigger *pTrig = 0; initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1"); /* Change op to check that eTriggerOp is set */ pTrig->op = TK_INSERT; int rc = test_renameResolveTrigger(&sParse); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(sParse.pTriggerTab); TEST_ASSERT_EQUAL_INT(TK_INSERT, sParse.eTriggerOp); /* Cleanup */ sqlite3DbFree(db, pTrig->table); sqlite3DbFree(db, pTrig); sqlite3_close(db); } /* Test 2: WHEN clause is a constant expression -> success */ void test_renameResolveTrigger_when_constant_ok(void){ sqlite3 *db = 0; Parse sParse; Trigger *pTrig = 0; initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1"); /* WHEN 1 */ Token t1 = makeToken("1"); pTrig->pWhen = sqlite3ExprAlloc(db, TK_INTEGER, &t1, 0); TEST_ASSERT_NOT_NULL(pTrig->pWhen); int rc = test_renameResolveTrigger(&sParse); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Cleanup */ sqlite3ExprDelete(db, pTrig->pWhen); sqlite3DbFree(db, pTrig->table); sqlite3DbFree(db, pTrig); sqlite3_close(db); } /* Test 3: WHEN clause references a non-existent column -> expect error */ void test_renameResolveTrigger_when_bad_column_error(void){ sqlite3 *db = 0; Parse sParse; Trigger *pTrig = 0; initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1"); /* WHEN nosuchcol */ Token tBad = makeToken("nosuchcol"); pTrig->pWhen = sqlite3ExprAlloc(db, TK_ID, &tBad, 0); TEST_ASSERT_NOT_NULL(pTrig->pWhen); int rc = test_renameResolveTrigger(&sParse); TEST_ASSERT_NOT_EQUAL_INT(SQLITE_OK, rc); /* Cleanup */ sqlite3ExprDelete(db, pTrig->pWhen); sqlite3DbFree(db, pTrig->table); sqlite3DbFree(db, pTrig); sqlite3_close(db); } /* Test 4: Trigger step contains a minimal SELECT -> success */ void test_renameResolveTrigger_step_with_select_ok(void){ sqlite3 *db = 0; Parse sParse; Trigger *pTrig = 0; initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1"); TriggerStep *pStep = (TriggerStep*)sqlite3DbMallocZero(db, sizeof(TriggerStep)); TEST_ASSERT_NOT_NULL(pStep); /* Minimal select */ pStep->pSelect = sqlite3SelectNew(&sParse, 0, 0, 0, 0, 0, 0, 0, 0); TEST_ASSERT_NOT_NULL(pStep->pSelect); pTrig->step_list = pStep; int rc = test_renameResolveTrigger(&sParse); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Cleanup */ sqlite3SelectDelete(db, pStep->pSelect); sqlite3DbFree(db, pStep); sqlite3DbFree(db, pTrig->table); sqlite3DbFree(db, pTrig); sqlite3_close(db); } /* Test 5: Trigger step contains a SrcList referencing existing table and a WHERE that resolves -> success */ void test_renameResolveTrigger_step_with_src_and_where_ok(void){ sqlite3 *db = 0; Parse sParse; Trigger *pTrig = 0; initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1"); TriggerStep *pStep = (TriggerStep*)sqlite3DbMallocZero(db, sizeof(TriggerStep)); TEST_ASSERT_NOT_NULL(pStep); /* Build a minimal SrcList with one term "t1" (in "main") */ SrcList *pSrc = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList)); TEST_ASSERT_NOT_NULL(pSrc); pSrc->nSrc = 1; pSrc->a[0].zName = sqlite3DbStrDup(db, "t1"); TEST_ASSERT_NOT_NULL(pSrc->a[0].zName); pSrc->a[0].zDatabase = sqlite3DbStrDup(db, "main"); TEST_ASSERT_NOT_NULL(pSrc->a[0].zDatabase); pStep->pSrc = pSrc; /* WHERE a (column of t1) */ Token tA = makeToken("a"); pStep->pWhere = sqlite3ExprAlloc(db, TK_ID, &tA, 0); TEST_ASSERT_NOT_NULL(pStep->pWhere); pTrig->step_list = pStep; int rc = test_renameResolveTrigger(&sParse); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Cleanup original (the function deletes its duplicate internally) */ sqlite3ExprDelete(db, pStep->pWhere); sqlite3SrcListDelete(db, pStep->pSrc); sqlite3DbFree(db, pStep); sqlite3DbFree(db, pTrig->table); sqlite3DbFree(db, pTrig); sqlite3_close(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameResolveTrigger_basic_ok); RUN_TEST(test_renameResolveTrigger_when_constant_ok); RUN_TEST(test_renameResolveTrigger_when_bad_column_error); RUN_TEST(test_renameResolveTrigger_step_with_select_ok); RUN_TEST(test_renameResolveTrigger_step_with_src_and_where_ok); return UNITY_END(); }