Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_func_sumInverse.c276 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <math.h>6#include <float.h>7 8/* Prototype of the test wrapper exposed by the module */9void test_sumInverse(sqlite3_context *context, int argc, sqlite3_value **argv);10 11/* Local dummy step function to satisfy sqlite3_aggregate_context() assertion */12static void dummyStep(sqlite3_context *ctx, int argc, sqlite3_value **argv){13  UNUSED_PARAMETER(ctx);14  UNUSED_PARAMETER(argc);15  UNUSED_PARAMETER(argv);16}17 18/* Helpers to create a valid sqlite3_context for aggregate usage */19static void makeContext(sqlite3 **pDb,20                        sqlite3_context *pCtx,21                        Mem **ppMem,22                        FuncDef *pFuncDef){23  memset(pCtx, 0, sizeof(*pCtx));24  memset(pFuncDef, 0, sizeof(*pFuncDef));25 26  /* Open an in-memory database */27  int rc = sqlite3_open(":memory:", pDb);28  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);29  TEST_ASSERT_NOT_NULL(*pDb);30 31  /* Create a Mem (sqlite3_value) tied to db */32  *ppMem = sqlite3ValueNew(*pDb);33  TEST_ASSERT_NOT_NULL(*ppMem);34 35  /* Configure FuncDef with non-NULL xSFunc */36  pFuncDef->xSFunc = dummyStep;37 38  /* Initialize context */39  pCtx->db = *pDb;40  pCtx->pMem = *ppMem;41  pCtx->pFunc = pFuncDef;42}43 44/* Helper to destroy a context */45static void destroyContext(sqlite3 *db, sqlite3_context *pCtx){46  if( pCtx && pCtx->pMem ){47    sqlite3ValueFree(pCtx->pMem);48    pCtx->pMem = NULL;49  }50  if( db ){51    sqlite3_close(db);52  }53}54 55/* Helpers to create argument values */56static sqlite3_value *makeIntValue(sqlite3 *db, i64 v){57  Mem *p = sqlite3ValueNew(db);58  TEST_ASSERT_NOT_NULL(p);59  sqlite3VdbeMemSetInt64(p, v);60  return (sqlite3_value*)p;61}62static sqlite3_value *makeRealValue(sqlite3 *db, double v){63  Mem *p = sqlite3ValueNew(db);64  TEST_ASSERT_NOT_NULL(p);65  sqlite3VdbeMemSetDouble(p, v);66  return (sqlite3_value*)p;67}68static sqlite3_value *makeNullValue(sqlite3 *db){69  Mem *p = sqlite3ValueNew(db);70  TEST_ASSERT_NOT_NULL(p);71  sqlite3VdbeMemSetNull(p);72  return (sqlite3_value*)p;73}74 75void setUp(void) {76  /* no-op */77}78 79void tearDown(void) {80  /* no-op */81}82 83/* Test 1: Integer-mode inverse without overflow: approx==0, subtract a small integer */84void test_sumInverse_integer_simple(void){85  sqlite3 *db = NULL;86  sqlite3_context ctx;87  Mem *pMem = NULL;88  FuncDef funcDef;89  makeContext(&db, &ctx, &pMem, &funcDef);90 91  /* Allocate SumCtx and initialize fields */92  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));93  TEST_ASSERT_NOT_NULL(pSum);94  memset(pSum, 0, sizeof(*pSum));95  pSum->cnt = 1;96  pSum->approx = 0;97  pSum->ovrfl = 0;98  pSum->iSum = 10; /* starting integer sum */99 100  sqlite3_value *argv0 = makeIntValue(db, 3);101  sqlite3_value *argv[1] = { argv0 };102 103  test_sumInverse(&ctx, 1, argv);104 105  TEST_ASSERT_EQUAL_INT(0, pSum->cnt);106  TEST_ASSERT_EQUAL_INT(0, pSum->approx);107  TEST_ASSERT_EQUAL_INT(0, pSum->ovrfl);108  TEST_ASSERT_EQUAL_INT64(7, pSum->iSum);109 110  sqlite3ValueFree((Mem*)argv0);111  destroyContext(db, &ctx);112}113 114/* Test 2: Integer-mode inverse with overflow: forces approx=1 and ovrfl=1 */115void test_sumInverse_integer_overflow_to_approx(void){116  sqlite3 *db = NULL;117  sqlite3_context ctx;118  Mem *pMem = NULL;119  FuncDef funcDef;120  makeContext(&db, &ctx, &pMem, &funcDef);121 122  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));123  TEST_ASSERT_NOT_NULL(pSum);124  memset(pSum, 0, sizeof(*pSum));125  pSum->cnt = 1;126  pSum->approx = 0;127  pSum->ovrfl = 0;128 129  /* Choose values so that iSum - (-10) overflows (iSum near LARGEST_INT64) */130  pSum->iSum = LARGEST_INT64 - 1;131  sqlite3_value *argv0 = makeIntValue(db, -10);132  sqlite3_value *argv[1] = { argv0 };133 134  test_sumInverse(&ctx, 1, argv);135 136  TEST_ASSERT_EQUAL_INT(0, pSum->cnt);137  TEST_ASSERT_EQUAL_INT(1, pSum->approx);138  TEST_ASSERT_EQUAL_INT(1, pSum->ovrfl);139 140  sqlite3ValueFree((Mem*)argv0);141  destroyContext(db, &ctx);142}143 144/* Test 3: Approx-mode with integer input: KBN step with -iVal */145void test_sumInverse_approx_with_integer(void){146  sqlite3 *db = NULL;147  sqlite3_context ctx;148  Mem *pMem = NULL;149  FuncDef funcDef;150  makeContext(&db, &ctx, &pMem, &funcDef);151 152  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));153  TEST_ASSERT_NOT_NULL(pSum);154  memset(pSum, 0, sizeof(*pSum));155  pSum->cnt = 2;156  pSum->approx = 1;   /* already in approximate mode */157  pSum->rSum = 0.0;158  pSum->rErr = 0.0;159 160  sqlite3_value *argv0 = makeIntValue(db, 5);161  sqlite3_value *argv[1] = { argv0 };162 163  test_sumInverse(&ctx, 1, argv);164 165  TEST_ASSERT_EQUAL_INT(1, pSum->cnt);166  TEST_ASSERT_EQUAL_INT(1, pSum->approx);167  TEST_ASSERT_DOUBLE_WITHIN(0.0, -5.0, pSum->rSum); /* exact -5 */168  TEST_ASSERT_DOUBLE_WITHIN(0.0, 0.0, pSum->rErr);169 170  sqlite3ValueFree((Mem*)argv0);171  destroyContext(db, &ctx);172}173 174/* Test 4: Approx-mode with SMALLEST_INT64: special-case path (two steps) */175void test_sumInverse_approx_with_smallest_int64(void){176  sqlite3 *db = NULL;177  sqlite3_context ctx;178  Mem *pMem = NULL;179  FuncDef funcDef;180  makeContext(&db, &ctx, &pMem, &funcDef);181 182  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));183  TEST_ASSERT_NOT_NULL(pSum);184  memset(pSum, 0, sizeof(*pSum));185  pSum->cnt = 1;186  pSum->approx = 1;187  pSum->rSum = 0.0;188  pSum->rErr = 0.0;189 190  sqlite3_value *argv0 = makeIntValue(db, SMALLEST_INT64);191  sqlite3_value *argv[1] = { argv0 };192 193  test_sumInverse(&ctx, 1, argv);194 195  /* Expect rSum == LARGEST_INT64 + 1 == 2^63, exactly representable in double */196  double expected = (double)LARGEST_INT64 + 1.0; /* 9223372036854775808.0 = 2^63 */197  TEST_ASSERT_EQUAL_INT(0, pSum->cnt);198  TEST_ASSERT_DOUBLE_WITHIN(0.0, expected, pSum->rSum);199  TEST_ASSERT_DOUBLE_WITHIN(0.0, 0.0, pSum->rErr);200 201  sqlite3ValueFree((Mem*)argv0);202  destroyContext(db, &ctx);203}204 205/* Test 5: Approx-mode with real input: KBN step with -double, and ovrfl cleared */206void test_sumInverse_approx_with_real(void){207  sqlite3 *db = NULL;208  sqlite3_context ctx;209  Mem *pMem = NULL;210  FuncDef funcDef;211  makeContext(&db, &ctx, &pMem, &funcDef);212 213  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));214  TEST_ASSERT_NOT_NULL(pSum);215  memset(pSum, 0, sizeof(*pSum));216  pSum->cnt = 3;217  pSum->approx = 1;218  pSum->ovrfl = 1; /* should be cleared by real inverse path */219  pSum->rSum = 0.0;220  pSum->rErr = 0.0;221 222  sqlite3_value *argv0 = makeRealValue(db, 2.5);223  sqlite3_value *argv[1] = { argv0 };224 225  test_sumInverse(&ctx, 1, argv);226 227  TEST_ASSERT_EQUAL_INT(2, pSum->cnt);228  TEST_ASSERT_EQUAL_INT(0, pSum->ovrfl);229  TEST_ASSERT_DOUBLE_WITHIN(0.0, -2.5, pSum->rSum);230  TEST_ASSERT_DOUBLE_WITHIN(0.0, 0.0, pSum->rErr);231 232  sqlite3ValueFree((Mem*)argv0);233  destroyContext(db, &ctx);234}235 236/* Test 6: NULL input should be ignored (no changes) */237void test_sumInverse_ignore_null(void){238  sqlite3 *db = NULL;239  sqlite3_context ctx;240  Mem *pMem = NULL;241  FuncDef funcDef;242  makeContext(&db, &ctx, &pMem, &funcDef);243 244  SumCtx *pSum = (SumCtx*)sqlite3_aggregate_context(&ctx, (int)sizeof(SumCtx));245  TEST_ASSERT_NOT_NULL(pSum);246  memset(pSum, 0, sizeof(*pSum));247  pSum->cnt = 5;248  pSum->approx = 0;249  pSum->iSum = 1234;250  pSum->ovrfl = 0;251 252  sqlite3_value *argv0 = makeNullValue(db);253  sqlite3_value *argv[1] = { argv0 };254 255  test_sumInverse(&ctx, 1, argv);256 257  /* No changes expected */258  TEST_ASSERT_EQUAL_INT(5, pSum->cnt);259  TEST_ASSERT_EQUAL_INT(0, pSum->approx);260  TEST_ASSERT_EQUAL_INT64(1234, pSum->iSum);261  TEST_ASSERT_EQUAL_INT(0, pSum->ovrfl);262 263  sqlite3ValueFree((Mem*)argv0);264  destroyContext(db, &ctx);265}266 267int main(void){268  UNITY_BEGIN();269  RUN_TEST(test_sumInverse_integer_simple);270  RUN_TEST(test_sumInverse_integer_overflow_to_approx);271  RUN_TEST(test_sumInverse_approx_with_integer);272  RUN_TEST(test_sumInverse_approx_with_smallest_int64);273  RUN_TEST(test_sumInverse_approx_with_real);274  RUN_TEST(test_sumInverse_ignore_null);275  return UNITY_END();276}