AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* Wrapper provided for static function under test */8extern void test_markExprListImmutable(ExprList *pList);9 10/* Helpers to build minimal Expr/ExprList trees for testing */11 12static Expr *newLeaf(sqlite3 *db, int op){13 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));14 TEST_ASSERT_NOT_NULL(e);15 e->op = (u8)op;16 return e;17}18 19static Expr *newLeafWithFlags(sqlite3 *db, int op, u32 flags){20 Expr *e = newLeaf(db, op);21 e->flags |= flags;22 return e;23}24 25static Expr *newBinary(sqlite3 *db, int op, Expr *lhs, Expr *rhs){26 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));27 TEST_ASSERT_NOT_NULL(e);28 e->op = (u8)op;29 e->pLeft = lhs;30 e->pRight = rhs;31 return e;32}33 34static ExprList *newExprListFromArray(sqlite3 *db, Expr **arr, int n){35 ExprList *pList = (ExprList*)sqlite3DbMallocZero(db, sizeof(ExprList));36 TEST_ASSERT_NOT_NULL(pList);37 if( n>0 ){38 pList->a = (struct ExprList_item*)sqlite3DbMallocZero(db, sizeof(struct ExprList_item)*n);39 TEST_ASSERT_NOT_NULL(pList->a);40 }else{41 pList->a = 0;42 }43 pList->nExpr = n;44 pList->nAlloc = n;45 for(int i=0; i<n; i++){46 pList->a[i].pExpr = arr[i];47 }48 return pList;49}50 51static Expr *newFunctionWithArgs(sqlite3 *db, Expr **args, int nArg){52 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));53 TEST_ASSERT_NOT_NULL(e);54 e->op = TK_FUNCTION;55 e->x.pList = newExprListFromArray(db, args, nArg);56 return e;57}58 59/* Recursively verify EP_Immutable flag across an expression tree, including x.pList children */60static int exprAllImmutable(const Expr *e){61 if( e==0 ) return 1;62 if( (e->flags & EP_Immutable)==0 ) return 0;63 if( e->pLeft && !exprAllImmutable(e->pLeft) ) return 0;64 if( e->pRight && !exprAllImmutable(e->pRight) ) return 0;65 if( e->x.pList ){66 ExprList *pl = e->x.pList;67 for(int i=0; i<pl->nExpr; i++){68 if( pl->a[i].pExpr && !exprAllImmutable(pl->a[i].pExpr) ) return 0;69 }70 }71 return 1;72}73 74/* Verify EP_Immutable across an ExprList and its subtrees */75static int exprListAllImmutable(const ExprList *pList){76 if( pList==0 ) return 1;77 for(int i=0; i<pList->nExpr; i++){78 if( !exprAllImmutable(pList->a[i].pExpr) ) return 0;79 }80 return 1;81}82 83void setUp(void) {84 /* No global setup */85}86void tearDown(void) {87 /* No global teardown */88}89 90/* Test: NULL list should be handled safely (no crash). */91void test_markExprListImmutable_null_list_safe(void){92 test_markExprListImmutable(NULL);93 TEST_ASSERT_TRUE(1); /* If we reached here, no crash occurred */94}95 96/* Test: Empty ExprList (nExpr=0) should be handled safely. */97void test_markExprListImmutable_empty_list_safe(void){98 sqlite3 *db = 0;99 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));100 ExprList *pEmpty = newExprListFromArray(db, NULL, 0);101 test_markExprListImmutable(pEmpty);102 /* Nothing to verify other than no crash */103 sqlite3ExprListDelete(db, pEmpty);104 sqlite3_close(db);105 TEST_ASSERT_TRUE(1);106}107 108/* Test: Single leaf expression gets EP_Immutable, and existing flags are preserved. */109void test_markExprListImmutable_single_leaf_preserves_flags(void){110 sqlite3 *db = 0;111 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));112 113 Expr *leaf = newLeafWithFlags(db, TK_INTEGER, EP_IntValue);114 TEST_ASSERT_FALSE((leaf->flags & EP_Immutable)!=0);115 116 Expr *arr[1] = { leaf };117 ExprList *pList = newExprListFromArray(db, arr, 1);118 119 test_markExprListImmutable(pList);120 121 TEST_ASSERT_TRUE((leaf->flags & EP_Immutable)!=0);122 TEST_ASSERT_TRUE((leaf->flags & EP_IntValue)!=0); /* original flag preserved */123 124 sqlite3ExprListDelete(db, pList);125 sqlite3_close(db);126}127 128/* Test: Nested trees and function-argument lists are fully marked immutable. */129void test_markExprListImmutable_nested_and_function_args(void){130 sqlite3 *db = 0;131 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));132 133 /* e1 = (1 + 2) */134 Expr *e1 = newBinary(db, TK_PLUS, newLeaf(db, TK_INTEGER), newLeaf(db, TK_INTEGER));135 136 /* e2 = (3 * (4 + 5)) */137 Expr *e2 = newBinary(db, TK_STAR,138 newLeaf(db, TK_INTEGER),139 newBinary(db, TK_PLUS, newLeaf(db, TK_INTEGER), newLeaf(db, TK_INTEGER)));140 141 /* e3 = func(6, 7) */142 Expr *funcArgs[2] = { newLeaf(db, TK_INTEGER), newLeaf(db, TK_INTEGER) };143 Expr *e3 = newFunctionWithArgs(db, funcArgs, 2);144 145 Expr *top[3] = { e1, e2, e3 };146 ExprList *pList = newExprListFromArray(db, top, 3);147 148 /* Precondition: no EP_Immutable */149 TEST_ASSERT_FALSE((e1->flags & EP_Immutable)!=0);150 TEST_ASSERT_FALSE((e2->flags & EP_Immutable)!=0);151 TEST_ASSERT_FALSE((e3->flags & EP_Immutable)!=0);152 153 test_markExprListImmutable(pList);154 155 TEST_ASSERT_TRUE(exprListAllImmutable(pList));156 157 sqlite3ExprListDelete(db, pList);158 sqlite3_close(db);159}160 161/* Test: Idempotency — running twice does not further change flags after first application. */162void test_markExprListImmutable_idempotent(void){163 sqlite3 *db = 0;164 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));165 166 Expr *leaf = newLeaf(db, TK_INTEGER);167 Expr *arr[1] = { leaf };168 ExprList *pList = newExprListFromArray(db, arr, 1);169 170 test_markExprListImmutable(pList);171 u32 firstFlags = leaf->flags;172 173 test_markExprListImmutable(pList);174 u32 secondFlags = leaf->flags;175 176 TEST_ASSERT_EQUAL_UINT32(firstFlags, secondFlags);177 TEST_ASSERT_TRUE((leaf->flags & EP_Immutable)!=0);178 179 sqlite3ExprListDelete(db, pList);180 sqlite3_close(db);181}182 183int main(void){184 UNITY_BEGIN();185 RUN_TEST(test_markExprListImmutable_null_list_safe);186 RUN_TEST(test_markExprListImmutable_empty_list_safe);187 RUN_TEST(test_markExprListImmutable_single_leaf_preserves_flags);188 RUN_TEST(test_markExprListImmutable_nested_and_function_args);189 RUN_TEST(test_markExprListImmutable_idempotent);190 return UNITY_END();191}