Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_createFunctionApi.c221 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Prototype for the provided test wrapper around the static function */7extern int test_createFunctionApi(8  sqlite3 *db,9  const char *zFunc,10  int nArg,11  int enc,12  void *p,13  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),14  void (*xStep)(sqlite3_context*,int,sqlite3_value**),15  void (*xFinal)(sqlite3_context*),16  void (*xValue)(sqlite3_context*),17  void (*xInverse)(sqlite3_context*,int,sqlite3_value**),18  void(*xDestroy)(void*)19);20 21/* Minimal scalar function: returns arg0 + 1 (or 1 if null) */22static void sfunc_add_one(sqlite3_context *ctx, int argc, sqlite3_value **argv){23  int v = 0;24  if( argc>0 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){25    v = sqlite3_value_int(argv[0]);26  }27  sqlite3_result_int(ctx, v+1);28}29 30/* No-op aggregate step and finalizers */31static void step_noop(sqlite3_context *ctx, int argc, sqlite3_value **argv){32  (void)ctx; (void)argc; (void)argv;33}34static void final_noop(sqlite3_context *ctx){35  (void)ctx;36}37 38/* No-op value/inverse (for window-only functions) */39static void value_noop(sqlite3_context *ctx){40  (void)ctx;41}42static void inverse_noop(sqlite3_context *ctx, int argc, sqlite3_value **argv){43  (void)ctx; (void)argc; (void)argv;44}45 46/* Destructor that increments an integer at the provided pointer */47static void destroy_incr(void *p){48  int *pi = (int*)p;49  if( pi ) (*pi)++;50}51 52void setUp(void) {53  /* No global setup needed */54}55void tearDown(void) {56  /* No global teardown needed */57}58 59/* Test: Deleting a non-existent function should be a no-op (SQLITE_OK),60   and xDestroy must be called once because the FuncDestructor is unused. */61void test_createFunctionApi_delete_noop_calls_destructor(void){62  sqlite3 *db = 0;63  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));64 65  int dcount = 0;66  int rc = test_createFunctionApi(67    db, "nonexistent_func", -1, SQLITE_UTF8,68    &dcount,69    0, 0, 0, 0, 0,70    destroy_incr71  );72  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);73  TEST_ASSERT_EQUAL_INT(1, dcount);74 75  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));76}77 78/* Test: Misuse of API (both xSFunc and xFinal set) should return error,79   and xDestroy must be called once because FuncDestructor is unused. */80void test_createFunctionApi_misuse_calls_destructor(void){81  sqlite3 *db = 0;82  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));83 84  int dcount = 0;85  int rc = test_createFunctionApi(86    db, "bad_func", 1, SQLITE_UTF8,87    &dcount,88    sfunc_add_one,              /* xSFunc != 0 */89    0,90    final_noop,                 /* xFinal != 0 -> misuse */91    0, 0,92    destroy_incr93  );94  TEST_ASSERT_NOT_EQUAL(SQLITE_OK, rc);95  TEST_ASSERT_EQUAL_INT(1, dcount);96 97  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));98}99 100/* Test: Successful scalar registration should not call xDestroy immediately.101   Upon later deletion, the destructor of the existing function must be called exactly once. */102void test_createFunctionApi_register_and_delete_scalar(void){103  sqlite3 *db = 0;104  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));105 106  int dcount = 0;107  int rc = test_createFunctionApi(108    db, "ok_func_scalar", 1, SQLITE_UTF8,109    &dcount,110    sfunc_add_one,  /* scalar function */111    0, 0,           /* xStep/xFinal both 0 -> fine */112    0, 0,           /* xValue/xInverse both 0 */113    destroy_incr114  );115  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);116  TEST_ASSERT_EQUAL_INT(0, dcount); /* Not called yet */117 118  /* Now delete the function (no xDestroy passed to the delete call).119     The original destructor must be invoked now. */120  rc = test_createFunctionApi(121    db, "ok_func_scalar", 1, SQLITE_UTF8,122    0,123    0, 0, 0, 0, 0,124    0125  );126  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);127  TEST_ASSERT_EQUAL_INT(1, dcount);128 129  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));130}131 132/* Test: Attempt to modify/delete an existing function while there are active VMs.133   Emulate an active VM by setting db->nVdbeActive.134   Expect SQLITE_BUSY, input xDestroy called, and existing destructor NOT called. */135void test_createFunctionApi_busy_prevents_modify_and_calls_input_destructor_only(void){136  sqlite3 *db = 0;137  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));138 139  /* Register an existing function with a destructor */140  int existing_dcount = 0;141  int rc = test_createFunctionApi(142    db, "busy_func", 1, SQLITE_UTF8,143    &existing_dcount,144    sfunc_add_one,145    0, 0,146    0, 0,147    destroy_incr148  );149  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);150  TEST_ASSERT_EQUAL_INT(0, existing_dcount);151 152  /* Emulate active statements */153  db->nVdbeActive = 1;154 155  /* Attempt to delete/modify it with a new destructor payload */156  int input_dcount = 0;157  rc = test_createFunctionApi(158    db, "busy_func", 1, SQLITE_UTF8,159    &input_dcount,160    0, 0, 0, 0, 0,161    destroy_incr162  );163  TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc);164  TEST_ASSERT_EQUAL_INT(1, input_dcount);     /* input destructor called */165  TEST_ASSERT_EQUAL_INT(0, existing_dcount);  /* existing destructor NOT called */166 167  /* Clear active VMs and delete for cleanup */168  db->nVdbeActive = 0;169  rc = test_createFunctionApi(170    db, "busy_func", 1, SQLITE_UTF8,171    0,172    0, 0, 0, 0, 0,173    0174  );175  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);176  TEST_ASSERT_EQUAL_INT(1, existing_dcount);  /* now called */177 178  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));179}180 181/* Test: Successful window-only registration (xValue/xInverse) without xSFunc.182   Destructor should be called upon deletion only. */183void test_createFunctionApi_register_and_delete_window_only(void){184  sqlite3 *db = 0;185  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));186 187  int dcount = 0;188  int rc = test_createFunctionApi(189    db, "ok_func_window_only", 1, SQLITE_UTF8,190    &dcount,191    0,            /* xSFunc must be 0 when xValue!=0 */192    0, 0,193    value_noop,   /* window-only value */194    inverse_noop, /* window-only inverse */195    destroy_incr196  );197  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);198  TEST_ASSERT_EQUAL_INT(0, dcount);199 200  /* Delete and expect destructor call */201  rc = test_createFunctionApi(202    db, "ok_func_window_only", 1, SQLITE_UTF8,203    0,204    0, 0, 0, 0, 0,205    0206  );207  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);208  TEST_ASSERT_EQUAL_INT(1, dcount);209 210  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));211}212 213int main(void){214  UNITY_BEGIN();215  RUN_TEST(test_createFunctionApi_delete_noop_calls_destructor);216  RUN_TEST(test_createFunctionApi_misuse_calls_destructor);217  RUN_TEST(test_createFunctionApi_register_and_delete_scalar);218  RUN_TEST(test_createFunctionApi_busy_prevents_modify_and_calls_input_destructor_only);219  RUN_TEST(test_createFunctionApi_register_and_delete_window_only);220  return UNITY_END();221}