AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdio.h>7#include <stdint.h>8 9/* Unity setup/teardown */10void setUp(void) {11 /* Ensure SQLite subsystems (including memory allocator) are initialized */12 sqlite3_initialize();13}14void tearDown(void) {15 /* Shutdown between tests to avoid cross-test interference */16 sqlite3_shutdown();17}18 19/* Helper to populate a hash with n distinct key/value pairs.20 Keys are stored in keys[i], values are addresses of values[i]. */21static void populate_hash(Hash *pH, int n, char keys[][32], int *values){22 for(int i=0; i<n; i++){23 snprintf(keys[i], 32, "key_%03d", i);24 values[i] = i + 1000;25 void *old = sqlite3HashInsert(pH, keys[i], &values[i]);26 TEST_ASSERT_NULL(old);27 }28}29 30/* Test: Clearing an empty hash should be a no-op and maintain zeroed state. */31void test_sqlite3HashClear_on_empty_hash(void){32 Hash h;33 sqlite3HashInit(&h);34 35 /* Verify initial state */36 TEST_ASSERT_EQUAL_PTR(NULL, h.first);37 TEST_ASSERT_EQUAL_UINT(0u, h.count);38 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);39 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);40 41 /* Clear empty */42 sqlite3HashClear(&h);43 44 /* Verify remains empty */45 TEST_ASSERT_EQUAL_PTR(NULL, h.first);46 TEST_ASSERT_EQUAL_UINT(0u, h.count);47 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);48 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);49 50 /* Ensure find returns NULL */51 TEST_ASSERT_NULL(sqlite3HashFind(&h, "nonexistent"));52}53 54/* Test: Insert a single element, then clear. */55void test_sqlite3HashClear_after_single_insert(void){56 Hash h;57 sqlite3HashInit(&h);58 59 int v = 42;60 const char *key = "abc";61 void *old = sqlite3HashInsert(&h, key, &v);62 TEST_ASSERT_NULL(old);63 64 /* Pre-clear: should find value (case-insensitive) */65 TEST_ASSERT_EQUAL_PTR(&v, sqlite3HashFind(&h, "ABC"));66 TEST_ASSERT_EQUAL_UINT(1u, h.count);67 TEST_ASSERT_NOT_NULL(h.first);68 69 /* Clear */70 sqlite3HashClear(&h);71 72 /* Post-clear state */73 TEST_ASSERT_EQUAL_PTR(NULL, h.first);74 TEST_ASSERT_EQUAL_UINT(0u, h.count);75 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);76 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);77 78 /* Should not find previously inserted key */79 TEST_ASSERT_NULL(sqlite3HashFind(&h, "abc"));80 TEST_ASSERT_NULL(sqlite3HashFind(&h, "ABC"));81}82 83/* Test: Insert many elements (likely causing bucket allocation/rehash), then clear. */84void test_sqlite3HashClear_many_inserts_and_rehash(void){85 Hash h;86 sqlite3HashInit(&h);87 88 enum { N = 40 };89 char keys[N][32];90 int values[N];91 92 populate_hash(&h, N, keys, values);93 94 /* Pre-clear: Should find a couple of entries */95 TEST_ASSERT_EQUAL_UINT((unsigned)N, h.count);96 void *found0 = sqlite3HashFind(&h, "KEY_000"); /* case-insensitive */97 void *foundN1 = sqlite3HashFind(&h, "KEY_039");98 TEST_ASSERT_NOT_NULL(found0);99 TEST_ASSERT_NOT_NULL(foundN1);100 101 /* Record whether buckets were allocated (implementation detail) */102 int hadBuckets = (h.ht != NULL);103 unsigned int pre_htsize = h.htsize;104 105 /* Clear */106 sqlite3HashClear(&h);107 108 /* Post-clear invariants */109 TEST_ASSERT_EQUAL_PTR(NULL, h.first);110 TEST_ASSERT_EQUAL_UINT(0u, h.count);111 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);112 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);113 114 /* Ensure previous keys are gone */115 TEST_ASSERT_NULL(sqlite3HashFind(&h, "KEY_000"));116 TEST_ASSERT_NULL(sqlite3HashFind(&h, "KEY_039"));117 118 /* Reuse the hash after clearing */119 int v = 777;120 void *old = sqlite3HashInsert(&h, "after_clear", &v);121 TEST_ASSERT_NULL(old);122 TEST_ASSERT_EQUAL_UINT(1u, h.count);123 TEST_ASSERT_EQUAL_PTR(&v, sqlite3HashFind(&h, "AFTER_CLEAR"));124 125 /* If buckets existed before, they must have been freed and not retained */126 if( hadBuckets ){127 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);128 }129 130 /* Clean up and clear again to ensure no residual state */131 sqlite3HashClear(&h);132 TEST_ASSERT_EQUAL_UINT(0u, h.count);133 TEST_ASSERT_EQUAL_PTR(NULL, sqlite3HashFind(&h, "after_clear"));134}135 136/* Test: sqlite3HashClear must not free or modify client data pointers. */137void test_sqlite3HashClear_does_not_free_client_data(void){138 Hash h;139 sqlite3HashInit(&h);140 141 int *pdata = (int*)sqlite3_malloc(sizeof(int));142 TEST_ASSERT_NOT_NULL(pdata);143 *pdata = 0x12345678;144 145 void *old = sqlite3HashInsert(&h, "data_key", pdata);146 TEST_ASSERT_NULL(old);147 TEST_ASSERT_EQUAL_PTR(pdata, sqlite3HashFind(&h, "DATA_KEY"));148 149 /* Clear the hash; user data must not be freed or modified */150 sqlite3HashClear(&h);151 152 /* Verify pdata remains valid and unchanged */153 TEST_ASSERT_EQUAL_INT(0x12345678, *pdata);154 sqlite3_free(pdata);155 156 /* Hash should be empty */157 TEST_ASSERT_EQUAL_UINT(0u, h.count);158 TEST_ASSERT_EQUAL_PTR(NULL, h.first);159 TEST_ASSERT_NULL(sqlite3HashFind(&h, "data_key"));160}161 162/* Test: Idempotency - calling sqlite3HashClear twice should be safe. */163void test_sqlite3HashClear_idempotent_twice(void){164 Hash h;165 sqlite3HashInit(&h);166 167 int a=1, b=2, c=3;168 TEST_ASSERT_NULL(sqlite3HashInsert(&h, "one", &a));169 TEST_ASSERT_NULL(sqlite3HashInsert(&h, "two", &b));170 TEST_ASSERT_NULL(sqlite3HashInsert(&h, "three", &c));171 172 TEST_ASSERT_EQUAL_UINT(3u, h.count);173 174 sqlite3HashClear(&h);175 176 TEST_ASSERT_EQUAL_UINT(0u, h.count);177 TEST_ASSERT_EQUAL_PTR(NULL, h.first);178 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);179 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);180 181 /* Second clear should be a no-op */182 sqlite3HashClear(&h);183 184 TEST_ASSERT_EQUAL_UINT(0u, h.count);185 TEST_ASSERT_EQUAL_PTR(NULL, h.first);186 TEST_ASSERT_EQUAL_UINT(0u, h.htsize);187 TEST_ASSERT_EQUAL_PTR(NULL, h.ht);188}189 190/* Main runner */191int main(void){192 UNITY_BEGIN();193 RUN_TEST(test_sqlite3HashClear_on_empty_hash);194 RUN_TEST(test_sqlite3HashClear_after_single_insert);195 RUN_TEST(test_sqlite3HashClear_many_inserts_and_rehash);196 RUN_TEST(test_sqlite3HashClear_does_not_free_client_data);197 RUN_TEST(test_sqlite3HashClear_idempotent_twice);198 return UNITY_END();199}