AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <string.h>6 7/* Global DB handle for tests */8static sqlite3 *gDb = NULL;9 10/* Unity fixtures */11void setUp(void) {12 int rc = sqlite3_open(":memory:", &gDb);13 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);14}15 16void tearDown(void) {17 if (gDb) {18 sqlite3_close(gDb);19 gDb = NULL;20 }21}22 23/* Helper: run arbitrary SQL and assert success */24static void exec_ok(const char *zSql){25 char *zErr = 0;26 int rc = sqlite3_exec(gDb, zSql, 0, 0, &zErr);27 if( zErr ){28 /* Provide context on failure */29 fprintf(stderr, "sqlite3_exec error: %s\n", zErr);30 sqlite3_free(zErr);31 }32 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);33}34 35/* Helper: construct a Token from a C-string literal */36static Token makeToken(const char *z){37 Token t;38 t.z = (char*)z;39 t.n = (int)strlen(z);40 return t;41}42 43/* Helper: constructs an empty/zero-length token (non-NULL pointer, n==0) */44static Token makeEmptyToken(void){45 Token t;46 t.z = (char*)"";47 t.n = 0;48 return t;49}50 51/* Helper: invoke sqlite3Analyze directly and return a copy of the Parse struct.52 Caller must delete pOut->pVdbe (if non-NULL) after use. */53static void call_analyze(Token *p1, Token *p2, Parse *pOut){54 Parse p;55 memset(&p, 0, sizeof(p));56 p.db = gDb;57 58 /* Ensure the assertion in sqlite3Analyze about Btree mutexes holds */59 sqlite3BtreeEnterAll(gDb);60 sqlite3Analyze(&p, p1, p2);61 sqlite3BtreeLeaveAll(gDb);62 63 *pOut = p;64}65 66/* Assert that a parse resulted in a non-empty VDBE program and no parse errors */67static void assert_codegen_success(Parse *p){68 TEST_ASSERT_NOT_NULL(p->pVdbe);69 TEST_ASSERT_TRUE(p->pVdbe->nOp > 0);70 TEST_ASSERT_EQUAL_INT(0, p->nErr);71}72 73/* Cleanup helper: delete VDBE if created */74static void cleanup_parse(Parse *p){75 if( p->pVdbe ){76 sqlite3VdbeDelete(p->pVdbe);77 p->pVdbe = NULL;78 }79}80 81/* Test 1: ANALYZE (form 1) with NULL tokens should generate code for all dbs */82static void test_sqlite3Analyze_analyze_all_generates_vdbe(void){83 /* Create some schema to analyze */84 exec_ok("CREATE TABLE t1(a INTEGER, b TEXT);");85 exec_ok("CREATE INDEX i1 ON t1(a);");86 exec_ok("INSERT INTO t1 VALUES (1,'x'),(2,'y'),(3,'z');");87 88 Parse p;89 call_analyze(NULL, NULL, &p);90 assert_codegen_success(&p);91 cleanup_parse(&p);92}93 94/* Test 2: ANALYZE <database> (form 2) using 'main' */95static void test_sqlite3Analyze_analyze_main_db_generates_vdbe(void){96 exec_ok("CREATE TABLE t2(x);");97 98 Token tDb = makeToken("main");99 Token tEmpty = makeEmptyToken(); /* pName2 must be non-NULL with n==0 */100 101 Parse p;102 call_analyze(&tDb, &tEmpty, &p);103 assert_codegen_success(&p);104 cleanup_parse(&p);105}106 107/* Test 3: ANALYZE <table> (form 3) unqualified table name */108static void test_sqlite3Analyze_analyze_table_unqualified(void){109 exec_ok("CREATE TABLE t3(a, b);");110 exec_ok("CREATE INDEX i3 ON t3(b);");111 exec_ok("INSERT INTO t3 VALUES (10, 'aa'), (20, 'bb');");112 113 Token tTbl = makeToken("t3");114 Token tEmpty = makeEmptyToken();115 116 Parse p;117 call_analyze(&tTbl, &tEmpty, &p);118 assert_codegen_success(&p);119 cleanup_parse(&p);120}121 122/* Test 4: ANALYZE <index> (form 3) by index name */123static void test_sqlite3Analyze_analyze_index_by_name(void){124 exec_ok("CREATE TABLE t4(a, b);");125 exec_ok("CREATE INDEX i4 ON t4(a, b);");126 127 Token tIdx = makeToken("i4");128 Token tEmpty = makeEmptyToken();129 130 Parse p;131 call_analyze(&tIdx, &tEmpty, &p);132 assert_codegen_success(&p);133 cleanup_parse(&p);134}135 136/* Test 5: ANALYZE <schema>.<table> (form 3) qualified name */137static void test_sqlite3Analyze_analyze_table_qualified(void){138 exec_ok("CREATE TABLE t5(a, b);");139 exec_ok("CREATE INDEX i5 ON t5(a);");140 141 Token tDb = makeToken("main");142 Token tTbl = makeToken("t5");143 144 Parse p;145 call_analyze(&tDb, &tTbl, &p);146 assert_codegen_success(&p);147 cleanup_parse(&p);148}149 150/* Test 6: Non-existent table should set parse error (nErr>0) */151static void test_sqlite3Analyze_nonexistent_table_sets_error(void){152 Token tTbl = makeToken("no_such_table");153 Token tEmpty = makeEmptyToken();154 155 Parse p;156 call_analyze(&tTbl, &tEmpty, &p);157 158 /* Expect a parse error due to sqlite3LocateTable() failure */159 TEST_ASSERT_TRUE(p.nErr > 0);160 /* A VDBE object may or may not be present; if present it should be valid */161 if( p.pVdbe ){162 TEST_ASSERT_TRUE(p.pVdbe->nOp >= 0);163 }164 cleanup_parse(&p);165}166 167/* Test 7: ANALYZE temp database explicitly (form 2) */168static void test_sqlite3Analyze_analyze_temp_db(void){169 exec_ok("CREATE TEMP TABLE tt(x);");170 exec_ok("CREATE INDEX temp.ti ON tt(x);");171 exec_ok("INSERT INTO tt VALUES (1),(2),(3);");172 173 Token tDb = makeToken("temp");174 Token tEmpty = makeEmptyToken();175 176 Parse p;177 call_analyze(&tDb, &tEmpty, &p);178 assert_codegen_success(&p);179 cleanup_parse(&p);180}181 182int main(void) {183 UNITY_BEGIN();184 RUN_TEST(test_sqlite3Analyze_analyze_all_generates_vdbe);185 RUN_TEST(test_sqlite3Analyze_analyze_main_db_generates_vdbe);186 RUN_TEST(test_sqlite3Analyze_analyze_table_unqualified);187 RUN_TEST(test_sqlite3Analyze_analyze_index_by_name);188 RUN_TEST(test_sqlite3Analyze_analyze_table_qualified);189 RUN_TEST(test_sqlite3Analyze_nonexistent_table_sets_error);190 RUN_TEST(test_sqlite3Analyze_analyze_temp_db);191 return UNITY_END();192}