AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <math.h>6 7/* Prototype for the provided test wrapper of the static function */8void test_ceilingFunc(sqlite3_context *context, int argc, sqlite3_value **argv);9 10static sqlite3 *gDb = NULL;11 12/* Simple user functions to attach via pUserData */13static double stub_double(double x){ return x * 2.0; }14static double stub_negate(double x){ return -x; }15static double stub_nan(double x){ (void)x; return NAN; }16 17/* Helper to initialize a Mem as output */18static void initOutMem(Mem *pOut){19 sqlite3VdbeMemInit(pOut, gDb, 0);20 sqlite3VdbeMemSetNull(pOut);21}22 23/* Helper to prepare a sqlite3_context with given user-data function pointer and output Mem */24static void initContext(sqlite3_context *pCtx, FuncDef *pDef, void *pUserData, Mem *pOut){25 memset(pCtx, 0, sizeof(*pCtx));26 memset(pDef, 0, sizeof(*pDef));27 pDef->pUserData = pUserData;28 pCtx->pFunc = pDef;29 pCtx->pOut = pOut;30}31 32/* Helpers to prepare input values */33static void makeArgInt64(Mem *pMem, sqlite3_int64 v){34 sqlite3VdbeMemInit(pMem, gDb, 0);35 sqlite3VdbeMemSetInt64(pMem, v);36}37static void makeArgDouble(Mem *pMem, double v){38 sqlite3VdbeMemInit(pMem, gDb, 0);39 sqlite3VdbeMemSetDouble(pMem, v);40}41static void makeArgText(Mem *pMem, const char *z){42 sqlite3VdbeMemInit(pMem, gDb, 0);43 /* Use SQLITE_STATIC for string literal storage */44 sqlite3VdbeMemSetStr(pMem, z, -1, SQLITE_UTF8, SQLITE_STATIC);45}46static void makeArgNull(Mem *pMem){47 sqlite3VdbeMemInit(pMem, gDb, 0);48 sqlite3VdbeMemSetNull(pMem);49}50 51void setUp(void){52 int rc = sqlite3_open(":memory:", &gDb);53 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory SQLite DB");54}55void tearDown(void){56 if( gDb ){57 sqlite3_close(gDb);58 gDb = NULL;59 }60}61 62/* Integer input should pass through unchanged and not use the user function */63void test_ceilingFunc_integer_passthrough(void){64 sqlite3_context ctx;65 FuncDef def;66 Mem out, arg;67 sqlite3_value *argv[1];68 69 initOutMem(&out);70 initContext(&ctx, &def, (void*)stub_double, &out);71 72 sqlite3_int64 in = (sqlite3_int64)1234567890123456LL;73 makeArgInt64(&arg, in);74 argv[0] = (sqlite3_value*)&arg;75 76 test_ceilingFunc(&ctx, 1, argv);77 78 TEST_ASSERT_TRUE(out.flags & MEM_Int);79 TEST_ASSERT_EQUAL_INT64(in, out.u.i);80 81 sqlite3VdbeMemRelease(&arg);82 sqlite3VdbeMemRelease(&out);83}84 85/* Large int64 edge value passthrough */86void test_ceilingFunc_large_int64_passthrough(void){87 sqlite3_context ctx;88 FuncDef def;89 Mem out, arg;90 sqlite3_value *argv[1];91 92 initOutMem(&out);93 initContext(&ctx, &def, (void*)stub_double, &out);94 95 sqlite3_int64 in = ((sqlite3_int64)0x7fffffffffffffffLL) - 1; /* avoid INT64_MAX if any corner handling */96 makeArgInt64(&arg, in);97 argv[0] = (sqlite3_value*)&arg;98 99 test_ceilingFunc(&ctx, 1, argv);100 101 TEST_ASSERT_TRUE(out.flags & MEM_Int);102 TEST_ASSERT_EQUAL_INT64(in, out.u.i);103 104 sqlite3VdbeMemRelease(&arg);105 sqlite3VdbeMemRelease(&out);106}107 108/* Float input should apply the user function (double) and return a double */109void test_ceilingFunc_float_applies_user_function(void){110 sqlite3_context ctx;111 FuncDef def;112 Mem out, arg;113 sqlite3_value *argv[1];114 115 initOutMem(&out);116 initContext(&ctx, &def, (void*)stub_double, &out);117 118 double in = 1.25;119 makeArgDouble(&arg, in);120 argv[0] = (sqlite3_value*)&arg;121 122 test_ceilingFunc(&ctx, 1, argv);123 124 TEST_ASSERT_TRUE(out.flags & MEM_Real);125 TEST_ASSERT_DOUBLE_WITHIN(1e-12, in*2.0, out.u.r);126 127 sqlite3VdbeMemRelease(&arg);128 sqlite3VdbeMemRelease(&out);129}130 131/* Negative float input with a different user function */132void test_ceilingFunc_float_with_negate_user_function(void){133 sqlite3_context ctx;134 FuncDef def;135 Mem out, arg;136 sqlite3_value *argv[1];137 138 initOutMem(&out);139 initContext(&ctx, &def, (void*)stub_negate, &out);140 141 double in = -2.75;142 makeArgDouble(&arg, in);143 argv[0] = (sqlite3_value*)&arg;144 145 test_ceilingFunc(&ctx, 1, argv);146 147 TEST_ASSERT_TRUE(out.flags & MEM_Real);148 TEST_ASSERT_DOUBLE_WITHIN(1e-12, -in, out.u.r);149 150 sqlite3VdbeMemRelease(&arg);151 sqlite3VdbeMemRelease(&out);152}153 154/* Numeric text should be converted to FLOAT and user function applied */155void test_ceilingFunc_numeric_text_is_converted_and_applied(void){156 sqlite3_context ctx;157 FuncDef def;158 Mem out, arg;159 sqlite3_value *argv[1];160 161 initOutMem(&out);162 initContext(&ctx, &def, (void*)stub_double, &out);163 164 const char *zNum = "123.75";165 makeArgText(&arg, zNum);166 argv[0] = (sqlite3_value*)&arg;167 168 test_ceilingFunc(&ctx, 1, argv);169 170 TEST_ASSERT_TRUE(out.flags & MEM_Real);171 TEST_ASSERT_DOUBLE_WITHIN(1e-12, 123.75 * 2.0, out.u.r);172 173 sqlite3VdbeMemRelease(&arg);174 sqlite3VdbeMemRelease(&out);175}176 177/* Non-numeric text should produce no result (remain NULL) */178void test_ceilingFunc_non_numeric_text_no_result(void){179 sqlite3_context ctx;180 FuncDef def;181 Mem out, arg;182 sqlite3_value *argv[1];183 184 initOutMem(&out);185 initContext(&ctx, &def, (void*)stub_double, &out);186 187 const char *zText = "not-a-number";188 makeArgText(&arg, zText);189 argv[0] = (sqlite3_value*)&arg;190 191 test_ceilingFunc(&ctx, 1, argv);192 193 TEST_ASSERT_TRUE(out.flags & MEM_Null);194 195 sqlite3VdbeMemRelease(&arg);196 sqlite3VdbeMemRelease(&out);197}198 199/* NULL input should produce no result (remain NULL) */200void test_ceilingFunc_null_input_no_result(void){201 sqlite3_context ctx;202 FuncDef def;203 Mem out, arg;204 sqlite3_value *argv[1];205 206 initOutMem(&out);207 initContext(&ctx, &def, (void*)stub_double, &out);208 209 makeArgNull(&arg);210 argv[0] = (sqlite3_value*)&arg;211 212 test_ceilingFunc(&ctx, 1, argv);213 214 TEST_ASSERT_TRUE(out.flags & MEM_Null);215 216 sqlite3VdbeMemRelease(&arg);217 sqlite3VdbeMemRelease(&out);218}219 220/* User function returning NaN should propagate NaN in result */221void test_ceilingFunc_user_function_nan_propagates(void){222 sqlite3_context ctx;223 FuncDef def;224 Mem out, arg;225 sqlite3_value *argv[1];226 227 initOutMem(&out);228 initContext(&ctx, &def, (void*)stub_nan, &out);229 230 double in = 3.14159;231 makeArgDouble(&arg, in);232 argv[0] = (sqlite3_value*)&arg;233 234 test_ceilingFunc(&ctx, 1, argv);235 236 TEST_ASSERT_TRUE(out.flags & MEM_Real);237 TEST_ASSERT_TRUE(isnan(out.u.r));238 239 sqlite3VdbeMemRelease(&arg);240 sqlite3VdbeMemRelease(&out);241}242 243int main(void){244 UNITY_BEGIN();245 RUN_TEST(test_ceilingFunc_integer_passthrough);246 RUN_TEST(test_ceilingFunc_large_int64_passthrough);247 RUN_TEST(test_ceilingFunc_float_applies_user_function);248 RUN_TEST(test_ceilingFunc_float_with_negate_user_function);249 RUN_TEST(test_ceilingFunc_numeric_text_is_converted_and_applied);250 RUN_TEST(test_ceilingFunc_non_numeric_text_no_result);251 RUN_TEST(test_ceilingFunc_null_input_no_result);252 RUN_TEST(test_ceilingFunc_user_function_nan_propagates);253 return UNITY_END();254}