File size: 5,059 Bytes
7510827 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdlib.h>
/* Unity setUp/tearDown */
void setUp(void) {
/* No global setup required */
}
void tearDown(void) {
/* No global teardown required */
}
/* Helper: create a SrcList with one item for table zTab in database zDb (or NULL for main) */
static SrcList *makeSrcListOne(sqlite3 *db, const char *zDb, const char *zTab){
/* SrcList has a flexible array a[1], so sizeof(SrcList) is sufficient for one element */
SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));
TEST_ASSERT_NOT_NULL_MESSAGE(p, "sqlite3DbMallocZero failed creating SrcList");
p->nAlloc = 1;
p->nSrc = 1;
p->a[0].zName = sqlite3DbStrDup(db, zTab);
TEST_ASSERT_NOT_NULL_MESSAGE(p->a[0].zName, "sqlite3DbStrDup failed for table name");
if( zDb ){
p->a[0].zDatabase = sqlite3DbStrDup(db, zDb);
TEST_ASSERT_NOT_NULL_MESSAGE(p->a[0].zDatabase, "sqlite3DbStrDup failed for database name");
}
return p;
}
/* Helper: make a Token from a C string literal */
static Token makeToken(const char *z){
Token t;
t.z = z;
t.n = (int)strlen(z);
return t;
}
/* Helper: initialize a Parse object for a given db */
static void initParse(Parse *pParse, sqlite3 *db){
memset(pParse, 0, sizeof(*pParse));
pParse->db = db;
}
/* Helper: exec SQL and assert SQLITE_OK */
static void execSqlOk(sqlite3 *db, const char *zSql){
int rc = sqlite3_exec(db, zSql, 0, 0, 0);
if( rc!=SQLITE_OK ){
const char *err = sqlite3_errmsg(db);
char msg[512];
sqlite3_snprintf(sizeof(msg), msg, "SQL exec failed (%d): %s; SQL: %s", rc, err ? err : "(null)", zSql);
TEST_FAIL_MESSAGE(msg);
}
}
/* Test: Nonexistent table should cause early return: no VDBE and an error recorded */
void test_sqlite3AlterDropConstraint_nonexistent_table(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
Parse p;
initParse(&p, db);
SrcList *pSrc = makeSrcListOne(db, NULL, "nosuchtable");
Token cons = makeToken("c1");
sqlite3AlterDropConstraint(&p, pSrc, &cons, 0);
TEST_ASSERT_NULL_MESSAGE(p.pVdbe, "VDBE should not be created for nonexistent table");
TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "An error should be recorded for nonexistent table");
sqlite3SrcListDelete(db, pSrc);
if( p.pVdbe ) sqlite3VdbeDelete(p.pVdbe);
sqlite3_close(db);
}
/* Test: Existing table, drop NOT NULL from existing column -> code generated (VDBE created) */
void test_sqlite3AlterDropConstraint_drop_not_null_on_existing_col_generates_code(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
execSqlOk(db, "CREATE TABLE t1(a INTEGER NOT NULL, b TEXT);");
Parse p;
initParse(&p, db);
SrcList *pSrc = makeSrcListOne(db, NULL, "t1");
Token col = makeToken("a");
sqlite3AlterDropConstraint(&p, pSrc, 0, &col);
TEST_ASSERT_NOT_NULL_MESSAGE(p.pVdbe, "VDBE should be created for valid DROP NOT NULL operation");
/* We do not execute the VDBE here; we only ensure code generation occurred. */
sqlite3SrcListDelete(db, pSrc);
if( p.pVdbe ) sqlite3VdbeDelete(p.pVdbe);
sqlite3_close(db);
}
/* Test: Existing table, drop NOT NULL from nonexistent column -> error, no VDBE */
void test_sqlite3AlterDropConstraint_nonexistent_column_reports_error(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
execSqlOk(db, "CREATE TABLE t2(a INTEGER NOT NULL, b TEXT);");
Parse p;
initParse(&p, db);
SrcList *pSrc = makeSrcListOne(db, NULL, "t2");
Token col = makeToken("no_such_col");
sqlite3AlterDropConstraint(&p, pSrc, 0, &col);
TEST_ASSERT_NULL_MESSAGE(p.pVdbe, "VDBE should not be created when column does not exist");
TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "An error should be recorded for nonexistent column");
sqlite3SrcListDelete(db, pSrc);
if( p.pVdbe ) sqlite3VdbeDelete(p.pVdbe);
sqlite3_close(db);
}
/* Test: Existing table with named constraint, drop named constraint -> code generated */
void test_sqlite3AlterDropConstraint_drop_named_constraint_generates_code(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
/* Create a table with a named CHECK constraint */
execSqlOk(db, "CREATE TABLE t3(x INT, y INT, CONSTRAINT c1 CHECK(x>0));");
Parse p;
initParse(&p, db);
SrcList *pSrc = makeSrcListOne(db, NULL, "t3");
Token cons = makeToken("c1");
sqlite3AlterDropConstraint(&p, pSrc, &cons, 0);
TEST_ASSERT_NOT_NULL_MESSAGE(p.pVdbe, "VDBE should be created for valid DROP CONSTRAINT operation");
sqlite3SrcListDelete(db, pSrc);
if( p.pVdbe ) sqlite3VdbeDelete(p.pVdbe);
sqlite3_close(db);
}
int main(void){
UNITY_BEGIN();
RUN_TEST(test_sqlite3AlterDropConstraint_nonexistent_table);
RUN_TEST(test_sqlite3AlterDropConstraint_drop_not_null_on_existing_col_generates_code);
RUN_TEST(test_sqlite3AlterDropConstraint_nonexistent_column_reports_error);
RUN_TEST(test_sqlite3AlterDropConstraint_drop_named_constraint_generates_code);
return UNITY_END();
} |