AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5#include <stdlib.h>6 7/* Global database handle for each test */8static sqlite3 *gDb = NULL;9 10/* Convenience helpers to safely enter/leave the db mutex */11static void enterDbMutex(sqlite3 *db){12 if( db && db->mutex ) sqlite3_mutex_enter(db->mutex);13}14static void leaveDbMutex(sqlite3 *db){15 if( db && db->mutex ) sqlite3_mutex_leave(db->mutex);16}17 18/* Initialize an InitData struct with sensible defaults */19static void init_InitData(InitData *p, sqlite3 *db, int iDb, char **pzErr){20 memset(p, 0, sizeof(*p));21 p->db = db;22 p->iDb = iDb;23 p->mxPage = 0; /* 0 disables the >mxPage extra check */24 p->pzErrMsg = pzErr;25 p->rc = SQLITE_OK;26 p->nInitRow = 0;27 p->mInitFlags = 0;28}29 30void setUp(void) {31 int rc = sqlite3_open(":memory:", &gDb);32 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);33 TEST_ASSERT_NOT_NULL(gDb);34}35 36void tearDown(void) {37 if( gDb ){38 int rc = sqlite3_close(gDb);39 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);40 gDb = NULL;41 }42}43 44/* Test: argv==NULL should return 0 and not increment nInitRow */45void test_sqlite3InitCallback_null_argv_returns0(void){46 InitData d;47 char *zErr = 0;48 init_InitData(&d, gDb, 0, &zErr);49 50 enterDbMutex(gDb);51 int rc = sqlite3InitCallback(&d, 5, NULL, NULL);52 leaveDbMutex(gDb);53 54 TEST_ASSERT_EQUAL_INT(0, rc);55 TEST_ASSERT_EQUAL_INT(0, d.nInitRow);56 TEST_ASSERT_EQUAL_INT(SQLITE_OK, d.rc);57 TEST_ASSERT_NULL(zErr);58}59 60/* Test: Successful CREATE TABLE processing builds schema object */61void test_sqlite3InitCallback_create_builds_schema(void){62 InitData d;63 char *zErr = 0;64 init_InitData(&d, gDb, 0, &zErr);65 66 const char *type = "table";67 const char *name = "cb_t1";68 const char *tbl = "cb_t1";69 const char *root = "2";70 const char *sql = "CREATE TABLE cb_t1(a)";71 72 char *argv[5];73 argv[0] = (char*)type;74 argv[1] = (char*)name;75 argv[2] = (char*)tbl;76 argv[3] = (char*)root;77 argv[4] = (char*)sql;78 79 /* Ensure init mode is set, and mutex is held */80 enterDbMutex(gDb);81 int savedBusy = gDb->init.busy;82 gDb->init.busy = 1;83 84 int cbRc = sqlite3InitCallback(&d, 5, argv, NULL);85 86 /* Restore busy and unlock */87 gDb->init.busy = savedBusy;88 leaveDbMutex(gDb);89 90 TEST_ASSERT_EQUAL_INT(0, cbRc);91 TEST_ASSERT_EQUAL_INT(1, d.nInitRow);92 TEST_ASSERT_EQUAL_INT(SQLITE_OK, d.rc);93 TEST_ASSERT_NULL(zErr);94 95 /* Verify the Table now exists in the schema */96 enterDbMutex(gDb);97 Table *pTab = sqlite3FindTable(gDb, name, "main");98 leaveDbMutex(gDb);99 TEST_ASSERT_NOT_NULL(pTab);100}101 102/* Test: NULL rootpage (argv[3]==NULL) triggers corruptSchema */103void test_sqlite3InitCallback_null_rootpage_triggers_corrupt(void){104 InitData d;105 char *zErr = 0;106 init_InitData(&d, gDb, 0, &zErr);107 108 char *argv[5];109 argv[0] = "table";110 argv[1] = "t_badroot";111 argv[2] = "t_badroot";112 argv[3] = NULL; /* NULL rootpage */113 argv[4] = "CREATE TABLE t_badroot(x)";114 115 enterDbMutex(gDb);116 int savedBusy = gDb->init.busy;117 gDb->init.busy = 1;118 119 int rc = sqlite3InitCallback(&d, 5, argv, NULL);120 121 gDb->init.busy = savedBusy;122 leaveDbMutex(gDb);123 124 TEST_ASSERT_EQUAL_INT(0, rc);125 TEST_ASSERT_NOT_EQUAL(SQLITE_OK, d.rc);126 TEST_ASSERT_NOT_NULL(zErr);127 /* Clean up error string */128 sqlite3DbFree(gDb, zErr); zErr = 0;129}130 131/* Test: Syntax error during CREATE triggers corruptSchema */132void test_sqlite3InitCallback_syntax_error_triggers_corrupt(void){133 InitData d;134 char *zErr = 0;135 init_InitData(&d, gDb, 0, &zErr);136 137 char *argv[5];138 argv[0] = "table";139 argv[1] = "t_syntax";140 argv[2] = "t_syntax";141 argv[3] = "7";142 argv[4] = "CREATE TABL t_syntax(a)"; /* deliberate syntax error */143 144 enterDbMutex(gDb);145 int savedBusy = gDb->init.busy;146 gDb->init.busy = 1;147 148 int rc = sqlite3InitCallback(&d, 5, argv, NULL);149 150 gDb->init.busy = savedBusy;151 leaveDbMutex(gDb);152 153 TEST_ASSERT_EQUAL_INT(0, rc);154 TEST_ASSERT_NOT_EQUAL(SQLITE_OK, d.rc);155 TEST_ASSERT_NOT_NULL(zErr);156 /* The message should reflect malformed database schema */157 TEST_ASSERT_NOT_EQUAL(NULL, strstr(zErr, "malformed database schema"));158 sqlite3DbFree(gDb, zErr); zErr = 0;159}160 161/* Test: Non-CREATE with non-empty SQL triggers corruptSchema */162void test_sqlite3InitCallback_noncreate_nonempty_sql_triggers_corrupt(void){163 InitData d;164 char *zErr = 0;165 init_InitData(&d, gDb, 0, &zErr);166 167 char *argv[5];168 argv[0] = "table";169 argv[1] = "t_misc";170 argv[2] = "t_misc";171 argv[3] = "10";172 argv[4] = "INSERT INTO t_misc VALUES(1)"; /* Not a CREATE statement */173 174 enterDbMutex(gDb);175 int rc = sqlite3InitCallback(&d, 5, argv, NULL);176 leaveDbMutex(gDb);177 178 TEST_ASSERT_EQUAL_INT(0, rc);179 TEST_ASSERT_NOT_EQUAL(SQLITE_OK, d.rc);180 TEST_ASSERT_NOT_NULL(zErr);181 sqlite3DbFree(gDb, zErr); zErr = 0;182}183 184/* Test: Blank-SQL index row sets the rootpage on an existing auto-index */185void test_sqlite3InitCallback_autoindex_blank_sql_sets_rootpage(void){186 /* First create a table with a PRIMARY KEY to ensure an auto-index exists */187 int rc = sqlite3_exec(gDb, "CREATE TABLE tidx(a PRIMARY KEY)", 0, 0, 0);188 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);189 190 /* Verify the auto-index exists */191 enterDbMutex(gDb);192 Index *pIdxPre = sqlite3FindIndex(gDb, "sqlite_autoindex_tidx_1", "main");193 leaveDbMutex(gDb);194 TEST_ASSERT_NOT_NULL(pIdxPre);195 196 InitData d;197 char *zErr = 0;198 init_InitData(&d, gDb, 0, &zErr);199 200 char *argv[5];201 argv[0] = "index";202 argv[1] = "sqlite_autoindex_tidx_1";203 argv[2] = "tidx";204 argv[3] = "42"; /* new rootpage to set */205 argv[4] = ""; /* blank SQL indicates auto-index row */206 207 enterDbMutex(gDb);208 rc = sqlite3InitCallback(&d, 5, argv, NULL);209 leaveDbMutex(gDb);210 211 TEST_ASSERT_EQUAL_INT(0, rc);212 TEST_ASSERT_EQUAL_INT(SQLITE_OK, d.rc);213 TEST_ASSERT_NULL(zErr);214 215 /* Confirm tnum was updated */216 enterDbMutex(gDb);217 Index *pIdxPost = sqlite3FindIndex(gDb, "sqlite_autoindex_tidx_1", "main");218 leaveDbMutex(gDb);219 TEST_ASSERT_NOT_NULL(pIdxPost);220 TEST_ASSERT_EQUAL_INT(42, (int)pIdxPost->tnum);221}222 223/* Test: Orphan index (blank SQL but index not found) triggers corruptSchema */224void test_sqlite3InitCallback_orphan_index_error(void){225 InitData d;226 char *zErr = 0;227 init_InitData(&d, gDb, 0, &zErr);228 229 char *argv[5];230 argv[0] = "index";231 argv[1] = "i_not_exist";232 argv[2] = "some_table";233 argv[3] = "99";234 argv[4] = ""; /* blank SQL => should look for existing index */235 236 enterDbMutex(gDb);237 int rc = sqlite3InitCallback(&d, 5, argv, NULL);238 leaveDbMutex(gDb);239 240 TEST_ASSERT_EQUAL_INT(0, rc);241 TEST_ASSERT_NOT_EQUAL(SQLITE_OK, d.rc);242 TEST_ASSERT_NOT_NULL(zErr);243 TEST_ASSERT_NOT_EQUAL(NULL, strstr(zErr, "orphan index"));244 sqlite3DbFree(gDb, zErr); zErr = 0;245}246 247int main(void) {248 UNITY_BEGIN();249 250 RUN_TEST(test_sqlite3InitCallback_null_argv_returns0);251 RUN_TEST(test_sqlite3InitCallback_create_builds_schema);252 RUN_TEST(test_sqlite3InitCallback_null_rootpage_triggers_corrupt);253 RUN_TEST(test_sqlite3InitCallback_syntax_error_triggers_corrupt);254 RUN_TEST(test_sqlite3InitCallback_noncreate_nonempty_sql_triggers_corrupt);255 RUN_TEST(test_sqlite3InitCallback_autoindex_blank_sql_sets_rootpage);256 RUN_TEST(test_sqlite3InitCallback_orphan_index_error);257 258 return UNITY_END();259}