AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* External wrapper for the static function under test (provided in module) */8extern void test_dateFunc(sqlite3_context *context, int argc, sqlite3_value **argv);9 10static sqlite3 *gDb = NULL;11 12/* Helper to run dateFunc and return a heap-allocated C-string with the result, or NULL on error/no result */13static char* run_date(sqlite3_value **argv, int argc){14 sqlite3_context ctx;15 Mem out;16 memset(&ctx, 0, sizeof(ctx));17 memset(&out, 0, sizeof(out));18 19 sqlite3VdbeMemInit(&out, gDb, 0);20 sqlite3VdbeMemSetNull(&out);21 22 ctx.pOut = &out;23 ctx.pVdbe = NULL; /* Not needed for our usage */24 ctx.pFunc = NULL;25 ctx.isError = 0;26 ctx.pMem = NULL;27 28 test_dateFunc(&ctx, argc, argv);29 30 char *res = NULL;31 if( (out.flags & MEM_Str)!=0 && out.z!=NULL ){32 res = sqlite3_mprintf("%s", out.z);33 }34 sqlite3VdbeMemRelease(&out);35 return res;36}37 38/* Helpers to initialize sqlite3_value (Mem) arguments */39static void init_str_value(Mem *m, const char *z){40 sqlite3VdbeMemInit(m, gDb, 0);41 /* Keep source string static; SQLite won't free it */42 sqlite3VdbeMemSetStr(m, z, -1, SQLITE_UTF8, SQLITE_STATIC);43}44 45static void init_double_value(Mem *m, double r){46 sqlite3VdbeMemInit(m, gDb, 0);47 sqlite3VdbeMemSetDouble(m, r);48}49 50void setUp(void) {51 int rc = sqlite3_open(":memory:", &gDb);52 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory SQLite database");53}54 55void tearDown(void) {56 if( gDb ){57 int rc = sqlite3_close(gDb);58 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to close SQLite database");59 gDb = NULL;60 }61}62 63/* Basic YYYY-MM-DD */64void test_dateFunc_basic_date(void){65 Mem a0; init_str_value(&a0, "2023-02-05");66 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };67 68 char *res = run_date(argv, 1);69 TEST_ASSERT_NOT_NULL(res);70 TEST_ASSERT_EQUAL_STRING("2023-02-05", res);71 72 sqlite3_free(res);73 sqlite3VdbeMemRelease(&a0);74}75 76/* Date-time input: time component should be ignored */77void test_dateFunc_datetime_input(void){78 Mem a0; init_str_value(&a0, "2001-02-03 04:05:06");79 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };80 81 char *res = run_date(argv, 1);82 TEST_ASSERT_NOT_NULL(res);83 TEST_ASSERT_EQUAL_STRING("2001-02-03", res);84 85 sqlite3_free(res);86 sqlite3VdbeMemRelease(&a0);87}88 89/* Modifiers: +1 day from 2000-01-31 -> 2000-02-01 */90void test_dateFunc_modifier_plus_one_day(void){91 Mem a0, a1;92 init_str_value(&a0, "2000-01-31");93 init_str_value(&a1, "+1 day");94 sqlite3_value *argv[2] = { (sqlite3_value*)&a0, (sqlite3_value*)&a1 };95 96 char *res = run_date(argv, 2);97 TEST_ASSERT_NOT_NULL(res);98 TEST_ASSERT_EQUAL_STRING("2000-02-01", res);99 100 sqlite3_free(res);101 sqlite3VdbeMemRelease(&a0);102 sqlite3VdbeMemRelease(&a1);103}104 105/* Normalization of invalid day-of-month when argc==1 (e.g., 2023-02-31 -> 2023-03-03) */106void test_dateFunc_normalization_overflow_day(void){107 Mem a0; init_str_value(&a0, "2023-02-31");108 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };109 110 char *res = run_date(argv, 1);111 TEST_ASSERT_NOT_NULL(res);112 TEST_ASSERT_EQUAL_STRING("2023-03-03", res);113 114 sqlite3_free(res);115 sqlite3VdbeMemRelease(&a0);116}117 118/* Leap year and non-leap year behavior */119void test_dateFunc_leap_and_nonleap(void){120 /* 2000 is a leap year */121 Mem a0; init_str_value(&a0, "2000-02-29");122 sqlite3_value *argv0[1] = { (sqlite3_value*)&a0 };123 char *res0 = run_date(argv0, 1);124 TEST_ASSERT_NOT_NULL(res0);125 TEST_ASSERT_EQUAL_STRING("2000-02-29", res0);126 sqlite3_free(res0);127 sqlite3VdbeMemRelease(&a0);128 129 /* 1900 is not a leap year in the Gregorian calendar */130 Mem a1; init_str_value(&a1, "1900-02-29");131 sqlite3_value *argv1[1] = { (sqlite3_value*)&a1 };132 char *res1 = run_date(argv1, 1);133 TEST_ASSERT_NOT_NULL(res1);134 TEST_ASSERT_EQUAL_STRING("1900-03-01", res1);135 sqlite3_free(res1);136 sqlite3VdbeMemRelease(&a1);137}138 139/* Negative year formatting */140void test_dateFunc_negative_year(void){141 Mem a0; init_str_value(&a0, "-0044-03-15");142 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };143 144 char *res = run_date(argv, 1);145 TEST_ASSERT_NOT_NULL(res);146 TEST_ASSERT_EQUAL_STRING("-0044-03-15", res);147 148 sqlite3_free(res);149 sqlite3VdbeMemRelease(&a0);150}151 152/* Year zero handling */153void test_dateFunc_year_zero(void){154 Mem a0; init_str_value(&a0, "0000-01-01");155 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };156 157 char *res = run_date(argv, 1);158 TEST_ASSERT_NOT_NULL(res);159 TEST_ASSERT_EQUAL_STRING("0000-01-01", res);160 161 sqlite3_free(res);162 sqlite3VdbeMemRelease(&a0);163}164 165/* Invalid input should yield no result */166void test_dateFunc_invalid_input(void){167 Mem a0; init_str_value(&a0, "not-a-date");168 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };169 170 char *res = run_date(argv, 1);171 TEST_ASSERT_NULL(res);172 173 /* Nothing to free for res == NULL */174 sqlite3VdbeMemRelease(&a0);175}176 177/* Numeric Julian day input (1970-01-01 is JD 2440587.5) */178void test_dateFunc_numeric_julian_day(void){179 Mem a0; init_double_value(&a0, 2440587.5);180 sqlite3_value *argv[1] = { (sqlite3_value*)&a0 };181 182 char *res = run_date(argv, 1);183 TEST_ASSERT_NOT_NULL(res);184 TEST_ASSERT_EQUAL_STRING("1970-01-01", res);185 186 sqlite3_free(res);187 sqlite3VdbeMemRelease(&a0);188}189 190int main(void) {191 UNITY_BEGIN();192 RUN_TEST(test_dateFunc_basic_date);193 RUN_TEST(test_dateFunc_datetime_input);194 RUN_TEST(test_dateFunc_modifier_plus_one_day);195 RUN_TEST(test_dateFunc_normalization_overflow_day);196 RUN_TEST(test_dateFunc_leap_and_nonleap);197 RUN_TEST(test_dateFunc_negative_year);198 RUN_TEST(test_dateFunc_year_zero);199 RUN_TEST(test_dateFunc_invalid_input);200 RUN_TEST(test_dateFunc_numeric_julian_day);201 return UNITY_END();202}