AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5#include <stdlib.h>6 7/* Call the provided wrapper for the static function */8extern int test_addAggInfoFunc(sqlite3 *db, AggInfo *pInfo);9 10/* Helpers for memory failure injection */11static sqlite3_mem_methods g_origMem;12static int g_haveOrigMem = 0;13 14static void *failMalloc(int n){ (void)n; return NULL; }15static void failFree(void *p){ (void)p; }16static void *failRealloc(void *p, int n){ (void)p; (void)n; return NULL; }17static int failSize(void *p){ (void)p; return 0; }18static int failRoundup(int n){ return n; }19static int failInit(void *p){ (void)p; return SQLITE_OK; }20static void failShutdown(void *p){ (void)p; }21 22static int installFailingAllocator(void){23 int rc;24 rc = sqlite3_shutdown();25 if( rc!=SQLITE_OK && rc!=SQLITE_MISUSE ){26 return rc;27 }28 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g_origMem);29 if( rc!=SQLITE_OK ) return rc;30 g_haveOrigMem = 1;31 32 sqlite3_mem_methods fail = {33 failMalloc, failFree, failRealloc, failSize, failRoundup, failInit, failShutdown, 034 };35 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &fail);36 if( rc!=SQLITE_OK ) return rc;37 rc = sqlite3_initialize();38 return rc;39}40 41static int restoreAllocator(void){42 int rc;43 if( !g_haveOrigMem ) return SQLITE_OK;44 rc = sqlite3_shutdown();45 if( rc!=SQLITE_OK && rc!=SQLITE_MISUSE ){46 return rc;47 }48 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &g_origMem);49 if( rc!=SQLITE_OK ) return rc;50 rc = sqlite3_initialize();51 return rc;52}53 54static int is_zero_memory(const void *p, size_t n){55 const unsigned char *b = (const unsigned char*)p;56 for(size_t i=0;i<n;i++){57 if( b[i]!=0 ) return 0;58 }59 return 1;60}61 62void setUp(void) {63 /* Ensure SQLite is initialized in default state for tests that do not override it */64 sqlite3_initialize();65}66 67void tearDown(void) {68 /* Restore allocator if a test changed it */69 if( g_haveOrigMem ){70 restoreAllocator();71 g_haveOrigMem = 0;72 }73}74 75/* Test 1: First allocation with db==NULL (global allocator) */76void test_addAggInfoFunc_first_alloc_db_null(void){77 AggInfo info;78 memset(&info, 0, sizeof(info));79 80 int idx = test_addAggInfoFunc(NULL, &info);81 TEST_ASSERT_EQUAL_INT(0, idx);82 TEST_ASSERT_EQUAL_INT(1, info.nFunc);83 TEST_ASSERT_NOT_NULL(info.aFunc);84 85 /* New slot must be zero-initialized */86 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[0], sizeof(info.aFunc[0])));87 88 /* Cleanup */89 sqlite3_free(info.aFunc);90}91 92/* Test 2: Second allocation preserves first element and zero-initializes new */93void test_addAggInfoFunc_second_alloc_preserve_and_zero_new(void){94 AggInfo info;95 memset(&info, 0, sizeof(info));96 97 int idx0 = test_addAggInfoFunc(NULL, &info);98 TEST_ASSERT_EQUAL_INT(0, idx0);99 TEST_ASSERT_EQUAL_INT(1, info.nFunc);100 TEST_ASSERT_NOT_NULL(info.aFunc);101 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[0], sizeof(info.aFunc[0])));102 103 /* Set a known field in the first element to a non-zero value to ensure preservation.104 Use a commonly-present integer field iMem in AggInfo_func. */105 info.aFunc[0].iMem = 12345;106 107 int idx1 = test_addAggInfoFunc(NULL, &info);108 TEST_ASSERT_EQUAL_INT(1, idx1);109 TEST_ASSERT_EQUAL_INT(2, info.nFunc);110 TEST_ASSERT_NOT_NULL(info.aFunc);111 112 /* Ensure first element preserved */113 TEST_ASSERT_EQUAL_INT(12345, info.aFunc[0].iMem);114 115 /* Ensure the newly added slot is zero-initialized */116 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[1], sizeof(info.aFunc[1])));117 118 /* Cleanup */119 sqlite3_free(info.aFunc);120}121 122/* Test 3: Multiple appends yield consecutive indices and correct nFunc */123void test_addAggInfoFunc_multiple_appends_indexes(void){124 AggInfo info;125 memset(&info, 0, sizeof(info));126 127 const int N = 50;128 for(int k=0; k<N; k++){129 int idx = test_addAggInfoFunc(NULL, &info);130 TEST_ASSERT_EQUAL_INT(k, idx);131 TEST_ASSERT_EQUAL_INT(k+1, info.nFunc);132 TEST_ASSERT_NOT_NULL(info.aFunc);133 134 /* The most recently added slot must be zeroed */135 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[idx], sizeof(info.aFunc[idx])));136 137 /* Optionally set a value in a previous element and ensure it persists after growth */138 if( k==0 ){139 info.aFunc[0].iMem = 777;140 }else{141 TEST_ASSERT_EQUAL_INT(777, info.aFunc[0].iMem);142 }143 }144 145 /* Cleanup */146 sqlite3_free(info.aFunc);147}148 149/* Test 4: Works with a real sqlite3* handle (db lookaside-aware allocation path) */150void test_addAggInfoFunc_with_real_db(void){151 sqlite3 *db = NULL;152 int rc = sqlite3_open(":memory:", &db);153 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 TEST_ASSERT_NOT_NULL(db);155 156 AggInfo info;157 memset(&info, 0, sizeof(info));158 159 int idx0 = test_addAggInfoFunc(db, &info);160 TEST_ASSERT_EQUAL_INT(0, idx0);161 TEST_ASSERT_EQUAL_INT(1, info.nFunc);162 TEST_ASSERT_NOT_NULL(info.aFunc);163 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[0], sizeof(info.aFunc[0])));164 165 int idx1 = test_addAggInfoFunc(db, &info);166 TEST_ASSERT_EQUAL_INT(1, idx1);167 TEST_ASSERT_EQUAL_INT(2, info.nFunc);168 TEST_ASSERT_TRUE(is_zero_memory(&info.aFunc[1], sizeof(info.aFunc[1])));169 170 /* Cleanup using db-aware free */171 sqlite3DbFree(db, info.aFunc);172 sqlite3_close(db);173}174 175/* Test 5: Allocation failure returns negative and does not modify pInfo */176void test_addAggInfoFunc_allocation_failure_returns_negative(void){177 /* Install failing allocator */178 int rc = installFailingAllocator();179 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);180 181 AggInfo info;182 memset(&info, 0, sizeof(info));183 184 int idx = test_addAggInfoFunc(NULL, &info);185 TEST_ASSERT_TRUE(idx < 0);186 TEST_ASSERT_EQUAL_INT(0, info.nFunc);187 TEST_ASSERT_NULL(info.aFunc);188 189 /* Restore allocator for the rest of the tests */190 rc = restoreAllocator();191 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);192 g_haveOrigMem = 0;193}194 195int main(void){196 UNITY_BEGIN();197 RUN_TEST(test_addAggInfoFunc_first_alloc_db_null);198 RUN_TEST(test_addAggInfoFunc_second_alloc_preserve_and_zero_new);199 RUN_TEST(test_addAggInfoFunc_multiple_appends_indexes);200 RUN_TEST(test_addAggInfoFunc_with_real_db);201 RUN_TEST(test_addAggInfoFunc_allocation_failure_returns_negative);202 return UNITY_END();203}