AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Global database handle for tests */7static sqlite3 *gDb = NULL;8 9/* Helper: allocate and zero memory tied to db */10static void *dbMalloc(sqlite3 *db, int n){11 void *p = sqlite3DbMallocZero(db, n);12 TEST_ASSERT_MESSAGE(p != NULL, "sqlite3DbMallocZero returned NULL");13 return p;14}15 16/* Helper: create a basic Expr with given op and zToken */17static Expr *makeExprOpToken(sqlite3 *db, int op, const char *zToken){18 Expr *p = (Expr*)dbMalloc(db, sizeof(Expr));19 memset(p, 0, sizeof(Expr));20 p->op = (u8)op;21 p->u.zToken = (char*)zToken; /* zToken is only read; test uses string literals */22 return p;23}24 25/* Helper: create a TK_STRING Expr with given content (no quotes) */26static Expr *makeStringExpr(sqlite3 *db, const char *z){27 return makeExprOpToken(db, TK_STRING, z);28}29 30/* Helper: create a TK_NULL Expr (content unused) */31static Expr *makeNullExpr(sqlite3 *db){32 return makeExprOpToken(db, TK_NULL, NULL);33}34 35/* Helper: free an Expr recursively if it contains an ExprList */36static void freeExpr(sqlite3 *db, Expr *p){37 if( p==NULL ) return;38 if( p->op==TK_FUNCTION && ExprUseXList(p) && p->x.pList ){39 ExprList *pList = p->x.pList;40 int i;41 for(i=0; i<pList->nExpr; i++){42 if( pList->a[i].pExpr ){43 freeExpr(db, pList->a[i].pExpr);44 pList->a[i].pExpr = NULL;45 }46 }47 sqlite3DbFree(db, pList);48 p->x.pList = NULL;49 }50 sqlite3DbFree(db, p);51}52 53/* Helper: build an ExprList with n arguments.54 If n>=1 the first two args are TK_NULL (unused by target function).55 If n==3 and escapeZ!=NULL, the third arg is TK_STRING with escapeZ;56 otherwise the third arg is TK_NULL. */57static ExprList *makeArgList(sqlite3 *db, int n, const char *escapeZ){58 if( n<=0 ){59 return NULL;60 }61 int sz = sizeof(ExprList) + (n-1) * (int)sizeof(((ExprList*)0)->a[0]);62 ExprList *pList = (ExprList*)dbMalloc(db, sz);63 memset(pList, 0, sz);64 pList->nExpr = n;65 pList->nAlloc = n;66 for(int i=0; i<n; i++){67 if( i==2 && escapeZ!=NULL ){68 pList->a[i].pExpr = makeStringExpr(db, escapeZ);69 }else{70 pList->a[i].pExpr = makeNullExpr(db);71 }72 }73 return pList;74}75 76/* Helper: construct a TK_FUNCTION Expr for a given function name with nArg args and optional escape */77static Expr *makeFuncExpr(sqlite3 *db, const char *zFunc, int nArg, const char *escapeZ){78 Expr *p = makeExprOpToken(db, TK_FUNCTION, zFunc);79 /* Ensure ExprUseXList(p) condition: op==TK_FUNCTION suffices */80 p->x.pList = makeArgList(db, nArg, escapeZ);81 return p;82}83 84void setUp(void) {85 int rc = sqlite3_open(":memory:", &gDb);86 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);87 TEST_ASSERT_NOT_NULL(gDb);88}89 90void tearDown(void) {91 if( gDb ){92 sqlite3_close(gDb);93 gDb = NULL;94 }95}96 97/* Test: LIKE with 2 arguments (no ESCAPE) */98void test_sqlite3IsLikeFunction_like_two_args_basic(void){99 Expr *p = makeFuncExpr(gDb, "like", 2, NULL);100 int isNoCase = -1;101 char aWc[4] = {0,0,0,0};102 103 int rc = sqlite3IsLikeFunction(gDb, p, &isNoCase, aWc);104 TEST_ASSERT_EQUAL_INT(1, rc);105 /* Expected wildcards for LIKE are '%' and '_' and no set */106 TEST_ASSERT_EQUAL_CHAR('%', aWc[0]);107 TEST_ASSERT_EQUAL_CHAR('_', aWc[1]);108 TEST_ASSERT_EQUAL_CHAR(0, aWc[2]);109 TEST_ASSERT_EQUAL_CHAR(0, aWc[3]);110 /* LIKE is case-insensitive by default */111 TEST_ASSERT_TRUE(isNoCase!=0);112 113 freeExpr(gDb, p);114}115 116/* Test: LIKE with 3 arguments and valid ESCAPE '\' */117void test_sqlite3IsLikeFunction_like_three_args_with_valid_escape(void){118 Expr *p = makeFuncExpr(gDb, "like", 3, "\\");119 int isNoCase = -1;120 char aWc[4] = {0,0,0,0};121 122 int rc = sqlite3IsLikeFunction(gDb, p, &isNoCase, aWc);123 TEST_ASSERT_EQUAL_INT(1, rc);124 TEST_ASSERT_EQUAL_CHAR('%', aWc[0]);125 TEST_ASSERT_EQUAL_CHAR('_', aWc[1]);126 TEST_ASSERT_EQUAL_CHAR(0, aWc[2]);127 TEST_ASSERT_EQUAL_CHAR('\\', aWc[3]);128 TEST_ASSERT_TRUE(isNoCase!=0);129 130 freeExpr(gDb, p);131}132 133/* Test: LIKE with 3 args but ESCAPE equals matchAll ('%') or matchOne ('_') -> should fail */134void test_sqlite3IsLikeFunction_like_three_args_invalid_escape_same_as_wildcards(void){135 /* Escape as '%' */136 Expr *p1 = makeFuncExpr(gDb, "like", 3, "%");137 int isNoCase = -1;138 char aWc[4] = {0,0,0,0};139 int rc = sqlite3IsLikeFunction(gDb, p1, &isNoCase, aWc);140 TEST_ASSERT_EQUAL_INT(0, rc);141 freeExpr(gDb, p1);142 143 /* Escape as '_' */144 Expr *p2 = makeFuncExpr(gDb, "like", 3, "_");145 memset(aWc, 0, sizeof(aWc));146 rc = sqlite3IsLikeFunction(gDb, p2, &isNoCase, aWc);147 TEST_ASSERT_EQUAL_INT(0, rc);148 freeExpr(gDb, p2);149}150 151/* Test: LIKE with invalid ESCAPE: multi-character, empty string, or non-string token */152void test_sqlite3IsLikeFunction_like_three_args_invalid_escape_length_or_type(void){153 /* Multi-character escape "ab" */154 Expr *p1 = makeFuncExpr(gDb, "like", 3, "ab");155 int isNoCase = -1;156 char aWc[4] = {0,0,0,0};157 int rc = sqlite3IsLikeFunction(gDb, p1, &isNoCase, aWc);158 TEST_ASSERT_EQUAL_INT(0, rc);159 freeExpr(gDb, p1);160 161 /* Empty-string escape "" */162 Expr *p2 = makeFuncExpr(gDb, "like", 3, "");163 memset(aWc, 0, sizeof(aWc));164 rc = sqlite3IsLikeFunction(gDb, p2, &isNoCase, aWc);165 TEST_ASSERT_EQUAL_INT(0, rc);166 freeExpr(gDb, p2);167 168 /* Non-string token in 3rd arg: build list manually with TK_NULL as 3rd */169 Expr *p3 = makeFuncExpr(gDb, "like", 3, NULL); /* third defaults to TK_NULL in our helper */170 memset(aWc, 0, sizeof(aWc));171 rc = sqlite3IsLikeFunction(gDb, p3, &isNoCase, aWc);172 TEST_ASSERT_EQUAL_INT(0, rc);173 freeExpr(gDb, p3);174}175 176/* Test: x.pList is NULL -> should return 0 */177void test_sqlite3IsLikeFunction_null_arglist_returns_false(void){178 Expr *p = makeExprOpToken(gDb, TK_FUNCTION, "like");179 /* Intentionally leave x.pList NULL */180 int isNoCase = -1;181 char aWc[4] = {0,0,0,0};182 183 int rc = sqlite3IsLikeFunction(gDb, p, &isNoCase, aWc);184 TEST_ASSERT_EQUAL_INT(0, rc);185 186 freeExpr(gDb, p);187}188 189/* Test: Non-LIKE-style function (substr) -> should return 0 */190void test_sqlite3IsLikeFunction_non_like_function_returns_false(void){191 Expr *p = makeFuncExpr(gDb, "substr", 2, NULL);192 int isNoCase = -1;193 char aWc[4] = {0,0,0,0};194 195 int rc = sqlite3IsLikeFunction(gDb, p, &isNoCase, aWc);196 TEST_ASSERT_EQUAL_INT(0, rc);197 198 freeExpr(gDb, p);199}200 201/* Test: GLOB with 2 arguments -> should return 1, case-sensitive, and expected wildcards */202void test_sqlite3IsLikeFunction_glob_two_args_casesensitive(void){203 Expr *p = makeFuncExpr(gDb, "glob", 2, NULL);204 int isNoCase = -1;205 char aWc[4] = {0,0,0,0};206 207 int rc = sqlite3IsLikeFunction(gDb, p, &isNoCase, aWc);208 TEST_ASSERT_EQUAL_INT(1, rc);209 /* Expected glob wildcards: '*', '?', '[' */210 TEST_ASSERT_EQUAL_CHAR('*', aWc[0]);211 TEST_ASSERT_EQUAL_CHAR('?', aWc[1]);212 TEST_ASSERT_EQUAL_CHAR('[', aWc[2]);213 TEST_ASSERT_EQUAL_CHAR(0, aWc[3]);214 /* GLOB is case-sensitive */215 TEST_ASSERT_FALSE(isNoCase!=0);216 217 freeExpr(gDb, p);218}219 220int main(void) {221 UNITY_BEGIN();222 RUN_TEST(test_sqlite3IsLikeFunction_like_two_args_basic);223 RUN_TEST(test_sqlite3IsLikeFunction_like_three_args_with_valid_escape);224 RUN_TEST(test_sqlite3IsLikeFunction_like_three_args_invalid_escape_same_as_wildcards);225 RUN_TEST(test_sqlite3IsLikeFunction_like_three_args_invalid_escape_length_or_type);226 RUN_TEST(test_sqlite3IsLikeFunction_null_arglist_returns_false);227 RUN_TEST(test_sqlite3IsLikeFunction_non_like_function_returns_false);228 RUN_TEST(test_sqlite3IsLikeFunction_glob_two_args_casesensitive);229 return UNITY_END();230}