#include "sqliteInt.h" #include "unity.h" #include #include /* Wrapper for the static function under test (provided in the build) */ extern int test_renameUnmapSelectCb(Walker *pWalker, Select *p); /* Global counter for expression walker callback invocations */ static int g_expr_walk_count = 0; /* A simple walker expression callback that increments a counter */ static int testExprCallback(Walker *pWalker, Expr *pExpr){ (void)pWalker; (void)pExpr; g_expr_walk_count++; return WRC_Continue; } void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* Helper: append a RenameToken node to Parse->pRename for a given pointer */ static RenameToken* addRenameToken(Parse *pParse, const void *pTarget){ RenameToken *pTok = (RenameToken*)sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); TEST_ASSERT_NOT_NULL_MESSAGE(pTok, "Failed to allocate RenameToken"); pTok->p = (void*)pTarget; pTok->pNext = pParse->pRename; pParse->pRename = pTok; return pTok; } /* Helper: create an empty ExprList object */ static ExprList* makeEmptyExprList(sqlite3 *db){ ExprList *p = (ExprList*)sqlite3DbMallocZero(db, sizeof(ExprList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate ExprList"); /* nExpr = 0; a may be NULL */ return p; } /* Helper: create an empty SrcList object */ static SrcList* makeEmptySrcList(sqlite3 *db){ SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate SrcList"); /* nSrc = 0; a may be NULL */ return p; } /* Helper: allocate an ExprList with n entries */ static ExprList* makeExprListWithN(sqlite3 *db, int n){ ExprList *p = (ExprList*)sqlite3DbMallocZero(db, sizeof(ExprList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate ExprList"); p->nExpr = n; if( n>0 ){ p->a = (struct ExprList_item*)sqlite3DbMallocZero(db, sizeof(struct ExprList_item) * n); TEST_ASSERT_NOT_NULL_MESSAGE(p->a, "Failed to allocate ExprList_item array"); } return p; } /* Helper: allocate a SrcList with n entries */ static SrcList* makeSrcListWithN(sqlite3 *db, int n){ SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate SrcList"); p->nSrc = n; if( n>0 ){ p->a = (struct SrcList_item*)sqlite3DbMallocZero(db, sizeof(struct SrcList_item) * n); TEST_ASSERT_NOT_NULL_MESSAGE(p->a, "Failed to allocate SrcList_item array"); } return p; } /* Helper: create an IdList with n entries and set zName pointers from array */ static IdList* makeIdList(sqlite3 *db, int n, const char **names){ IdList *p = (IdList*)sqlite3DbMallocZero(db, sizeof(IdList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate IdList"); p->nId = n; if( n>0 ){ p->a = (struct IdList_item*)sqlite3DbMallocZero(db, sizeof(struct IdList_item) * n); TEST_ASSERT_NOT_NULL_MESSAGE(p->a, "Failed to allocate IdList_item array"); for(int i=0; ia[i].zName = (char*)names[i]; } } return p; } /* Test 1: Returns WRC_Abort if Parse.nErr is non-zero */ void test_renameUnmapSelectCb_returns_abort_if_nErr(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse sParse; memset(&sParse, 0, sizeof(sParse)); sParse.db = db; sParse.nErr = 1; /* Trigger abort */ Walker w; memset(&w, 0, sizeof(w)); w.pParse = &sParse; w.xExprCallback = testExprCallback; Select sSel; memset(&sSel, 0, sizeof(sSel)); sSel.pEList = makeEmptyExprList(db); sSel.pSrc = makeEmptySrcList(db); int rc = test_renameUnmapSelectCb(&w, &sSel); TEST_ASSERT_EQUAL_INT(WRC_Abort, rc); sqlite3_close(db); } /* Test 2: Returns WRC_Prune when SF_View set and does not unmap tokens */ void test_renameUnmapSelectCb_prunes_on_view_and_preserves_tokens(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse sParse; memset(&sParse, 0, sizeof(sParse)); sParse.db = db; Walker w; memset(&w, 0, sizeof(w)); w.pParse = &sParse; w.xExprCallback = testExprCallback; Select sSel; memset(&sSel, 0, sizeof(sSel)); sSel.selFlags = SF_View; /* Trigger prune path */ sSel.pEList = makeExprListWithN(db, 1); sSel.pSrc = makeSrcListWithN(db, 1); /* Prepare alias and table names with RenameTokens */ const char *alias = "aliasA"; const char *tname = "tabA"; sSel.pEList->a[0].zEName = (char*)alias; sSel.pEList->a[0].fg.eEName = ENAME_NAME; sSel.pSrc->a[0].zName = (char*)tname; RenameToken *pTokAlias = addRenameToken(&sParse, alias); RenameToken *pTokTab = addRenameToken(&sParse, tname); int rc = test_renameUnmapSelectCb(&w, &sSel); TEST_ASSERT_EQUAL_INT(WRC_Prune, rc); /* Ensure tokens are unchanged (not unmapped) due to prune */ TEST_ASSERT_EQUAL_PTR(alias, pTokAlias->p); TEST_ASSERT_EQUAL_PTR(tname, pTokTab->p); sqlite3_close(db); } /* Test 3: Unmaps only ENAME_NAME aliases in ExprList */ void test_renameUnmapSelectCb_unmaps_only_ENAME_NAME_aliases(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse sParse; memset(&sParse, 0, sizeof(sParse)); sParse.db = db; Walker w; memset(&w, 0, sizeof(w)); w.pParse = &sParse; w.xExprCallback = testExprCallback; Select sSel; memset(&sSel, 0, sizeof(sSel)); sSel.pEList = makeExprListWithN(db, 2); sSel.pSrc = makeEmptySrcList(db); /* empty but non-NULL */ const char *alias1 = "alias1"; const char *alias2 = "alias2"; sSel.pEList->a[0].zEName = (char*)alias1; sSel.pEList->a[0].fg.eEName = ENAME_NAME; /* should be unmapped */ sSel.pEList->a[1].zEName = (char*)alias2; sSel.pEList->a[1].fg.eEName = ENAME_NAME + 1; /* different value => unchanged */ RenameToken *pTok1 = addRenameToken(&sParse, alias1); RenameToken *pTok2 = addRenameToken(&sParse, alias2); int rc = test_renameUnmapSelectCb(&w, &sSel); TEST_ASSERT_EQUAL_INT(WRC_Continue, rc); TEST_ASSERT_EQUAL_PTR(NULL, pTok1->p); /* unmapped */ TEST_ASSERT_EQUAL_PTR(alias2, pTok2->p); /* unchanged */ sqlite3_close(db); } /* Test 4: Unmaps SrcList names, walks ON expr for isUsing==0, and unmaps USING(IdList) names for isUsing==1 */ void test_renameUnmapSelectCb_unmaps_srclist_and_walks_on_or_using(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse sParse; memset(&sParse, 0, sizeof(sParse)); sParse.db = db; Walker w; memset(&w, 0, sizeof(w)); w.pParse = &sParse; w.xExprCallback = testExprCallback; Select sSel; memset(&sSel, 0, sizeof(sSel)); sSel.pEList = makeEmptyExprList(db); sSel.pSrc = makeSrcListWithN(db, 2); /* First source: isUsing==0 with ON expression */ const char *tA = "tA"; sSel.pSrc->a[0].zName = (char*)tA; sSel.pSrc->a[0].fg.isUsing = 0; Expr onExpr; memset(&onExpr, 0, sizeof(onExpr)); onExpr.op = TK_NULL; /* simple expression */ sSel.pSrc->a[0].u3.pOn = &onExpr; /* Second source: isUsing==1 with USING(IdList) */ const char *tB = "tB"; sSel.pSrc->a[1].zName = (char*)tB; sSel.pSrc->a[1].fg.isUsing = 1; const char *usingNames[] = { "u1", "u2" }; sSel.pSrc->a[1].u3.pUsing = makeIdList(db, 2, usingNames); RenameToken *pTok_tA = addRenameToken(&sParse, tA); RenameToken *pTok_tB = addRenameToken(&sParse, tB); RenameToken *pTok_u1 = addRenameToken(&sParse, usingNames[0]); RenameToken *pTok_u2 = addRenameToken(&sParse, usingNames[1]); g_expr_walk_count = 0; int rc = test_renameUnmapSelectCb(&w, &sSel); TEST_ASSERT_EQUAL_INT(WRC_Continue, rc); /* Table names unmapped */ TEST_ASSERT_EQUAL_PTR(NULL, pTok_tA->p); TEST_ASSERT_EQUAL_PTR(NULL, pTok_tB->p); /* USING IdList names unmapped */ TEST_ASSERT_EQUAL_PTR(NULL, pTok_u1->p); TEST_ASSERT_EQUAL_PTR(NULL, pTok_u2->p); /* ON expression walker executed at least once */ TEST_ASSERT_TRUE(g_expr_walk_count >= 1); sqlite3_close(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameUnmapSelectCb_returns_abort_if_nErr); RUN_TEST(test_renameUnmapSelectCb_prunes_on_view_and_preserves_tokens); RUN_TEST(test_renameUnmapSelectCb_unmaps_only_ENAME_NAME_aliases); RUN_TEST(test_renameUnmapSelectCb_unmaps_srclist_and_walks_on_or_using); return UNITY_END(); }