AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Global database handle for tests */7static sqlite3 *gDb = NULL;8 9static void disable_db_lookaside(sqlite3 *db){10 /* Disable per-connection lookaside to ensure sqlite3DbMalloc uses heap */11#if defined(SQLITE_ENABLE_API_ARMOR) || 112 /* Use db config API if available */13 (void)sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, 0, 0);14#endif15}16 17/* Unity setup/teardown */18void setUp(void) {19 int rc = sqlite3_open(":memory:", &gDb);20 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);21 TEST_ASSERT_NOT_NULL(gDb);22 disable_db_lookaside(gDb);23}24 25void tearDown(void) {26 if( gDb ){27 sqlite3_close(gDb);28 gDb = NULL;29 }30}31 32/* Helper to allocate an Index with zeroed memory via db allocator */33static Index* alloc_index(sqlite3 *db){34 Index *p = (Index*)sqlite3DbMallocZero(db, sizeof(Index));35 TEST_ASSERT_NOT_NULL(p);36 return p;37}38 39/* Test 1: Free an Index with no sub-allocations */40void test_sqlite3FreeIndex_basic_free_only_struct(void) {41 sqlite3_int64 before = sqlite3_memory_used();42 43 Index *p = alloc_index(gDb);44 /* Leave all subfields NULL/zero */45 sqlite3FreeIndex(gDb, p);46 47 sqlite3_int64 after = sqlite3_memory_used();48 TEST_ASSERT_LESS_OR_EQUAL_INT64(before, after);49}50 51/* Test 2: Free Index with zColAff and azColl allocated; isResized=1 so azColl must be freed */52void test_sqlite3FreeIndex_frees_allocated_fields_when_resized(void) {53 sqlite3_int64 before = sqlite3_memory_used();54 55 Index *p = alloc_index(gDb);56 57 /* Allocate some column affinity string */58 p->zColAff = (char*)sqlite3DbMallocRaw(gDb, 32);59 TEST_ASSERT_NOT_NULL(p->zColAff);60 memset(p->zColAff, 'A', 31);61 p->zColAff[31] = '\0';62 63 /* Allocate azColl array and mark as resized so it should be freed */64 p->azColl = (const char**)sqlite3DbMallocZero(gDb, 4 * sizeof(char*));65 TEST_ASSERT_NOT_NULL(p->azColl);66 p->isResized = 1;67 68 sqlite3FreeIndex(gDb, p);69 70 sqlite3_int64 after = sqlite3_memory_used();71 TEST_ASSERT_LESS_OR_EQUAL_INT64(before, after);72}73 74/* Test 3: Ensure azColl is NOT freed when isResized==0, and manually free afterwards */75void test_sqlite3FreeIndex_does_not_free_azColl_when_not_resized(void) {76 sqlite3_int64 before = sqlite3_memory_used();77 78 Index *p = alloc_index(gDb);79 80 /* Allocate azColl and leave isResized = 0 (default). Function should NOT free it. */81 p->azColl = (const char**)sqlite3DbMallocZero(gDb, 3 * sizeof(char*));82 TEST_ASSERT_NOT_NULL(p->azColl);83 84 /* Also allocate zColAff so function has something to free */85 p->zColAff = (char*)sqlite3DbMallocRaw(gDb, 16);86 TEST_ASSERT_NOT_NULL(p->zColAff);87 88 sqlite3FreeIndex(gDb, p);89 90 /* If sqlite3FreeIndex incorrectly freed azColl, the next free would likely crash. */91 sqlite3DbFree(gDb, (void*)p->azColl);92 93 sqlite3_int64 after = sqlite3_memory_used();94 TEST_ASSERT_LESS_OR_EQUAL_INT64(before, after);95}96 97/* Test 4: Provide minimal Expr and ExprList to exercise sqlite3ExprDelete and sqlite3ExprListDelete paths */98void test_sqlite3FreeIndex_handles_minimal_expr_and_exprlist(void) {99 sqlite3_int64 before = sqlite3_memory_used();100 101 Index *p = alloc_index(gDb);102 103 /* Minimal zero-initialized Expr and ExprList should be safely deletable. */104 p->pPartIdxWhere = (Expr*)sqlite3DbMallocZero(gDb, sizeof(Expr));105 TEST_ASSERT_NOT_NULL(p->pPartIdxWhere);106 107 p->aColExpr = (ExprList*)sqlite3DbMallocZero(gDb, sizeof(ExprList));108 TEST_ASSERT_NOT_NULL(p->aColExpr);109 110 sqlite3FreeIndex(gDb, p);111 112 sqlite3_int64 after = sqlite3_memory_used();113 TEST_ASSERT_LESS_OR_EQUAL_INT64(before, after);114}115 116/* Test 5: Under SQLITE_ENABLE_STAT4, ensure aiRowEst allocated using sqlite3_malloc is freed */117void test_sqlite3FreeIndex_frees_aiRowEst_when_STAT4_enabled(void) {118#ifdef SQLITE_ENABLE_STAT4119 sqlite3_int64 before = sqlite3_memory_used();120 121 Index *p = alloc_index(gDb);122 123 /* Allocate a few tRowcnt entries using the global allocator, as sqlite3FreeIndex uses sqlite3_free */124 size_t n = 5;125 p->aiRowEst = (tRowcnt*)sqlite3_malloc64(n * sizeof(tRowcnt));126 TEST_ASSERT_NOT_NULL(p->aiRowEst);127 128 sqlite3FreeIndex(gDb, p);129 130 sqlite3_int64 after = sqlite3_memory_used();131 TEST_ASSERT_LESS_OR_EQUAL_INT64(before, after);132#else133 TEST_IGNORE_MESSAGE("SQLITE_ENABLE_STAT4 not enabled; skipping aiRowEst free test.");134#endif135}136 137int main(void) {138 /* Ensure predictable memory accounting and disable default lookaside */139 sqlite3_shutdown();140 sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 1);141 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);142 sqlite3_initialize();143 144 UNITY_BEGIN();145 RUN_TEST(test_sqlite3FreeIndex_basic_free_only_struct);146 RUN_TEST(test_sqlite3FreeIndex_frees_allocated_fields_when_resized);147 RUN_TEST(test_sqlite3FreeIndex_does_not_free_azColl_when_not_resized);148 RUN_TEST(test_sqlite3FreeIndex_handles_minimal_expr_and_exprlist);149 RUN_TEST(test_sqlite3FreeIndex_frees_aiRowEst_when_STAT4_enabled);150 return UNITY_END();151}