AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helper: create a Parse with an associated Vdbe */7static void initParse(sqlite3 **ppDb, Parse *pParse, int okConstFactor){8 int rc = sqlite3_open(":memory:", ppDb);9 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");10 memset(pParse, 0, sizeof(*pParse));11 pParse->db = *ppDb;12 pParse->pVdbe = sqlite3VdbeCreate(*ppDb);13 TEST_ASSERT_NOT_NULL_MESSAGE(pParse->pVdbe, "sqlite3VdbeCreate returned NULL");14 pParse->okConstFactor = (u8)okConstFactor;15}16 17/* Helper: cleanup Parse and db */18static void cleanupParse(sqlite3 *db, Parse *pParse){19 if( pParse->pConstExpr ){20 sqlite3ExprListDelete(db, pParse->pConstExpr);21 pParse->pConstExpr = 0;22 }23 if( pParse->pVdbe ){24 sqlite3VdbeDelete(pParse->pVdbe);25 pParse->pVdbe = 0;26 }27 if( db ){28 sqlite3_close(db);29 }30}31 32/* Helper: build a TK_INTEGER Expr using sqlite3ExprAlloc */33static Expr* makeIntExpr(sqlite3 *db, const char *zNum){34 Token t;35 memset(&t, 0, sizeof(t));36 t.z = zNum;37 t.n = (int)strlen(zNum);38 return sqlite3ExprAlloc(db, TK_INTEGER, &t, 0);39}40 41void setUp(void) {42 /* No global setup required */43}44 45void tearDown(void) {46 /* No global teardown required */47}48 49/* Test 1: Constant factoring enabled, constant integer expression.50 Expect: *pReg==0 and result register is reused across calls. */51void test_sqlite3ExprCodeTemp_constant_factoring_reuse(void){52 sqlite3 *db = 0;53 Parse parse;54 initParse(&db, &parse, 1);55 56 Expr *pExpr = makeIntExpr(db, "42");57 TEST_ASSERT_NOT_NULL(pExpr);58 59 int regOut1 = -999;60 int r1 = sqlite3ExprCodeTemp(&parse, pExpr, ®Out1);61 TEST_ASSERT_GREATER_THAN_INT(0, 0); /* keep Unity happy about type promotion */62 TEST_ASSERT_TRUE_MESSAGE(r1 > 0, "Returned register should be > 0");63 TEST_ASSERT_EQUAL_INT_MESSAGE(0, regOut1, "*pReg should be 0 for factored constants");64 65 /* Second call with the same expression should reuse the same register */66 int regOut2 = -999;67 int r2 = sqlite3ExprCodeTemp(&parse, pExpr, ®Out2);68 TEST_ASSERT_EQUAL_INT_MESSAGE(0, regOut2, "*pReg should be 0 for factored constants (2nd call)");69 TEST_ASSERT_EQUAL_INT_MESSAGE(r1, r2, "Constant factoring should reuse the same register");70 71 sqlite3ExprDelete(db, pExpr);72 cleanupParse(db, &parse);73}74 75/* Test 2: Constant factoring disabled, constant integer expression.76 Expect: temp register allocated and returned, *pReg equals the returned reg. */77void test_sqlite3ExprCodeTemp_no_const_factor_temp_reg_returned(void){78 sqlite3 *db = 0;79 Parse parse;80 initParse(&db, &parse, 0); /* okConstFactor = 0 */81 82 Expr *pExpr = makeIntExpr(db, "7");83 TEST_ASSERT_NOT_NULL(pExpr);84 85 int tempReg = 0;86 int r = sqlite3ExprCodeTemp(&parse, pExpr, &tempReg);87 TEST_ASSERT_TRUE_MESSAGE(r > 0, "Returned register should be > 0");88 TEST_ASSERT_EQUAL_INT_MESSAGE(r, tempReg, "When not factored, *pReg should be the temp register used");89 TEST_ASSERT_NULL_MESSAGE(parse.pConstExpr, "pConstExpr list should remain NULL when factoring is disabled");90 91 sqlite3ExprDelete(db, pExpr);92 cleanupParse(db, &parse);93}94 95/* Test 3: NULL expression pointer. Expect: handled as TK_NULL, temp reg used and returned; *pReg equals returned reg. */96void test_sqlite3ExprCodeTemp_null_expr(void){97 sqlite3 *db = 0;98 Parse parse;99 initParse(&db, &parse, 1); /* factoring setting shouldn't matter for NULL */100 101 int tempReg = 0;102 int r = sqlite3ExprCodeTemp(&parse, NULL, &tempReg);103 TEST_ASSERT_TRUE_MESSAGE(r > 0, "Returned register should be > 0 for NULL expr");104 TEST_ASSERT_EQUAL_INT_MESSAGE(r, tempReg, "*pReg should equal the temp register for NULL expr");105 106 cleanupParse(db, &parse);107}108 109/* Test 4: TK_REGISTER expression returns a different register than the temp target.110 Expect: sqlite3ExprCodeTemp releases the temp and sets *pReg==0. */111void test_sqlite3ExprCodeTemp_register_expr_returns_non_target_register(void){112 sqlite3 *db = 0;113 Parse parse;114 initParse(&db, &parse, 1);115 116 Expr e;117 memset(&e, 0, sizeof(e));118 e.op = TK_REGISTER;119 e.iTable = 123; /* Force a register different from the temp one */120 121 int outReg = -1;122 int r = sqlite3ExprCodeTemp(&parse, &e, &outReg);123 TEST_ASSERT_EQUAL_INT_MESSAGE(123, r, "Expected sqlite3ExprCodeTarget to return Expr.iTable for TK_REGISTER");124 TEST_ASSERT_EQUAL_INT_MESSAGE(0, outReg, "*pReg should be 0 when result is not stored in the temp target");125 126 cleanupParse(db, &parse);127}128 129int main(void){130 UNITY_BEGIN();131 RUN_TEST(test_sqlite3ExprCodeTemp_constant_factoring_reuse);132 RUN_TEST(test_sqlite3ExprCodeTemp_no_const_factor_temp_reg_returned);133 RUN_TEST(test_sqlite3ExprCodeTemp_null_expr);134 RUN_TEST(test_sqlite3ExprCodeTemp_register_expr_returns_non_target_register);135 return UNITY_END();136}