AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/*9 Test suite for: static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv)10 Wrapper provided in module: void test_countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv);11*/12extern void test_countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv);13 14/* Globals to steer the aggregate step behavior for each test */15static int gMode = 0; /* 1: argc=0, 2: argc=1 NULL, 3: argc=1 non-NULL */16static sqlite3_int64 gInitial = 3;17 18/* Aggregate step callback that sets up aggregate context and invokes test_countInverse */19static void invtestStep(sqlite3_context *ctx, int argc, sqlite3_value **argv){20 (void)argc; (void)argv;21 22 /* Allocate/obtain the aggregate context and initialize the first 8 bytes (CountCtx.n) */23 void *p = sqlite3_aggregate_context(ctx, 16); /* >= sizeof(CountCtx) across builds */24 TEST_ASSERT_NOT_NULL_MESSAGE(p, "sqlite3_aggregate_context returned NULL in step");25 26 /* Initialize starting count to gInitial */27 ((sqlite3_int64*)p)[0] = gInitial;28 29 sqlite3_int64 expectedAfter = gInitial;30 31 if( gMode==1 ){32 /* argc==0 case: should decrement */33 test_countInverse(ctx, 0, NULL);34 expectedAfter = gInitial - 1;35 }else if( gMode==2 ){36 /* argc==1 with NULL argument: should NOT decrement */37 Mem m; memset(&m, 0, sizeof(m));38 m.flags = MEM_Null; /* Represents a NULL sqlite3_value */39 sqlite3_value *localArgv[1];40 localArgv[0] = (sqlite3_value*)&m;41 test_countInverse(ctx, 1, localArgv);42 expectedAfter = gInitial;43 }else if( gMode==3 ){44 /* argc==1 with non-NULL integer argument: should decrement */45 Mem m; memset(&m, 0, sizeof(m));46 m.flags = MEM_Int;47#if defined(SQLITE_OMIT_FLOATING_POINT)48 m.u.i = 123; /* integer path */49#else50 m.u.i = 123;51#endif52 sqlite3_value *localArgv[1];53 localArgv[0] = (sqlite3_value*)&m;54 test_countInverse(ctx, 1, localArgv);55 expectedAfter = gInitial - 1;56 }else{57 TEST_FAIL_MESSAGE("Invalid gMode in invtestStep");58 }59 60 /* Verify the same aggregate context pointer and expected count value */61 void *p2 = sqlite3_aggregate_context(ctx, 0);62 TEST_ASSERT_EQUAL_PTR(p, p2);63 64 sqlite3_int64 after = ((sqlite3_int64*)p2)[0];65 TEST_ASSERT_EQUAL_INT64(expectedAfter, after);66}67 68/* Aggregate final callback - nothing required for these tests */69static void invtestFinal(sqlite3_context *ctx){70 /* No-op: The test assertions are performed in the step function */71 (void)ctx;72}73 74void setUp(void) {75 /* No global setup needed */76}77 78void tearDown(void) {79 /* No global teardown needed */80}81 82/* Helper to execute a single-row aggregate to trigger one step invocation */83static void run_single_row_aggregate(sqlite3 *db){84 int rc;85 char *zErrMsg = NULL;86 /* Single row to ensure exactly one xStep() call */87 rc = sqlite3_exec(db, "SELECT invtest(1);", 0, 0, &zErrMsg);88 if( zErrMsg ){89 /* Ensure no leaked error message */90 TEST_MESSAGE(zErrMsg);91 sqlite3_free(zErrMsg);92 }93 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);94}95 96/* Register the aggregate function used for testing */97static void register_invtest(sqlite3 *db){98 int rc = sqlite3_create_function_v2(99 db,100 "invtest", /* name */101 1, /* nArg: we pass 1 arg in SQL, but internal tests ignore it */102 SQLITE_UTF8, /* encoding */103 NULL, /* pApp */104 NULL, /* xFunc (scalar) */105 invtestStep, /* xStep (aggregate) */106 invtestFinal, /* xFinal */107 NULL /* xDestroy */108 );109 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);110}111 112void test_countInverse_decrements_when_no_args(void){113 sqlite3 *db = NULL;114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));115 register_invtest(db);116 117 gMode = 1; /* argc==0 path */118 gInitial = 3;119 run_single_row_aggregate(db);120 121 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));122}123 124void test_countInverse_no_decrement_when_arg_is_NULL(void){125 sqlite3 *db = NULL;126 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));127 register_invtest(db);128 129 gMode = 2; /* argc==1 with NULL argument */130 gInitial = 5; /* Use different initial to ensure independence */131 run_single_row_aggregate(db);132 133 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));134}135 136void test_countInverse_decrements_when_arg_not_NULL(void){137 sqlite3 *db = NULL;138 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));139 register_invtest(db);140 141 gMode = 3; /* argc==1 with non-NULL argument */142 gInitial = 10;143 run_single_row_aggregate(db);144 145 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));146}147 148int main(void) {149 UNITY_BEGIN();150 RUN_TEST(test_countInverse_decrements_when_no_args);151 RUN_TEST(test_countInverse_no_decrement_when_arg_is_NULL);152 RUN_TEST(test_countInverse_decrements_when_arg_not_NULL);153 return UNITY_END();154}