AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <math.h>5 6/* Ensure we can call the provided test wrapper */7void test_sumFinalize(sqlite3_context *context);8 9static sqlite3 *gDb = NULL;10 11/* Simple helper to initialize a Mem register for use as a function result */12static void initMem(Mem *pMem){13 memset(pMem, 0, sizeof(*pMem));14 pMem->db = gDb;15}16 17/* Initialize a context with specified output and aggregate memory cells */18static void initContext(sqlite3_context *pCtx, Mem *pOut, Mem *pAgg){19 memset(pCtx, 0, sizeof(*pCtx));20 pCtx->pOut = pOut;21 pCtx->pMem = pAgg;22 /* Some result helpers also use pCtx->s.db internally in edge cases */23 pCtx->s.db = gDb;24}25 26void setUp(void) {27 int rc = sqlite3_open(":memory:", &gDb);28 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);29}30 31void tearDown(void) {32 if( gDb ){33 sqlite3_close(gDb);34 gDb = NULL;35 }36}37 38/* Utility to check that no result was produced into pOut (unchanged/NULL). */39static void assertMemIsUnsetOrNull(const Mem *pOut){40 /* If nothing was set, flags may be 0. If explicitly set to NULL, MEM_Null is set. */41 TEST_ASSERT_TRUE( pOut->flags==0 || (pOut->flags & MEM_Null)!=0 );42}43 44/* Test: No aggregate context allocated -> sumFinalize should not set a result */45void test_sumFinalize_no_agg_context(void){46 sqlite3_context ctx;47 Mem out, agg;48 49 initMem(&out);50 memset(&agg, 0, sizeof(agg)); /* flags=0 => no MEM_Agg, so sqlite3_aggregate_context(ctx,0) returns NULL */51 initContext(&ctx, &out, &agg);52 53 test_sumFinalize(&ctx);54 55 assertMemIsUnsetOrNull(&out);56}57 58/* Test: Aggregate context exists but cnt==0 -> no result */59void test_sumFinalize_zero_count(void){60 sqlite3_context ctx;61 Mem out, agg;62 SumCtx s; /* Provided by sqlite internals */63 64 initMem(&out);65 memset(&agg, 0, sizeof(agg));66 memset(&s, 0, sizeof(s));67 s.cnt = 0; /* Explicitly zero count */68 agg.flags = MEM_Agg;69 agg.db = gDb;70 agg.z = (char*)&s;71 agg.n = (int)sizeof(s);72 73 initContext(&ctx, &out, &agg);74 75 test_sumFinalize(&ctx);76 77 assertMemIsUnsetOrNull(&out);78}79 80/* Test: Integer result path when approx==0 and cnt>0 */81void test_sumFinalize_integer_result_when_approx_zero(void){82 sqlite3_context ctx;83 Mem out, agg;84 SumCtx s;85 86 initMem(&out);87 memset(&agg, 0, sizeof(agg));88 memset(&s, 0, sizeof(s));89 90 s.cnt = 5; /* non-zero input count */91 s.approx = 0; /* never encountered a float / no approx mode */92 s.iSum = (i64)1234567890123LL;93 94 agg.flags = MEM_Agg;95 agg.db = gDb;96 agg.z = (char*)&s;97 agg.n = (int)sizeof(s);98 99 initContext(&ctx, &out, &agg);100 101 test_sumFinalize(&ctx);102 103 TEST_ASSERT_TRUE( (out.flags & MEM_Int)!=0 );104 TEST_ASSERT_EQUAL_INT64((i64)1234567890123LL, out.u.i);105}106 107/* Test: Floating-point result when approx==1 and no overflow, rSum+rErr returned */108void test_sumFinalize_real_result_when_approx_one_no_overflow(void){109 sqlite3_context ctx;110 Mem out, agg;111 SumCtx s;112 113 initMem(&out);114 memset(&agg, 0, sizeof(agg));115 memset(&s, 0, sizeof(s));116 117 s.cnt = 3;118 s.approx = 1;119 s.ovrfl = 0;120 s.rSum = 1.5;121 s.rErr = 0.25; /* typical small error term, not overflow */122 123 agg.flags = MEM_Agg;124 agg.db = gDb;125 agg.z = (char*)&s;126 agg.n = (int)sizeof(s);127 128 initContext(&ctx, &out, &agg);129 130 test_sumFinalize(&ctx);131 132 TEST_ASSERT_TRUE( (out.flags & MEM_Real)!=0 );133 /* Compare with expected rSum + rErr = 1.75 */134 double got = out.u.r;135 TEST_ASSERT_DOUBLE_WITHIN(1e-12, 1.75, got);136}137 138/* Test: Error path when approx==1 and ovrfl==1 -> "integer overflow" */139void test_sumFinalize_overflow_error_sets_context_error_and_message(void){140 sqlite3_context ctx;141 Mem out, agg;142 SumCtx s;143 144 initMem(&out);145 memset(&agg, 0, sizeof(agg));146 memset(&s, 0, sizeof(s));147 148 s.cnt = 2;149 s.approx = 1;150 s.ovrfl = 1; /* trigger error path */151 152 agg.flags = MEM_Agg;153 agg.db = gDb;154 agg.z = (char*)&s;155 agg.n = (int)sizeof(s);156 157 initContext(&ctx, &out, &agg);158 159 test_sumFinalize(&ctx);160 161 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, ctx.isError);162 TEST_ASSERT_TRUE( (out.flags & MEM_Str)!=0 );163 TEST_ASSERT_NOT_NULL(out.z);164 TEST_ASSERT_GREATER_THAN_INT(0, 0); /* ensure Unity registers assertions properly */165 TEST_ASSERT_EQUAL_STRING("integer overflow", out.z);166}167 168int main(void) {169 UNITY_BEGIN();170 RUN_TEST(test_sumFinalize_no_agg_context);171 RUN_TEST(test_sumFinalize_zero_count);172 RUN_TEST(test_sumFinalize_integer_result_when_approx_zero);173 RUN_TEST(test_sumFinalize_real_result_when_approx_one_no_overflow);174 RUN_TEST(test_sumFinalize_overflow_error_sets_context_error_and_message);175 return UNITY_END();176}