#include "sqliteInt.h" #include "unity.h" #include #include /* Forward declaration of function under test */ void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom); static void* allocByte(unsigned char v){ unsigned char *p = (unsigned char*)sqlite3_malloc(1); TEST_ASSERT_NOT_NULL(p); *p = v; return (void*)p; } static void freeIf(void *p){ if(p) sqlite3_free(p); } static void initParseWithDb(Parse *pParse, sqlite3 **ppDb){ int rc; sqlite3 *db = 0; memset(pParse, 0, sizeof(*pParse)); rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); TEST_ASSERT_NOT_NULL(db); pParse->db = db; db->pParse = pParse; db->mallocFailed = 0; *ppDb = db; } static void cleanupDb(sqlite3 *db){ if(db){ db->pParse = 0; sqlite3_close(db); } } void setUp(void) { /* no-op */ } void tearDown(void) { /* no-op */ } /* Test 1: Basic remap when pFrom is found in the list (nErr==0). Ensure only the first matching token is updated and others unchanged. */ void test_sqlite3RenameTokenRemap_basic_remap(void){ Parse parse; sqlite3 *db = NULL; initParseWithDb(&parse, &db); parse.nErr = 0; /* Create distinct valid pointers for dereference */ void *pA = allocByte(0xA1); void *pB = allocByte(0xB2); void *pC = allocByte(0xC3); void *pX = allocByte(0x5A); /* pTo: ensure not equal to any existing p */ /* Build RenameToken list: A -> B -> C */ RenameToken rt1, rt2, rt3; memset(&rt1, 0, sizeof(rt1)); memset(&rt2, 0, sizeof(rt2)); memset(&rt3, 0, sizeof(rt3)); rt1.p = pA; rt1.pNext = &rt2; rt2.p = pB; rt2.pNext = &rt3; rt3.p = pC; rt3.pNext = NULL; parse.pRename = &rt1; /* Act */ sqlite3RenameTokenRemap(&parse, pX, pB); /* Assert */ TEST_ASSERT_EQUAL_PTR(pA, rt1.p); TEST_ASSERT_EQUAL_PTR(pX, rt2.p); TEST_ASSERT_EQUAL_PTR(pC, rt3.p); /* Cleanup */ freeIf(pA); freeIf(pB); freeIf(pC); freeIf(pX); cleanupDb(db); } /* Test 2: No match for pFrom in the list (nErr==0). Ensure list remains unchanged. */ void test_sqlite3RenameTokenRemap_no_match(void){ Parse parse; sqlite3 *db = NULL; initParseWithDb(&parse, &db); parse.nErr = 0; void *pA = allocByte(0x11); void *pB = allocByte(0x22); void *pC = allocByte(0x33); void *pZ = allocByte(0x44); /* pFrom not in list */ void *pTo = allocByte(0x55); /* unique pTo not in list */ RenameToken rt1, rt2, rt3; memset(&rt1, 0, sizeof(rt1)); memset(&rt2, 0, sizeof(rt2)); memset(&rt3, 0, sizeof(rt3)); rt1.p = pA; rt1.pNext = &rt2; rt2.p = pB; rt2.pNext = &rt3; rt3.p = pC; rt3.pNext = NULL; parse.pRename = &rt1; sqlite3RenameTokenRemap(&parse, pTo, pZ); TEST_ASSERT_EQUAL_PTR(pA, rt1.p); TEST_ASSERT_EQUAL_PTR(pB, rt2.p); TEST_ASSERT_EQUAL_PTR(pC, rt3.p); freeIf(pA); freeIf(pB); freeIf(pC); freeIf(pZ); freeIf(pTo); cleanupDb(db); } /* Test 3: Multiple matches for pFrom; only the first should be remapped (nErr==0). */ void test_sqlite3RenameTokenRemap_multiple_matches_first_only(void){ Parse parse; sqlite3 *db = NULL; initParseWithDb(&parse, &db); parse.nErr = 0; void *pM = allocByte(0x77); void *pOther = allocByte(0x88); void *pNew = allocByte(0x99); /* unique pTo not in list */ RenameToken rt1, rt2, rt3; memset(&rt1, 0, sizeof(rt1)); memset(&rt2, 0, sizeof(rt2)); memset(&rt3, 0, sizeof(rt3)); rt1.p = pM; rt1.pNext = &rt2; rt2.p = pOther; rt2.pNext = &rt3; rt3.p = pM; rt3.pNext = NULL; parse.pRename = &rt1; sqlite3RenameTokenRemap(&parse, pNew, pM); TEST_ASSERT_EQUAL_PTR(pNew, rt1.p); TEST_ASSERT_EQUAL_PTR(pOther, rt2.p); TEST_ASSERT_EQUAL_PTR(pM, rt3.p); /* unchanged */ freeIf(pM); freeIf(pOther); freeIf(pNew); cleanupDb(db); } /* Test 4: pParse->nErr != 0 bypasses the renameTokenCheckAll deref and P==pTo check. Here, pTo equals an existing pointer in the list. */ void test_sqlite3RenameTokenRemap_nErr_nonzero_allows_pTo_equal_existing(void){ Parse parse; sqlite3 *db = NULL; initParseWithDb(&parse, &db); parse.nErr = 1; /* bypass renameTokenCheckAll internal deref and equality assert */ void *pA = allocByte(0xAB); void *pB = allocByte(0xBC); RenameToken rt1, rt2; memset(&rt1, 0, sizeof(rt1)); memset(&rt2, 0, sizeof(rt2)); rt1.p = pA; rt1.pNext = &rt2; rt2.p = pB; rt2.pNext = NULL; parse.pRename = &rt1; /* pTo equals existing pointer (rt2.p) */ sqlite3RenameTokenRemap(&parse, pB, pA); TEST_ASSERT_EQUAL_PTR(pB, rt1.p); TEST_ASSERT_EQUAL_PTR(pB, rt2.p); /* Cleanup: avoid double-free: both tokens point to pB now */ freeIf(pA); freeIf(pB); cleanupDb(db); } /* Test 5: List contains a NULL pointer entry; function should skip it safely (nErr==0). */ void test_sqlite3RenameTokenRemap_handles_null_token_pointers(void){ Parse parse; sqlite3 *db = NULL; initParseWithDb(&parse, &db); parse.nErr = 0; void *pA = allocByte(0x01); void *pNew = allocByte(0x02); RenameToken rt1, rt2; memset(&rt1, 0, sizeof(rt1)); memset(&rt2, 0, sizeof(rt2)); rt1.p = NULL; rt1.pNext = &rt2; rt2.p = pA; rt2.pNext = NULL; parse.pRename = &rt1; sqlite3RenameTokenRemap(&parse, pNew, pA); TEST_ASSERT_NULL(rt1.p); TEST_ASSERT_EQUAL_PTR(pNew, rt2.p); freeIf(pA); freeIf(pNew); cleanupDb(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_sqlite3RenameTokenRemap_basic_remap); RUN_TEST(test_sqlite3RenameTokenRemap_no_match); RUN_TEST(test_sqlite3RenameTokenRemap_multiple_matches_first_only); RUN_TEST(test_sqlite3RenameTokenRemap_nErr_nonzero_allows_pTo_equal_existing); RUN_TEST(test_sqlite3RenameTokenRemap_handles_null_token_pointers); return UNITY_END(); }