Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3_create_function_v2.c235 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdint.h>6 7/* Global counters for verification */8static volatile int g_destroy_count = 0;9static volatile int g_scalar_calls = 0;10static volatile int g_step_calls = 0;11static volatile int g_final_calls = 0;12 13/* Destructor used with sqlite3_create_function_v2 */14static void destructor_counter(void *p){15  int *pi = (int*)p;16  g_destroy_count++;17  if( pi ) (*pi)++;18}19 20/* Scalar: double the integer input */21static void udf_double(sqlite3_context *ctx, int argc, sqlite3_value **argv){22  g_scalar_calls++;23  int v = (argc>0) ? sqlite3_value_int(argv[0]) : 0;24  sqlite3_result_int(ctx, v*2);25}26 27/* Scalar variable-arity: return argc */28static void udf_argcount(sqlite3_context *ctx, int argc, sqlite3_value **argv){29  (void)argv;30  sqlite3_result_int(ctx, argc);31}32 33/* Aggregate SUM(x): step */34static void agg_step_sum(sqlite3_context *ctx, int argc, sqlite3_value **argv){35  g_step_calls++;36  if( argc<1 ) return;37  long long *pSum = (long long*)sqlite3_aggregate_context(ctx, sizeof(long long));38  if( pSum ){39    int v = sqlite3_value_int(argv[0]);40    *pSum += v;41  }42}43 44/* Aggregate SUM(x): final */45static void agg_final_sum(sqlite3_context *ctx){46  g_final_calls++;47  long long *pSum = (long long*)sqlite3_aggregate_context(ctx, 0);48  sqlite3_result_int64(ctx, pSum ? *pSum : 0);49}50 51/* Unity hooks */52void setUp(void) {53  g_destroy_count = 0;54  g_scalar_calls = 0;55  g_step_calls = 0;56  g_final_calls = 0;57}58 59void tearDown(void) {60  /* nothing */61}62 63/* Helper: prepare single-row/single-column integer result */64static int eval_int(sqlite3 *db, const char *zSql, int *pOut){65  sqlite3_stmt *stmt = 0;66  int rc = sqlite3_prepare_v2(db, zSql, -1, &stmt, 0);67  if( rc!=SQLITE_OK ) return rc;68  rc = sqlite3_step(stmt);69  if( rc==SQLITE_ROW ){70    *pOut = sqlite3_column_int(stmt, 0);71    rc = sqlite3_step(stmt);72    if( rc!=SQLITE_DONE ){73      sqlite3_finalize(stmt);74      return SQLITE_ERROR;75    }76    rc = SQLITE_OK;77  }else if( rc==SQLITE_DONE ){78    /* No row returned. */79    rc = SQLITE_ERROR;80  }81  sqlite3_finalize(stmt);82  return rc;83}84 85/* Test 1: Register scalar function and call it */86void test_sqlite3_create_function_v2_scalar_basic(void){87  sqlite3 *db = 0;88  int rc = sqlite3_open(":memory:", &db);89  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);90 91  rc = sqlite3_create_function_v2(92    db, "my_double_fn", 1, SQLITE_UTF8, NULL, udf_double, NULL, NULL, NULL93  );94  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95 96  sqlite3_stmt *stmt = 0;97  rc = sqlite3_prepare_v2(db, "SELECT my_double_fn(7);", -1, &stmt, 0);98  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);99 100  rc = sqlite3_step(stmt);101  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);102  TEST_ASSERT_EQUAL_INT(14, sqlite3_column_int(stmt, 0));103  rc = sqlite3_step(stmt);104  TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);105 106  sqlite3_finalize(stmt);107 108  /* Ensure the function body was executed exactly once in this simple query */109  TEST_ASSERT_EQUAL_INT(1, g_scalar_calls);110 111  sqlite3_close(db);112}113 114/* Test 2: Variable-arity function (nArg = -1) returns argument count */115void test_sqlite3_create_function_v2_variable_arity(void){116  sqlite3 *db = 0;117  int rc = sqlite3_open(":memory:", &db);118  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);119 120  rc = sqlite3_create_function_v2(121    db, "argcount", -1, SQLITE_UTF8, NULL, udf_argcount, NULL, NULL, NULL122  );123  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);124 125  int out = -1;126  rc = eval_int(db, "SELECT argcount();", &out);127  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);128  TEST_ASSERT_EQUAL_INT(0, out);129 130  out = -1;131  rc = eval_int(db, "SELECT argcount(1,2,3,4,5);", &out);132  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);133  TEST_ASSERT_EQUAL_INT(5, out);134 135  sqlite3_close(db);136}137 138/* Test 3: xDestroy is invoked on database close */139void test_sqlite3_create_function_v2_destructor_on_close(void){140  sqlite3 *db = 0;141  int rc = sqlite3_open(":memory:", &db);142  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);143 144  int user_data_mark = 0;145 146  rc = sqlite3_create_function_v2(147    db, "noop_fn", 1, SQLITE_UTF8, &user_data_mark, udf_double, NULL, NULL, destructor_counter148  );149  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);150 151  /* Close the database: xDestroy should be called exactly once */152  rc = sqlite3_close(db);153  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 155  TEST_ASSERT_EQUAL_INT(1, g_destroy_count);156  TEST_ASSERT_EQUAL_INT(1, user_data_mark);157}158 159/* Test 4: xDestroy is invoked when the function is redefined */160void test_sqlite3_create_function_v2_destructor_on_redefine(void){161  sqlite3 *db = 0;162  int rc = sqlite3_open(":memory:", &db);163  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);164 165  int user_a = 0;166  int user_b = 0;167 168  rc = sqlite3_create_function_v2(169    db, "redef_fn", 1, SQLITE_UTF8, &user_a, udf_double, NULL, NULL, destructor_counter170  );171  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);172 173  /* Redefine same function name/signature */174  rc = sqlite3_create_function_v2(175    db, "redef_fn", 1, SQLITE_UTF8, &user_b, udf_double, NULL, NULL, destructor_counter176  );177  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);178 179  /* The first registration should have been destroyed upon redefinition */180  TEST_ASSERT_EQUAL_INT(1, user_a);181  TEST_ASSERT_TRUE(g_destroy_count >= 1);182 183  /* Close the DB should destroy the second registration */184  rc = sqlite3_close(db);185  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);186 187  TEST_ASSERT_EQUAL_INT(1, user_b);188  TEST_ASSERT_EQUAL_INT(2, g_destroy_count);189}190 191/* Test 5: Register and run an aggregate function implemented via xStep/xFinal */192void test_sqlite3_create_function_v2_aggregate_basic(void){193  sqlite3 *db = 0;194  int rc = sqlite3_open(":memory:", &db);195  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);196 197  rc = sqlite3_create_function_v2(198    db, "test_sum", 1, SQLITE_UTF8, NULL, NULL, agg_step_sum, agg_final_sum, NULL199  );200  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);201 202  rc = sqlite3_exec(db, "CREATE TABLE t(x INTEGER);", 0, 0, 0);203  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);204  rc = sqlite3_exec(db, "INSERT INTO t(x) VALUES(1),(2),(3);", 0, 0, 0);205  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);206 207  sqlite3_stmt *stmt = 0;208  rc = sqlite3_prepare_v2(db, "SELECT test_sum(x) FROM t;", -1, &stmt, 0);209  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);210 211  rc = sqlite3_step(stmt);212  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);213  TEST_ASSERT_EQUAL_INT(6, sqlite3_column_int(stmt, 0));214  rc = sqlite3_step(stmt);215  TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);216 217  sqlite3_finalize(stmt);218 219  /* Sanity check that step/final were invoked appropriate number of times */220  TEST_ASSERT_EQUAL_INT(3, g_step_calls);221  TEST_ASSERT_EQUAL_INT(1, g_final_calls);222 223  sqlite3_close(db);224}225 226/* Main runner */227int main(void) {228  UNITY_BEGIN();229  RUN_TEST(test_sqlite3_create_function_v2_scalar_basic);230  RUN_TEST(test_sqlite3_create_function_v2_variable_arity);231  RUN_TEST(test_sqlite3_create_function_v2_destructor_on_close);232  RUN_TEST(test_sqlite3_create_function_v2_destructor_on_redefine);233  RUN_TEST(test_sqlite3_create_function_v2_aggregate_basic);234  return UNITY_END();235}