AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Unity fixtures */7void setUp(void) {8 /* No global setup needed */9}10void tearDown(void) {11 /* No global teardown needed */12}13 14/* Helpers to manipulate and verify PARSE_TAIL */15static void fill_parse_tail(Parse *p, unsigned char v){16 memset(PARSE_TAIL(p), v, PARSE_TAIL_SZ);17}18static void snapshot_parse_tail(Parse *p, unsigned char *out){19 memcpy(out, PARSE_TAIL(p), PARSE_TAIL_SZ);20}21static void assert_parse_tail_equals(Parse *p, const unsigned char *snap){22 TEST_ASSERT_EQUAL_INT(0, memcmp(PARSE_TAIL(p), snap, PARSE_TAIL_SZ));23}24 25/* Helper to clean up any VDBE produced during parsing to allow sqlite3_close() */26static void cleanup_parse(Parse *p){27 if( p->pVdbe ){28 sqlite3VdbeDelete(p->pVdbe);29 p->pVdbe = 0;30 }31}32 33static void init_parse(Parse *p, sqlite3 *db){34 memset(p, 0, sizeof(*p));35 p->db = db;36 /* Ensure predictable starting conditions */37 p->nErr = 0;38 p->rc = SQLITE_OK;39 p->eParseMode = 0;40 p->nested = 0;41}42 43/* Test: Early return when pParse->nErr > 0, state should remain unchanged */44void test_sqlite3NestedParse_early_return_on_existing_error(void){45 sqlite3 *db = 0;46 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));47 48 Parse p;49 init_parse(&p, db);50 p.nErr = 1; /* Force early-return condition */51 p.nested = 2; /* Ensure nested is not incremented */52 u32 origFlags = db->mDbFlags;53 54 unsigned char snap[PARSE_TAIL_SZ];55 fill_parse_tail(&p, 0x5A);56 snapshot_parse_tail(&p, snap);57 58 sqlite3NestedParse(&p, "SELECT 1");59 60 /* State unchanged */61 TEST_ASSERT_EQUAL_INT(1, p.nErr);62 TEST_ASSERT_EQUAL_INT(2, p.nested);63 TEST_ASSERT_EQUAL_INT(origFlags, db->mDbFlags);64 assert_parse_tail_equals(&p, snap);65 66 cleanup_parse(&p);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));68}69 70/* Test: Early return when eParseMode != 0, state should remain unchanged */71void test_sqlite3NestedParse_early_return_on_eParseMode_nonzero(void){72 sqlite3 *db = 0;73 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));74 75 Parse p;76 init_parse(&p, db);77 p.eParseMode = 1; /* Force early-return condition */78 p.nested = 3;79 u32 origFlags = db->mDbFlags;80 81 unsigned char snap[PARSE_TAIL_SZ];82 fill_parse_tail(&p, 0xA5);83 snapshot_parse_tail(&p, snap);84 85 sqlite3NestedParse(&p, "SELECT 1");86 87 /* State unchanged */88 TEST_ASSERT_EQUAL_INT(0, p.nErr);89 TEST_ASSERT_EQUAL_INT(3, p.nested);90 TEST_ASSERT_EQUAL_INT(origFlags, db->mDbFlags);91 assert_parse_tail_equals(&p, snap);92 93 cleanup_parse(&p);94 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));95}96 97/* Test: Too-big SQL (exceeding SQLITE_LIMIT_LENGTH) sets rc=SQLITE_TOOBIG and increments nErr */98void test_sqlite3NestedParse_sets_TOOBIG_when_SQL_exceeds_limit(void){99 sqlite3 *db = 0;100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));101 102 /* Set a small length limit to trigger SQLITE_TOOBIG in sqlite3VMPrintf */103 int oldLim = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 50);104 105 Parse p;106 init_parse(&p, db);107 u32 origFlags = db->mDbFlags;108 109 unsigned char snap[PARSE_TAIL_SZ];110 fill_parse_tail(&p, 0xCC);111 snapshot_parse_tail(&p, snap);112 113 char longbuf[200];114 memset(longbuf, 'x', sizeof(longbuf)-1);115 longbuf[sizeof(longbuf)-1] = '\0';116 117 sqlite3NestedParse(&p, "%s", longbuf);118 119 /* Should report an error and not modify parser/db state beyond error fields */120 TEST_ASSERT_EQUAL_INT(1, p.nErr);121 TEST_ASSERT_EQUAL_INT(SQLITE_TOOBIG, p.rc);122 TEST_ASSERT_EQUAL_INT(0, p.nested); /* No nesting occurred */123 TEST_ASSERT_EQUAL_INT(origFlags, db->mDbFlags);124 assert_parse_tail_equals(&p, snap);125 126 /* Restore limit and cleanup */127 sqlite3_limit(db, SQLITE_LIMIT_LENGTH, oldLim);128 cleanup_parse(&p);129 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));130}131 132/* Test: Normal parse path restores flags, nested level, and PARSE_TAIL */133void test_sqlite3NestedParse_restores_state_after_successful_parse(void){134 sqlite3 *db = 0;135 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));136 137 Parse p;138 init_parse(&p, db);139 u32 origFlags = db->mDbFlags;140 141 unsigned char snap[PARSE_TAIL_SZ];142 fill_parse_tail(&p, 0xAA);143 snapshot_parse_tail(&p, snap);144 145 sqlite3NestedParse(&p, "SELECT 1");146 147 /* No new errors */148 TEST_ASSERT_EQUAL_INT(0, p.nErr);149 /* Nested level restored */150 TEST_ASSERT_EQUAL_INT(0, p.nested);151 /* Flags restored */152 TEST_ASSERT_EQUAL_INT(origFlags, db->mDbFlags);153 /* PARSE_TAIL restored */154 assert_parse_tail_equals(&p, snap);155 156 cleanup_parse(&p);157 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));158}159 160/* Test: Nested depth near limit (nested==9) still works and restores properly */161void test_sqlite3NestedParse_handles_maximum_supported_nesting_minus_one(void){162 sqlite3 *db = 0;163 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));164 165 Parse p;166 init_parse(&p, db);167 p.nested = 9; /* Allowed by the assert: nested < 10 */168 u32 origFlags = db->mDbFlags;169 170 unsigned char snap[PARSE_TAIL_SZ];171 fill_parse_tail(&p, 0x11);172 snapshot_parse_tail(&p, snap);173 174 sqlite3NestedParse(&p, "SELECT 1");175 176 TEST_ASSERT_EQUAL_INT(0, p.nErr);177 TEST_ASSERT_EQUAL_INT(9, p.nested);178 TEST_ASSERT_EQUAL_INT(origFlags, db->mDbFlags);179 assert_parse_tail_equals(&p, snap);180 181 cleanup_parse(&p);182 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));183}184 185int main(void){186 UNITY_BEGIN();187 RUN_TEST(test_sqlite3NestedParse_early_return_on_existing_error);188 RUN_TEST(test_sqlite3NestedParse_early_return_on_eParseMode_nonzero);189 RUN_TEST(test_sqlite3NestedParse_sets_TOOBIG_when_SQL_exceeds_limit);190 RUN_TEST(test_sqlite3NestedParse_restores_state_after_successful_parse);191 RUN_TEST(test_sqlite3NestedParse_handles_maximum_supported_nesting_minus_one);192 return UNITY_END();193}