#include "sqliteInt.h" #include "unity.h" #include #include /* Unity setup/teardown */ void setUp(void) { /* empty */ } void tearDown(void) { /* empty */ } /* Helper: initialize a Parse object */ static void initParse(Parse *pParse, sqlite3 *db, const char *zCons){ memset(pParse, 0, sizeof(*pParse)); pParse->db = db; if( zCons ){ /* sLastToken.z should point to the end of constraint text buffer */ pParse->sLastToken.z = zCons + strlen(zCons); pParse->sLastToken.n = 0; /* not used by sqlite3AlterSetNotNull */ } } /* Helper: create a SrcList for zDb.zTab (zDb may be NULL for "main") */ static SrcList* makeSrcList(sqlite3 *db, const char *zDb, const char *zTab){ SrcList *p = 0; Token tTab, tDb; tTab.z = zTab; tTab.n = (int)strlen(zTab); if( zDb ){ tDb.z = zDb; tDb.n = (int)strlen(zDb); p = sqlite3SrcListAppend(db, 0, &tTab, &tDb); }else{ p = sqlite3SrcListAppend(db, 0, &tTab, 0); } return p; } /* Helper: free error message in Parse */ static void freeParseError(sqlite3 *db, Parse *pParse){ if( pParse->zErrMsg ){ sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = 0; } } /* Test: table does not exist */ static void test_sqlite3AlterSetNotNull_table_not_found(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Prepare Parse and inputs */ const char *zCons = "NOT NULL -- trailing comment"; Parse sParse; initParse(&sParse, db, zCons); SrcList *pSrc = makeSrcList(db, 0, "nosuchtable"); TEST_ASSERT_NOT_NULL(pSrc); Token colTok; colTok.z = "a"; colTok.n = 1; Token firstTok; firstTok.z = zCons; firstTok.n = 3; /* "NOT" */ /* Call target */ sqlite3AlterSetNotNull(&sParse, pSrc, &colTok, &firstTok); /* Validate: error reported, and no vdbe created */ TEST_ASSERT_TRUE(sParse.nErr > 0); TEST_ASSERT_NOT_NULL(sParse.zErrMsg); TEST_ASSERT_NULL(sParse.pVdbe); /* Cleanup */ freeParseError(db, &sParse); sqlite3SrcListDelete(db, pSrc); sqlite3_close(db); } /* Test: table exists, column does not */ static void test_sqlite3AlterSetNotNull_column_not_found(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); rc = sqlite3_exec(db, "CREATE TABLE t(a, b);", 0, 0, 0); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); const char *zCons = "NOT NULL -- trim me"; Parse sParse; initParse(&sParse, db, zCons); SrcList *pSrc = makeSrcList(db, 0, "t"); TEST_ASSERT_NOT_NULL(pSrc); Token colTok; colTok.z = "c"; /* non-existent column */ colTok.n = 1; Token firstTok; firstTok.z = zCons; firstTok.n = 3; sqlite3AlterSetNotNull(&sParse, pSrc, &colTok, &firstTok); /* Expect an error: "no such column" and no VDBE */ TEST_ASSERT_TRUE(sParse.nErr > 0); TEST_ASSERT_NOT_NULL(sParse.zErrMsg); if( sParse.zErrMsg ){ TEST_ASSERT_NOT_NULL(strstr(sParse.zErrMsg, "no such column")); } TEST_ASSERT_NULL(sParse.pVdbe); /* Cleanup */ freeParseError(db, &sParse); sqlite3SrcListDelete(db, pSrc); sqlite3_close(db); } /* Test: success path - table and column exist, VDBE program is generated */ static void test_sqlite3AlterSetNotNull_success_creates_vdbe_program(void){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); rc = sqlite3_exec(db, "CREATE TABLE t(a, b);", 0, 0, 0); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); rc = sqlite3_exec(db, "INSERT INTO t(a,b) VALUES(1,2),(3,4);", 0, 0, 0); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); const char *zCons = "NOT NULL -- ensure trimming and comment handling"; Parse sParse; initParse(&sParse, db, zCons); SrcList *pSrc = makeSrcList(db, 0, "t"); TEST_ASSERT_NOT_NULL(pSrc); Token colTok; colTok.z = "a"; colTok.n = 1; Token firstTok; firstTok.z = zCons; firstTok.n = 3; /* "NOT" */ sqlite3AlterSetNotNull(&sParse, pSrc, &colTok, &firstTok); /* No parse error expected, and a VDBE should have been created */ TEST_ASSERT_EQUAL_INT(0, sParse.nErr); TEST_ASSERT_NULL(sParse.zErrMsg); TEST_ASSERT_NOT_NULL(sParse.pVdbe); /* The VDBE should have at least one opcode generated by sqlite3NestedParse */ if( sParse.pVdbe ){ int nOp = sqlite3VdbeCurrentAddr(sParse.pVdbe); TEST_ASSERT_TRUE(nOp > 0); } /* Cleanup */ if( sParse.pVdbe ){ sqlite3VdbeDelete(sParse.pVdbe); sParse.pVdbe = 0; } sqlite3SrcListDelete(db, pSrc); sqlite3_close(db); } /* main */ int main(void){ UNITY_BEGIN(); RUN_TEST(test_sqlite3AlterSetNotNull_table_not_found); RUN_TEST(test_sqlite3AlterSetNotNull_column_not_found); RUN_TEST(test_sqlite3AlterSetNotNull_success_creates_vdbe_program); return UNITY_END(); }