AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* External wrapper provided for testing the static function */7extern int test_resolveAttachExpr(NameContext *pName, Expr *pExpr);8 9static Token tokenFromString(const char *z){10 Token t;11 t.z = (char*)z;12 t.n = (int)strlen(z);13 return t;14}15 16static Expr* makeIdExpr(sqlite3 *db, const char *zId){17 Token t = tokenFromString(zId);18 return sqlite3ExprAlloc(db, TK_ID, &t, 0);19}20 21void setUp(void) {22 /* No-op */23}24 25void tearDown(void) {26 /* No-op */27}28 29/* pExpr==NULL returns SQLITE_OK */30void test_resolveAttachExpr_NullExpr_ReturnsOK(void){31 int rc;32 /* NameContext is unused when pExpr==NULL; can be NULL safely */33 rc = test_resolveAttachExpr(NULL, NULL);34 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);35}36 37/* Root TK_ID is converted to TK_STRING and returns SQLITE_OK */38void test_resolveAttachExpr_IdBecomesString_RootOnly(void){39 sqlite3 *db = 0;40 Parse parse;41 NameContext nc;42 Expr *pId = 0;43 int rc;44 45 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));46 memset(&parse, 0, sizeof(parse));47 parse.db = db;48 memset(&nc, 0, sizeof(nc));49 nc.pParse = &parse;50 51 pId = makeIdExpr(db, "abc");52 TEST_ASSERT_NOT_NULL(pId);53 TEST_ASSERT_EQUAL_INT(TK_ID, pId->op);54 55 rc = test_resolveAttachExpr(&nc, pId);56 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);57 TEST_ASSERT_EQUAL_INT(TK_STRING, pId->op);58 TEST_ASSERT_NOT_NULL(pId->u.zToken);59 TEST_ASSERT_EQUAL_STRING("abc", pId->u.zToken);60 61 /* Second call on same (now TK_STRING) expr should pass through resolver OK */62 rc = test_resolveAttachExpr(&nc, pId);63 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64 TEST_ASSERT_EQUAL_INT(TK_STRING, pId->op);65 66 sqlite3ExprDelete(db, pId);67 sqlite3_close(db);68}69 70/* Non-ID simple expression delegates to resolver and returns SQLITE_OK */71void test_resolveAttachExpr_NonIdSimpleExpr_ReturnsOK(void){72 sqlite3 *db = 0;73 Parse parse;74 NameContext nc;75 Expr *pNull = 0;76 int rc;77 78 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));79 memset(&parse, 0, sizeof(parse));80 parse.db = db;81 memset(&nc, 0, sizeof(nc));82 nc.pParse = &parse;83 84 /* Build a simple non-ID expression: TK_NULL */85 pNull = sqlite3ExprAlloc(db, TK_NULL, NULL, 0);86 TEST_ASSERT_NOT_NULL(pNull);87 TEST_ASSERT_EQUAL_INT(TK_NULL, pNull->op);88 89 rc = test_resolveAttachExpr(&nc, pNull);90 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);91 TEST_ASSERT_EQUAL_INT(TK_NULL, pNull->op);92 93 sqlite3ExprDelete(db, pNull);94 sqlite3_close(db);95}96 97/* Complex expression with IDs at non-root should fail to resolve (non-OK) */98void test_resolveAttachExpr_ComplexExprWithIds_FailsResolution(void){99 sqlite3 *db = 0;100 Parse parse;101 NameContext nc;102 Expr *pLeft = 0;103 Expr *pRight = 0;104 Expr *pConcat = 0;105 int rc;106 107 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));108 memset(&parse, 0, sizeof(parse));109 parse.db = db;110 memset(&nc, 0, sizeof(nc));111 nc.pParse = &parse;112 113 pLeft = makeIdExpr(db, "abc");114 pRight = makeIdExpr(db, "def");115 TEST_ASSERT_NOT_NULL(pLeft);116 TEST_ASSERT_NOT_NULL(pRight);117 118 /* Build abc || def (root op != TK_ID) */119 pConcat = sqlite3PExpr(&parse, TK_CONCAT, pLeft, pRight);120 TEST_ASSERT_NOT_NULL(pConcat);121 TEST_ASSERT_EQUAL_INT(TK_CONCAT, pConcat->op);122 123 rc = test_resolveAttachExpr(&nc, pConcat);124 125 /* Expect name resolution failure due to unresolved identifiers abc/def */126 TEST_ASSERT_NOT_EQUAL_INT(SQLITE_OK, rc);127 128 /* Ensure the child IDs were not converted to strings by resolveAttachExpr */129 TEST_ASSERT_EQUAL_INT(TK_ID, pConcat->pLeft->op);130 TEST_ASSERT_EQUAL_INT(TK_ID, pConcat->pRight->op);131 132 sqlite3ExprDelete(db, pConcat); /* This also frees pLeft/pRight */133 sqlite3_close(db);134}135 136int main(void) {137 UNITY_BEGIN();138 RUN_TEST(test_resolveAttachExpr_NullExpr_ReturnsOK);139 RUN_TEST(test_resolveAttachExpr_IdBecomesString_RootOnly);140 RUN_TEST(test_resolveAttachExpr_NonIdSimpleExpr_ReturnsOK);141 RUN_TEST(test_resolveAttachExpr_ComplexExprWithIds_FailsResolution);142 return UNITY_END();143}