AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Wrapper for the static function under test (provided by the module) */6extern void test_codeAttach(7 Parse *pParse,8 int type,9 const FuncDef *pFunc,10 Expr *pAuthArg,11 Expr *pFilename,12 Expr *pDbname,13 Expr *pKey14);15 16/* Dummy scalar function to populate FuncDef.xSFunc */17static void dummy_scalar(sqlite3_context *ctx, int argc, sqlite3_value **argv){18 UNUSED_PARAMETER(argc);19 UNUSED_PARAMETER(argv);20 sqlite3_result_null(ctx);21}22 23/* Helpers */24static sqlite3* open_memory_db(void){25 sqlite3 *db = 0;26 int rc = sqlite3_open(":memory:", &db);27 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);28 TEST_ASSERT_NOT_NULL(db);29 return db;30}31 32static void close_db(sqlite3 *db){33 if( db ){34 sqlite3_close(db);35 }36}37 38static void init_parse(Parse *pParse, sqlite3 *db){39 memset(pParse, 0, sizeof(*pParse));40 pParse->db = db;41}42 43static Expr* make_id_expr(sqlite3 *db, const char *z){44 Token t;45 t.z = z;46 t.n = (int)strlen(z);47 return sqlite3ExprAlloc(db, TK_ID, &t, 0);48}49 50static Expr* make_null_expr(sqlite3 *db){51 return sqlite3ExprAlloc(db, TK_NULL, 0, 0);52}53 54static Expr* make_concat_ids(sqlite3 *db, const char *a, const char *b){55 Expr *pLeft = make_id_expr(db, a);56 Expr *pRight = make_id_expr(db, b);57 Expr *pConcat = sqlite3ExprAlloc(db, TK_CONCAT, 0, 0);58 /* Link children */59 pConcat->pLeft = pLeft;60 pConcat->pRight = pRight;61 return pConcat;62}63 64static void make_funcdef(FuncDef *pFd, int nArg, const char *zName){65 memset(pFd, 0, sizeof(*pFd));66 pFd->nArg = (i8)nArg;67 pFd->funcFlags = SQLITE_UTF8;68 pFd->xSFunc = dummy_scalar;69 pFd->zName = (char*)zName;70}71 72static Op* find_last_op(Vdbe *v){73 if( v==0 || v->nOp<=0 ) return 0;74 return &v->aOp[v->nOp-1];75}76 77static int has_opcode(Vdbe *v, int opcode){78 if( v==0 ) return 0;79 for(int i=0; i<v->nOp; i++){80 if( v->aOp[i].opcode == opcode ) return 1;81 }82 return 0;83}84 85/* Unity fixtures */86void setUp(void) {87 /* no-op */88}89void tearDown(void) {90 /* no-op */91}92 93/* Tests */94 95void test_codeAttach_attach_success_expire_op(void){96 sqlite3 *db = open_memory_db();97 Parse pParse;98 init_parse(&pParse, db);99 100 /* Prepare expressions: treat TK_ID at root; resolver will convert to TK_STRING */101 Expr *pFilename = make_id_expr(db, "abc");102 Expr *pDbname = make_id_expr(db, "db2");103 Expr *pKey = make_null_expr(db);104 105 FuncDef fd;106 make_funcdef(&fd, 3, "sqlite_attach");107 108 /* pAuthArg is the same as pFilename for ATTACH */109 test_codeAttach(&pParse, SQLITE_ATTACH, &fd, pFilename, pFilename, pDbname, pKey);110 111 Vdbe *v = pParse.pVdbe;112 TEST_ASSERT_NOT_NULL(v);113 TEST_ASSERT_TRUE(v->nOp > 0);114 115 /* There should be a function call in the program */116 TEST_ASSERT_TRUE(has_opcode(v, OP_Function));117 118 /* Last op should be OP_Expire with P1=1 for ATTACH */119 Op *pLast = find_last_op(v);120 TEST_ASSERT_NOT_NULL(pLast);121 TEST_ASSERT_EQUAL_INT(OP_Expire, pLast->opcode);122 TEST_ASSERT_EQUAL_INT(1, pLast->p1);123 124 sqlite3VdbeDelete(v);125 pParse.pVdbe = 0;126 close_db(db);127}128 129void test_codeAttach_detach_success_expire_op(void){130 sqlite3 *db = open_memory_db();131 Parse pParse;132 init_parse(&pParse, db);133 134 /* DETACH uses only the dbname; filename/key are unused. */135 Expr *pDbname = make_id_expr(db, "db2");136 137 FuncDef fd;138 make_funcdef(&fd, 1, "sqlite_detach");139 140 test_codeAttach(&pParse, SQLITE_DETACH, &fd, pDbname, 0, pDbname, 0);141 142 Vdbe *v = pParse.pVdbe;143 TEST_ASSERT_NOT_NULL(v);144 TEST_ASSERT_TRUE(v->nOp > 0);145 146 /* There should be a function call in the program */147 TEST_ASSERT_TRUE(has_opcode(v, OP_Function));148 149 /* Last op should be OP_Expire with P1=0 for DETACH */150 Op *pLast = find_last_op(v);151 TEST_ASSERT_NOT_NULL(pLast);152 TEST_ASSERT_EQUAL_INT(OP_Expire, pLast->opcode);153 TEST_ASSERT_EQUAL_INT(0, pLast->p1);154 155 sqlite3VdbeDelete(v);156 pParse.pVdbe = 0;157 close_db(db);158}159 160void test_codeAttach_resolve_failure_on_concat_identifier(void){161 sqlite3 *db = open_memory_db();162 Parse pParse;163 init_parse(&pParse, db);164 165 /* pFilename is a concatenation of two identifiers, which should fail resolveAttachExpr */166 Expr *pFilename = make_concat_ids(db, "abc", "def");167 Expr *pDbname = make_id_expr(db, "db2");168 Expr *pKey = make_null_expr(db);169 170 FuncDef fd;171 make_funcdef(&fd, 3, "sqlite_attach");172 173 test_codeAttach(&pParse, SQLITE_ATTACH, &fd, pFilename, pFilename, pDbname, pKey);174 175 /* Should not create any VDBE because resolution fails */176 TEST_ASSERT_NULL(pParse.pVdbe);177 178 close_db(db);179}180 181static int deny_attach_authorizer(void *pUser, int action,182 const char *z1, const char *z2,183 const char *z3, const char *z4){184 UNUSED_PARAMETER(pUser);185 UNUSED_PARAMETER(z1);186 UNUSED_PARAMETER(z2);187 UNUSED_PARAMETER(z3);188 UNUSED_PARAMETER(z4);189 if( action==SQLITE_ATTACH ) return SQLITE_DENY;190 return SQLITE_OK;191}192 193void test_codeAttach_authorizer_denies(void){194 sqlite3 *db = open_memory_db();195 Parse pParse;196 init_parse(&pParse, db);197 198 /* Install authorizer that denies ATTACH */199 int rc = sqlite3_set_authorizer(db, deny_attach_authorizer, 0);200 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);201 202 Expr *pFilename = make_id_expr(db, "abc");203 Expr *pDbname = make_id_expr(db, "db2");204 Expr *pKey = make_null_expr(db);205 206 FuncDef fd;207 make_funcdef(&fd, 3, "sqlite_attach");208 209 test_codeAttach(&pParse, SQLITE_ATTACH, &fd, pFilename, pFilename, pDbname, pKey);210 211 /* Should not create any VDBE due to authorization failure */212 TEST_ASSERT_NULL(pParse.pVdbe);213 214 /* Cleanup */215 sqlite3_set_authorizer(db, 0, 0);216 close_db(db);217}218 219/* Main */220int main(void){221 UNITY_BEGIN();222 RUN_TEST(test_codeAttach_attach_success_expire_op);223 RUN_TEST(test_codeAttach_detach_success_expire_op);224 RUN_TEST(test_codeAttach_resolve_failure_on_concat_identifier);225 RUN_TEST(test_codeAttach_authorizer_denies);226 return UNITY_END();227}