#include "sqliteInt.h" #include "unity.h" #include /* The wrapper for the static function under test (provided in the module). */ extern void test_renameParseCleanup(Parse *pParse); static void init_parse_with_allocs(sqlite3 *db, Parse *pParse){ memset(pParse, 0, sizeof(*pParse)); pParse->db = db; /* Create a VDBE so that finalize is exercised. */ pParse->pVdbe = sqlite3VdbeCreate(db); /* Allocate a new Table */ pParse->pNewTable = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); /* Allocate a linked list of Index objects */ Index *pIdx1 = (Index*)sqlite3DbMallocZero(db, sizeof(Index)); Index *pIdx2 = (Index*)sqlite3DbMallocZero(db, sizeof(Index)); if( pIdx1 ) pIdx1->pNext = pIdx2; pParse->pNewIndex = pIdx1; /* Allocate a Trigger */ pParse->pNewTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); /* Allocate an error message */ pParse->zErrMsg = sqlite3DbStrDup(db, "unit-test-error"); /* Allocate a linked list of RenameToken */ RenameToken *t1 = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); RenameToken *t2 = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); if( t1 ) t1->pNext = t2; pParse->pRename = t1; } void setUp(void) { /* No-op */ } void tearDown(void) { /* No-op */ } static void assert_parse_pointers_cleared(Parse *p){ TEST_ASSERT_NULL(p->pVdbe); TEST_ASSERT_NULL(p->pNewTable); TEST_ASSERT_NULL(p->pNewIndex); TEST_ASSERT_NULL(p->pNewTrigger); TEST_ASSERT_NULL(p->zErrMsg); TEST_ASSERT_NULL(p->pRename); } /* Test that renameParseCleanup frees all populated fields and resets them. */ void test_renameParseCleanup_clears_all_fields(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(db); Parse p; init_parse_with_allocs(db, &p); test_renameParseCleanup(&p); /* After cleanup, all relevant pointers should be NULL. */ assert_parse_pointers_cleared(&p); /* Database should be cleanly closable (VDBE finalized). */ rc = sqlite3_close(db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } /* Test that renameParseCleanup is safe when all fields are NULL. */ void test_renameParseCleanup_handles_null_fields(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(db); Parse p; memset(&p, 0, sizeof(p)); p.db = db; /* Everything NULL already */ test_renameParseCleanup(&p); /* Still NULL after cleanup */ assert_parse_pointers_cleared(&p); rc = sqlite3_close(db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } /* Test with longer lists of Index and RenameToken to ensure full traversal/free. */ void test_renameParseCleanup_multiple_indexes_and_tokens(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(db); Parse p; memset(&p, 0, sizeof(p)); p.db = db; /* Create a VDBE */ p.pVdbe = sqlite3VdbeCreate(db); /* Create 3 Index nodes */ Index *i1 = (Index*)sqlite3DbMallocZero(db, sizeof(Index)); Index *i2 = (Index*)sqlite3DbMallocZero(db, sizeof(Index)); Index *i3 = (Index*)sqlite3DbMallocZero(db, sizeof(Index)); if( i1 ) i1->pNext = i2; if( i2 ) i2->pNext = i3; p.pNewIndex = i1; /* Create 3 RenameToken nodes */ RenameToken *t1 = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); RenameToken *t2 = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); RenameToken *t3 = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); if( t1 ) t1->pNext = t2; if( t2 ) t2->pNext = t3; p.pRename = t1; /* Also set a table, trigger, and error message */ p.pNewTable = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); p.pNewTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); p.zErrMsg = sqlite3DbStrDup(db, "err"); test_renameParseCleanup(&p); /* Ensure all pointers are cleared */ assert_parse_pointers_cleared(&p); rc = sqlite3_close(db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } /* Test idempotency: calling cleanup twice should be safe and keep pointers NULL. */ void test_renameParseCleanup_idempotent_double_call(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(db); Parse p; init_parse_with_allocs(db, &p); /* First cleanup */ test_renameParseCleanup(&p); assert_parse_pointers_cleared(&p); /* Second cleanup - should be a no-op and not crash */ test_renameParseCleanup(&p); assert_parse_pointers_cleared(&p); rc = sqlite3_close(db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameParseCleanup_clears_all_fields); RUN_TEST(test_renameParseCleanup_handles_null_fields); RUN_TEST(test_renameParseCleanup_multiple_indexes_and_tokens); RUN_TEST(test_renameParseCleanup_idempotent_double_call); return UNITY_END(); }