Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_func_sumStep.c321 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <limits.h>6#include <math.h>7 8/* The wrapper provided for calling the static function under test */9extern void test_sumStep(sqlite3_context *context, int argc, sqlite3_value **argv);10 11/* Helper to initialize a sqlite3_context for aggregate usage */12static void initAggContext(sqlite3 *db, sqlite3_context *pCtx, Mem *pAggMem){13  memset(pCtx, 0, sizeof(*pCtx));14  memset(pAggMem, 0, sizeof(*pAggMem));15  sqlite3VdbeMemInit(pAggMem, db, 0);16  pCtx->db = db;17  pCtx->pMem = pAggMem;18}19 20/* Helpers to create sqlite3_value instances */21static sqlite3_value *makeIntValue(sqlite3 *db, i64 v){22  sqlite3_value *p = sqlite3ValueNew(db);23  TEST_ASSERT_NOT_NULL(p);24  sqlite3VdbeMemSetInt64((Mem*)p, v);25  return p;26}27static sqlite3_value *makeDoubleValue(sqlite3 *db, double v){28  sqlite3_value *p = sqlite3ValueNew(db);29  TEST_ASSERT_NOT_NULL(p);30  sqlite3VdbeMemSetDouble((Mem*)p, v);31  return p;32}33static sqlite3_value *makeNullValue(sqlite3 *db){34  sqlite3_value *p = sqlite3ValueNew(db);35  TEST_ASSERT_NOT_NULL(p);36  sqlite3VdbeMemSetNull((Mem*)p);37  return p;38}39 40/* Helper to get SumCtx from aggregate context */41static SumCtx *getSumCtx(sqlite3_context *pCtx){42  void *p = sqlite3_aggregate_context(pCtx, (int)sizeof(SumCtx));43  return (SumCtx*)p;44}45 46static double kbn_total(const SumCtx *p){47  return p->rSum + p->rErr;48}49 50void setUp(void) {51  /* No-op */52}53void tearDown(void) {54  /* No-op */55}56 57/* Test: NULL input should not change counters/flags */58void test_sumStep_null_input_does_not_increment(void){59  sqlite3 *db = 0;60  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));61  sqlite3_context ctx;62  Mem agg;63  initAggContext(db, &ctx, &agg);64 65  sqlite3_value *v = makeNullValue(db);66  sqlite3_value *argv[1] = { v };67  test_sumStep(&ctx, 1, argv);68 69  SumCtx *p = getSumCtx(&ctx);70  TEST_ASSERT_NOT_NULL(p);71  TEST_ASSERT_EQUAL_INT64(0, p->cnt);72  TEST_ASSERT_EQUAL_INT(0, p->approx);73  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);74  TEST_ASSERT_EQUAL_INT64(0, p->iSum);75  TEST_ASSERT_DOUBLE_WITHIN(0.0, 0.0, p->rSum);76  TEST_ASSERT_DOUBLE_WITHIN(0.0, 0.0, p->rErr);77 78  sqlite3ValueFree((Mem*)v);79  sqlite3VdbeMemSetNull(&agg);80  sqlite3_close(db);81}82 83/* Test: Single integer accumulates in iSum with approx==0 */84void test_sumStep_single_integer(void){85  sqlite3 *db = 0;86  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));87  sqlite3_context ctx;88  Mem agg;89  initAggContext(db, &ctx, &agg);90 91  sqlite3_value *v = makeIntValue(db, 5);92  sqlite3_value *argv[1] = { v };93  test_sumStep(&ctx, 1, argv);94 95  SumCtx *p = getSumCtx(&ctx);96  TEST_ASSERT_NOT_NULL(p);97  TEST_ASSERT_EQUAL_INT64(1, p->cnt);98  TEST_ASSERT_EQUAL_INT(0, p->approx);99  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);100  TEST_ASSERT_EQUAL_INT64(5, p->iSum);101 102  sqlite3ValueFree((Mem*)v);103  sqlite3VdbeMemSetNull(&agg);104  sqlite3_close(db);105}106 107/* Test: Two integers sum with no overflow keeps approx==0 */108void test_sumStep_two_integers_no_overflow(void){109  sqlite3 *db = 0;110  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));111  sqlite3_context ctx;112  Mem agg;113  initAggContext(db, &ctx, &agg);114 115  sqlite3_value *v1 = makeIntValue(db, 7);116  sqlite3_value *argv[1] = { v1 };117  test_sumStep(&ctx, 1, argv);118  sqlite3ValueFree((Mem*)v1);119 120  sqlite3_value *v2 = makeIntValue(db, 8);121  argv[0] = v2;122  test_sumStep(&ctx, 1, argv);123  sqlite3ValueFree((Mem*)v2);124 125  SumCtx *p = getSumCtx(&ctx);126  TEST_ASSERT_NOT_NULL(p);127  TEST_ASSERT_EQUAL_INT64(2, p->cnt);128  TEST_ASSERT_EQUAL_INT(0, p->approx);129  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);130  TEST_ASSERT_EQUAL_INT64(15, p->iSum);131 132  sqlite3VdbeMemSetNull(&agg);133  sqlite3_close(db);134}135 136/* Test: Integer overflow triggers approx==1 and ovrfl==1 */137void test_sumStep_integer_overflow_sets_approx_and_ovrfl(void){138  sqlite3 *db = 0;139  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));140  sqlite3_context ctx;141  Mem agg;142  initAggContext(db, &ctx, &agg);143 144  sqlite3_value *v1 = makeIntValue(db, LLONG_MAX);145  sqlite3_value *argv[1] = { v1 };146  test_sumStep(&ctx, 1, argv);147  sqlite3ValueFree((Mem*)v1);148 149  sqlite3_value *v2 = makeIntValue(db, 1);150  argv[0] = v2;151  test_sumStep(&ctx, 1, argv);152  sqlite3ValueFree((Mem*)v2);153 154  SumCtx *p = getSumCtx(&ctx);155  TEST_ASSERT_NOT_NULL(p);156  TEST_ASSERT_EQUAL_INT64(2, p->cnt);157  TEST_ASSERT_EQUAL_INT(1, p->approx);158  TEST_ASSERT_EQUAL_INT(1, p->ovrfl);159  /* iSum remains the pre-overflow integer sum (LLONG_MAX) */160  TEST_ASSERT_EQUAL_INT64(LLONG_MAX, p->iSum);161  /* The KBN running total should be large; we check it's > 9e18 */162  TEST_ASSERT_TRUE(kbn_total(p) > 9e18);163 164  sqlite3VdbeMemSetNull(&agg);165  sqlite3_close(db);166}167 168/* Test: While approx==1, integer steps preserve ovrfl and real step clears it */169void test_sumStep_ovrfl_persists_with_integers_and_clears_on_real(void){170  sqlite3 *db = 0;171  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));172  sqlite3_context ctx;173  Mem agg;174  initAggContext(db, &ctx, &agg);175 176  /* Cause overflow to set approx=1 and ovrfl=1 */177  sqlite3_value *v1 = makeIntValue(db, LLONG_MAX);178  sqlite3_value *argv[1] = { v1 };179  test_sumStep(&ctx, 1, argv);180  sqlite3ValueFree((Mem*)v1);181 182  sqlite3_value *v2 = makeIntValue(db, 1);183  argv[0] = v2;184  test_sumStep(&ctx, 1, argv);185  sqlite3ValueFree((Mem*)v2);186 187  SumCtx *p = getSumCtx(&ctx);188  TEST_ASSERT_NOT_NULL(p);189  TEST_ASSERT_EQUAL_INT(1, p->approx);190  TEST_ASSERT_EQUAL_INT(1, p->ovrfl);191 192  /* Add another integer: ovrfl should remain 1 */193  sqlite3_value *v3 = makeIntValue(db, 5);194  argv[0] = v3;195  test_sumStep(&ctx, 1, argv);196  sqlite3ValueFree((Mem*)v3);197 198  p = getSumCtx(&ctx);199  TEST_ASSERT_EQUAL_INT(1, p->ovrfl);200 201  /* Add a real: ovrfl should reset to 0 */202  sqlite3_value *v4 = makeDoubleValue(db, 0.0);203  argv[0] = v4;204  test_sumStep(&ctx, 1, argv);205  sqlite3ValueFree((Mem*)v4);206 207  p = getSumCtx(&ctx);208  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);209  TEST_ASSERT_EQUAL_INT(1, p->approx);210 211  sqlite3VdbeMemSetNull(&agg);212  sqlite3_close(db);213}214 215/* Test: Kahan–Babuška–Neumaier precision: 1e16 + 1 - 1e16 ~= 1 */216void test_sumStep_real_cancellation_kahan_precision(void){217  sqlite3 *db = 0;218  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));219  sqlite3_context ctx;220  Mem agg;221  initAggContext(db, &ctx, &agg);222 223  sqlite3_value *a = makeDoubleValue(db, 1e16);224  sqlite3_value *argv[1] = { a };225  test_sumStep(&ctx, 1, argv);226  sqlite3ValueFree((Mem*)a);227 228  sqlite3_value *b = makeDoubleValue(db, 1.0);229  argv[0] = b;230  test_sumStep(&ctx, 1, argv);231  sqlite3ValueFree((Mem*)b);232 233  sqlite3_value *c = makeDoubleValue(db, -1e16);234  argv[0] = c;235  test_sumStep(&ctx, 1, argv);236  sqlite3ValueFree((Mem*)c);237 238  SumCtx *p = getSumCtx(&ctx);239  TEST_ASSERT_NOT_NULL(p);240  TEST_ASSERT_EQUAL_INT(1, p->approx);241  TEST_ASSERT_DOUBLE_WITHIN(1e-9, 1.0, kbn_total(p));242 243  sqlite3VdbeMemSetNull(&agg);244  sqlite3_close(db);245}246 247/* Test: Integers first then real initializes KBN from integer sum */248void test_sumStep_integer_then_real_initializes_kbn_from_iSum(void){249  sqlite3 *db = 0;250  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));251  sqlite3_context ctx;252  Mem agg;253  initAggContext(db, &ctx, &agg);254 255  sqlite3_value *i1 = makeIntValue(db, 2);256  sqlite3_value *argv[1] = { i1 };257  test_sumStep(&ctx, 1, argv);258  sqlite3ValueFree((Mem*)i1);259 260  sqlite3_value *i2 = makeIntValue(db, 3);261  argv[0] = i2;262  test_sumStep(&ctx, 1, argv);263  sqlite3ValueFree((Mem*)i2);264 265  /* Now add a real 0.5, should switch to approx and initialize from iSum=5 */266  sqlite3_value *r = makeDoubleValue(db, 0.5);267  argv[0] = r;268  test_sumStep(&ctx, 1, argv);269  sqlite3ValueFree((Mem*)r);270 271  SumCtx *p = getSumCtx(&ctx);272  TEST_ASSERT_NOT_NULL(p);273  TEST_ASSERT_EQUAL_INT(1, p->approx);274  TEST_ASSERT_EQUAL_INT64(3, p->cnt); /* NULLs are not added here */275  TEST_ASSERT_DOUBLE_WITHIN(1e-12, 5.5, kbn_total(p));276  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);277 278  sqlite3VdbeMemSetNull(&agg);279  sqlite3_close(db);280}281 282/* Test: Real first then integer accumulates via KBN */283void test_sumStep_real_then_integer_accumulates_with_kbn(void){284  sqlite3 *db = 0;285  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));286  sqlite3_context ctx;287  Mem agg;288  initAggContext(db, &ctx, &agg);289 290  sqlite3_value *r = makeDoubleValue(db, 2.25);291  sqlite3_value *argv[1] = { r };292  test_sumStep(&ctx, 1, argv);293  sqlite3ValueFree((Mem*)r);294 295  sqlite3_value *i = makeIntValue(db, 2);296  argv[0] = i;297  test_sumStep(&ctx, 1, argv);298  sqlite3ValueFree((Mem*)i);299 300  SumCtx *p = getSumCtx(&ctx);301  TEST_ASSERT_NOT_NULL(p);302  TEST_ASSERT_EQUAL_INT(1, p->approx);303  TEST_ASSERT_DOUBLE_WITHIN(1e-12, 4.25, kbn_total(p));304  TEST_ASSERT_EQUAL_INT(0, p->ovrfl);305 306  sqlite3VdbeMemSetNull(&agg);307  sqlite3_close(db);308}309 310int main(void){311  UNITY_BEGIN();312  RUN_TEST(test_sumStep_null_input_does_not_increment);313  RUN_TEST(test_sumStep_single_integer);314  RUN_TEST(test_sumStep_two_integers_no_overflow);315  RUN_TEST(test_sumStep_integer_overflow_sets_approx_and_ovrfl);316  RUN_TEST(test_sumStep_ovrfl_persists_with_integers_and_clears_on_real);317  RUN_TEST(test_sumStep_real_cancellation_kahan_precision);318  RUN_TEST(test_sumStep_integer_then_real_initializes_kbn_from_iSum);319  RUN_TEST(test_sumStep_real_then_integer_accumulates_with_kbn);320  return UNITY_END();321}