Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3_set_clientdata.c301 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Helper destructor counters */8static int d1_count = 0;9static int d2_count = 0;10static int d3_count = 0;11static void *last_dtor_ptr = NULL;12 13static void d1(void *p){14  d1_count++;15  last_dtor_ptr = p;16}17static void d2(void *p){18  d2_count++;19  last_dtor_ptr = p;20}21static void d3(void *p){22  d3_count++;23  last_dtor_ptr = p;24}25 26/* Helper: find a DbClientData entry by name */27static DbClientData* findEntry(sqlite3 *db, const char *zName){28  DbClientData *p;29  for(p=db->pDbData; p; p=p->pNext){30    if(0==strcmp(p->zName, zName)) return p;31  }32  return NULL;33}34 35/* Memory allocator override to simulate OOM */36static sqlite3_mem_methods gOrigMem;37static sqlite3_mem_methods gFailMem;38static int gFailAlloc = 0;39 40static int failingInit(void *pAppData){41  /* Initialize the original allocator */42  if( gOrigMem.xInit ){43    return gOrigMem.xInit(gOrigMem.pAppData);44  }45  return SQLITE_OK;46}47static void failingShutdown(void *pAppData){48  if( gOrigMem.xShutdown ){49    gOrigMem.xShutdown(gOrigMem.pAppData);50  }51}52static void *failingMalloc(int n){53  if( gFailAlloc ) return NULL;54  return gOrigMem.xMalloc ? gOrigMem.xMalloc(n) : NULL;55}56static void failingFree(void *p){57  if( gOrigMem.xFree ) gOrigMem.xFree(p);58}59static void *failingRealloc(void *p, int n){60  if( gFailAlloc ) return NULL;61  return gOrigMem.xRealloc ? gOrigMem.xRealloc(p, n) : NULL;62}63static int failingSize(void *p){64  return gOrigMem.xSize ? gOrigMem.xSize(p) : 0;65}66static int failingRoundup(int n){67  return gOrigMem.xRoundup ? gOrigMem.xRoundup(n) : n;68}69 70static int installFailingAllocator(void){71  int rc;72  sqlite3_shutdown();73  rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &gOrigMem);74  if( rc!=SQLITE_OK ) return rc;75 76  memset(&gFailMem, 0, sizeof(gFailMem));77  gFailMem.xMalloc   = failingMalloc;78  gFailMem.xFree     = failingFree;79  gFailMem.xRealloc  = failingRealloc;80  gFailMem.xSize     = failingSize;81  gFailMem.xRoundup  = failingRoundup;82  gFailMem.xInit     = failingInit;83  gFailMem.xShutdown = failingShutdown;84  gFailMem.pAppData  = gOrigMem.pAppData;85 86  rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &gFailMem);87  if( rc!=SQLITE_OK ) return rc;88  rc = sqlite3_initialize();89  return rc;90}91 92static void uninstallAllocator(void){93  sqlite3_shutdown();94  sqlite3_config(SQLITE_CONFIG_MALLOC, &gOrigMem);95  sqlite3_initialize();96}97 98/* Unity setup/teardown */99void setUp(void) {100  d1_count = d2_count = d3_count = 0;101  last_dtor_ptr = NULL;102  gFailAlloc = 0;103}104void tearDown(void) {105  /* nothing */106}107 108/* Tests */109 110void test_sqlite3_set_clientdata_insert_new_and_find(void){111  sqlite3 *db = NULL;112  int rc = sqlite3_open(":memory:", &db);113  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);114  TEST_ASSERT_NOT_NULL(db);115  TEST_ASSERT_NULL(db->pDbData);116 117  int payload = 123;118  rc = sqlite3_set_clientdata(db, "k1", &payload, NULL);119  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);120 121  DbClientData *p = findEntry(db, "k1");122  TEST_ASSERT_NOT_NULL(p);123  TEST_ASSERT_EQUAL_PTR(&payload, p->pData);124  TEST_ASSERT_NULL(p->xDestructor);125  TEST_ASSERT_EQUAL_INT(0, strcmp("k1", p->zName));126 127  sqlite3_close(db);128}129 130void test_sqlite3_set_clientdata_replace_calls_old_destructor(void){131  sqlite3 *db = NULL;132  int rc = sqlite3_open(":memory:", &db);133  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);134 135  int oldPayload = 0x11;136  int newPayload = 0x22;137 138  /* Insert with destructor d1 (should not be called on insert) */139  rc = sqlite3_set_clientdata(db, "k", &oldPayload, d1);140  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);141  TEST_ASSERT_EQUAL_INT(0, d1_count);142 143  /* Replace: must call old destructor (d1) with oldPayload */144  rc = sqlite3_set_clientdata(db, "k", &newPayload, d2);145  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);146  TEST_ASSERT_EQUAL_INT(1, d1_count);147  TEST_ASSERT_EQUAL_PTR(&oldPayload, last_dtor_ptr);148  TEST_ASSERT_EQUAL_INT(0, d2_count);149 150  /* Verify new data and destructor stored */151  DbClientData *p = findEntry(db, "k");152  TEST_ASSERT_NOT_NULL(p);153  TEST_ASSERT_EQUAL_PTR(&newPayload, p->pData);154  TEST_ASSERT_EQUAL_PTR(d2, p->xDestructor);155 156  sqlite3_close(db);157}158 159void test_sqlite3_set_clientdata_insert_with_null_destructor_then_replace_no_dtor_call_on_first(void){160  sqlite3 *db = NULL;161  int rc = sqlite3_open(":memory:", &db);162  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);163 164  int oldPayload = 0x100;165  int newPayload = 0x200;166 167  /* Insert with NULL destructor (should not call anything) */168  rc = sqlite3_set_clientdata(db, "knull", &oldPayload, NULL);169  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);170  TEST_ASSERT_EQUAL_INT(0, d1_count);171  TEST_ASSERT_EQUAL_INT(0, d2_count);172 173  /* Replace: since old destructor is NULL, no destructor call should occur here */174  rc = sqlite3_set_clientdata(db, "knull", &newPayload, d1);175  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);176  TEST_ASSERT_EQUAL_INT(0, d1_count);177 178  DbClientData *p = findEntry(db, "knull");179  TEST_ASSERT_NOT_NULL(p);180  TEST_ASSERT_EQUAL_PTR(&newPayload, p->pData);181  TEST_ASSERT_EQUAL_PTR(d1, p->xDestructor);182 183  sqlite3_close(db);184}185 186void test_sqlite3_set_clientdata_remove_existing_calls_destructor_and_unlinks(void){187  sqlite3 *db = NULL;188  int rc = sqlite3_open(":memory:", &db);189  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);190 191  int payload = 0x33;192  rc = sqlite3_set_clientdata(db, "rm", &payload, d2);193  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);194 195  /* Remove: pData==NULL triggers deletion; old destructor (d2) is called */196  rc = sqlite3_set_clientdata(db, "rm", NULL, d3 /* irrelevant */);197  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);198  TEST_ASSERT_EQUAL_INT(1, d2_count);199  TEST_ASSERT_EQUAL_PTR(&payload, last_dtor_ptr);200  TEST_ASSERT_EQUAL_INT(0, d3_count); /* the passed-in destructor is not used on removal */201 202  /* Ensure entry is gone */203  DbClientData *p = findEntry(db, "rm");204  TEST_ASSERT_NULL(p);205 206  sqlite3_close(db);207}208 209void test_sqlite3_set_clientdata_remove_nonexistent_is_noop(void){210  sqlite3 *db = NULL;211  int rc = sqlite3_open(":memory:", &db);212  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);213 214  /* Ensure not present */215  TEST_ASSERT_NULL(findEntry(db, "absent"));216 217  /* Removal of non-existent should be OK and not call destructor */218  rc = sqlite3_set_clientdata(db, "absent", NULL, d1);219  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);220  TEST_ASSERT_EQUAL_INT(0, d1_count);221 222  sqlite3_close(db);223}224 225void test_sqlite3_set_clientdata_multiple_entries_are_independent(void){226  sqlite3 *db = NULL;227  int rc = sqlite3_open(":memory:", &db);228  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);229 230  int pa = 1, pb = 2, pb2 = 3;231 232  rc = sqlite3_set_clientdata(db, "A", &pa, d1);233  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);234  rc = sqlite3_set_clientdata(db, "B", &pb, d2);235  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);236 237  /* Remove A: should call d1, leave B intact */238  rc = sqlite3_set_clientdata(db, "A", NULL, d3 /* irrelevant */);239  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);240  TEST_ASSERT_EQUAL_INT(1, d1_count);241  TEST_ASSERT_EQUAL_INT(0, d2_count);242  TEST_ASSERT_NULL(findEntry(db, "A"));243  DbClientData *pB = findEntry(db, "B");244  TEST_ASSERT_NOT_NULL(pB);245  TEST_ASSERT_EQUAL_PTR(&pb, pB->pData);246  TEST_ASSERT_EQUAL_PTR(d2, pB->xDestructor);247 248  /* Replace B: should call d2 and update to pb2 and destructor d3 */249  rc = sqlite3_set_clientdata(db, "B", &pb2, d3);250  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);251  TEST_ASSERT_EQUAL_INT(1, d2_count);252  pB = findEntry(db, "B");253  TEST_ASSERT_NOT_NULL(pB);254  TEST_ASSERT_EQUAL_PTR(&pb2, pB->pData);255  TEST_ASSERT_EQUAL_PTR(d3, pB->xDestructor);256 257  sqlite3_close(db);258}259 260void test_sqlite3_set_clientdata_allocation_failure_returns_nomem_and_calls_destructor(void){261  int rc = installFailingAllocator();262  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);263 264  sqlite3 *db = NULL;265  rc = sqlite3_open(":memory:", &db);266  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);267 268  /* Ensure name doesn't exist */269  TEST_ASSERT_NULL(findEntry(db, "oom"));270 271  /* Cause malloc to fail only for the following call */272  gFailAlloc = 1;273  int payload = 0x999;274  rc = sqlite3_set_clientdata(db, "oom", &payload, d1);275  gFailAlloc = 0;276 277  TEST_ASSERT_EQUAL_INT(SQLITE_NOMEM, rc);278  /* Destructor should be called on the provided payload because allocation failed */279  TEST_ASSERT_EQUAL_INT(1, d1_count);280  TEST_ASSERT_EQUAL_PTR(&payload, last_dtor_ptr);281 282  /* Ensure entry was not added */283  DbClientData *p = findEntry(db, "oom");284  TEST_ASSERT_NULL(p);285 286  sqlite3_close(db);287  uninstallAllocator();288}289 290/* main */291int main(void){292  UNITY_BEGIN();293  RUN_TEST(test_sqlite3_set_clientdata_insert_new_and_find);294  RUN_TEST(test_sqlite3_set_clientdata_replace_calls_old_destructor);295  RUN_TEST(test_sqlite3_set_clientdata_insert_with_null_destructor_then_replace_no_dtor_call_on_first);296  RUN_TEST(test_sqlite3_set_clientdata_remove_existing_calls_destructor_and_unlinks);297  RUN_TEST(test_sqlite3_set_clientdata_remove_nonexistent_is_noop);298  RUN_TEST(test_sqlite3_set_clientdata_multiple_entries_are_independent);299  RUN_TEST(test_sqlite3_set_clientdata_allocation_failure_returns_nomem_and_calls_destructor);300  return UNITY_END();301}