AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include "sqlite3.h"4#include "parse.h"5#include <string.h>6#include <stdlib.h>7 8/* Unity setup/teardown */9void setUp(void) {10 /* No-op */11}12void tearDown(void) {13 /* No-op */14}15 16/* Helper: allocate a zeroed Expr with given op, flags and nHeight */17static Expr* allocExpr(sqlite3 *db, int op, unsigned flags, int nHeight){18 Expr *p = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));19 TEST_ASSERT_NOT_NULL(p);20 p->op = (u8)op;21 p->flags = flags;22#if SQLITE_MAX_EXPR_DEPTH>023 p->nHeight = (u8)nHeight;24#else25 (void)nHeight;26#endif27 return p;28}29 30/* Test: attach both left and right, verify pointers, flag propagation, height */31void test_sqlite3ExprAttachSubtrees_attach_both(void){32 sqlite3 *db = 0;33 int rc = sqlite3_open(":memory:", &db);34 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);35 TEST_ASSERT_NOT_NULL(db);36 37 /* Create root with op that uses x.pList to satisfy internal assert */38 Expr *pRoot = allocExpr(db, TK_FUNCTION, 0, 0);39 Expr *pLeft = allocExpr(db, TK_INTEGER, 0, 4);40 Expr *pRight = allocExpr(db, TK_ID, 0, 2);41 42 /* Set flags on children to include EP_Propagate bits */43 pLeft->flags = EP_Propagate; /* all EP_Propagate bits set */44 pRight->flags = 0; /* no EP_Propagate bits */45 46 sqlite3ExprAttachSubtrees(db, pRoot, pLeft, pRight);47 48 /* Pointers must be attached */49 TEST_ASSERT_EQUAL_PTR(pLeft, pRoot->pLeft);50 TEST_ASSERT_EQUAL_PTR(pRight, pRoot->pRight);51 52 /* EP_Propagate bits must be ORed from both children into root */53 TEST_ASSERT_EQUAL_UINT((pLeft->flags | pRight->flags) & EP_Propagate,54 pRoot->flags & EP_Propagate);55 56#if SQLITE_MAX_EXPR_DEPTH>057 /* Height should be max(child.nHeight) + 1. Right initially sets it, left may raise it */58 TEST_ASSERT_EQUAL_UINT((unsigned)(pLeft->nHeight + 1), (unsigned)pRoot->nHeight);59#endif60 61 /* Free the whole tree starting from root */62 sqlite3ExprDelete(db, pRoot);63 64 sqlite3_close(db);65}66 67/* Test: attach only right subtree */68void test_sqlite3ExprAttachSubtrees_attach_only_right(void){69 sqlite3 *db = 0;70 int rc = sqlite3_open(":memory:", &db);71 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);72 TEST_ASSERT_NOT_NULL(db);73 74 Expr *pRoot = allocExpr(db, TK_FUNCTION, 0, 0);75 Expr *pRight = allocExpr(db, TK_ID, 0, 7);76 77 /* Give right an EP_Propagate subset; here we take them all to make check simple */78 pRight->flags = EP_Propagate;79 80 sqlite3ExprAttachSubtrees(db, pRoot, NULL, pRight);81 82 TEST_ASSERT_NULL(pRoot->pLeft);83 TEST_ASSERT_EQUAL_PTR(pRight, pRoot->pRight);84 85 TEST_ASSERT_EQUAL_UINT(pRight->flags & EP_Propagate,86 pRoot->flags & EP_Propagate);87 88#if SQLITE_MAX_EXPR_DEPTH>089 TEST_ASSERT_EQUAL_UINT((unsigned)(pRight->nHeight + 1), (unsigned)pRoot->nHeight);90#endif91 92 sqlite3ExprDelete(db, pRoot);93 sqlite3_close(db);94}95 96/* Test: attach only left subtree */97void test_sqlite3ExprAttachSubtrees_attach_only_left(void){98 sqlite3 *db = 0;99 int rc = sqlite3_open(":memory:", &db);100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101 TEST_ASSERT_NOT_NULL(db);102 103 Expr *pRoot = allocExpr(db, TK_FUNCTION, 0, 0);104 Expr *pLeft = allocExpr(db, TK_INTEGER, 0, 3);105 106 /* Put a specific EP_Propagate pattern: half of the bits (simply EP_Propagate again) */107 pLeft->flags = EP_Propagate;108 109 sqlite3ExprAttachSubtrees(db, pRoot, pLeft, NULL);110 111 TEST_ASSERT_EQUAL_PTR(pLeft, pRoot->pLeft);112 TEST_ASSERT_NULL(pRoot->pRight);113 114 TEST_ASSERT_EQUAL_UINT(pLeft->flags & EP_Propagate,115 pRoot->flags & EP_Propagate);116 117#if SQLITE_MAX_EXPR_DEPTH>0118 /* With no right, initial nHeight is set to 1, then possibly raised by left */119 TEST_ASSERT_EQUAL_UINT((unsigned)(pLeft->nHeight + 1), (unsigned)pRoot->nHeight);120#endif121 122 sqlite3ExprDelete(db, pRoot);123 sqlite3_close(db);124}125 126/* Test: attach only left subtree with left->nHeight == 0 to ensure base case works */127void test_sqlite3ExprAttachSubtrees_attach_left_height_zero(void){128 sqlite3 *db = 0;129 int rc = sqlite3_open(":memory:", &db);130 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);131 TEST_ASSERT_NOT_NULL(db);132 133 Expr *pRoot = allocExpr(db, TK_FUNCTION, 0, 0);134 Expr *pLeft = allocExpr(db, TK_INTEGER, 0, 0);135 136 sqlite3ExprAttachSubtrees(db, pRoot, pLeft, NULL);137 138 TEST_ASSERT_EQUAL_PTR(pLeft, pRoot->pLeft);139 TEST_ASSERT_NULL(pRoot->pRight);140 141#if SQLITE_MAX_EXPR_DEPTH>0142 /* If left->nHeight is 0, root should remain at least 1 (since base is 1) */143 TEST_ASSERT_EQUAL_UINT(1u, (unsigned)pRoot->nHeight);144#endif145 146 sqlite3ExprDelete(db, pRoot);147 sqlite3_close(db);148}149 150/* Test: pRoot == NULL should delete subtrees and not crash; requires db->mallocFailed set */151void test_sqlite3ExprAttachSubtrees_null_root_deletes_children(void){152 sqlite3 *db = 0;153 int rc = sqlite3_open(":memory:", &db);154 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);155 TEST_ASSERT_NOT_NULL(db);156 157 /* Create some non-trivial children */158 Expr *pLeft = allocExpr(db, TK_INTEGER, 0, 1);159 Expr *pRight = allocExpr(db, TK_ID, 0, 1);160 /* Give left a nested child to exercise delete recursion */161 pLeft->pLeft = allocExpr(db, TK_INTEGER, 0, 1);162 163 /* The function asserts that db->mallocFailed is set when pRoot==NULL */164 db->mallocFailed = 1;165 166 /* Should not crash. Children are expected to be deleted internally. */167 sqlite3ExprAttachSubtrees(db, NULL, pLeft, pRight);168 169 /* Nothing more to free here: ownership was transferred and released. */170 sqlite3_close(db);171}172 173int main(void){174 UNITY_BEGIN();175 RUN_TEST(test_sqlite3ExprAttachSubtrees_attach_both);176 RUN_TEST(test_sqlite3ExprAttachSubtrees_attach_only_right);177 RUN_TEST(test_sqlite3ExprAttachSubtrees_attach_only_left);178 RUN_TEST(test_sqlite3ExprAttachSubtrees_attach_left_height_zero);179 RUN_TEST(test_sqlite3ExprAttachSubtrees_null_root_deletes_children);180 return UNITY_END();181}