AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <string.h>6#include <stdlib.h>7 8/* Prototype for the auto-generated test wrapper provided in the module */9extern void test_datedebugFunc(sqlite3_context *context, int argc, sqlite3_value **argv);10 11static sqlite3 *gDb = NULL;12 13/* Helper: register the wrapper as a SQL function we can call from SQL */14static int register_x_datedebug(sqlite3 *db){15 /* Allow variable number of args (0 or more), do not mark deterministic to allow "now" */16 return sqlite3_create_function_v2(17 db, "x_datedebug", -1, SQLITE_UTF8, NULL,18 test_datedebugFunc, NULL, NULL, NULL19 );20}21 22/* Helper: run a scalar SQL that returns a single column value in first row.23 On success: returns SQLITE_OK. If the column is NULL, *pIsNull=1 and *pzOut=NULL.24 If text, *pIsNull=0 and *pzOut holds a copy (allocated with sqlite3_malloc64) to be freed with sqlite3_free(). */25static int get_text_result(sqlite3 *db, const char *zSql, char **pzOut, int *pIsNull){26 sqlite3_stmt *pStmt = NULL;27 int rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, NULL);28 if( rc!=SQLITE_OK ){29 if( pStmt ) sqlite3_finalize(pStmt);30 return rc;31 }32 rc = sqlite3_step(pStmt);33 if( rc==SQLITE_ROW ){34 int t = sqlite3_column_type(pStmt, 0);35 if( t==SQLITE_NULL ){36 *pIsNull = 1;37 *pzOut = NULL;38 rc = SQLITE_OK;39 }else{40 const unsigned char *z = sqlite3_column_text(pStmt, 0);41 if( z ){42 /* Duplicate using SQLite allocator for convenience */43 *pzOut = (char*)sqlite3_malloc64(sqlite3_column_bytes(pStmt,0)+1);44 if( *pzOut==NULL ){45 sqlite3_finalize(pStmt);46 return SQLITE_NOMEM;47 }48 memcpy(*pzOut, z, sqlite3_column_bytes(pStmt,0)+1);49 *pIsNull = 0;50 rc = SQLITE_OK;51 }else{52 *pIsNull = 1;53 *pzOut = NULL;54 rc = SQLITE_OK;55 }56 }57 }else if( rc==SQLITE_DONE ){58 /* No rows */59 *pIsNull = 1;60 *pzOut = NULL;61 rc = SQLITE_OK;62 }else{63 /* Error */64 }65 sqlite3_finalize(pStmt);66 return rc;67}68 69static int str_contains(const char *haystack, const char *needle){70 return (haystack && needle && strstr(haystack, needle)!=NULL);71}72 73/* Unity fixtures */74void setUp(void) {75 int rc = sqlite3_open(":memory:", &gDb);76 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");77 rc = register_x_datedebug(gDb);78 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "register_x_datedebug failed");79}80 81void tearDown(void) {82 if( gDb ){83 sqlite3_close(gDb);84 gDb = NULL;85 }86}87 88/* Tests */89 90void test_datedebug_now_validJD(void){91 char *z = NULL;92 int isNull = 0;93 int rc = get_text_result(gDb, "SELECT x_datedebug()", &z, &isNull);94 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95 TEST_ASSERT_FALSE_MESSAGE(isNull, "Expected non-NULL JSON for x_datedebug()");96 TEST_ASSERT_NOT_NULL(z);97 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "validJD:1"), "Expected validJD:1 in JSON");98 sqlite3_free(z);99}100 101void test_datedebug_basic_iso_datetime(void){102 char *z = NULL;103 int isNull = 0;104 int rc = get_text_result(gDb,105 "SELECT x_datedebug('2000-01-01 00:00:00')", &z, &isNull);106 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);107 TEST_ASSERT_FALSE(isNull);108 TEST_ASSERT_NOT_NULL(z);109 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "Y:2000"), "Missing Y:2000");110 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "M:1"), "Missing M:1");111 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "D:1"), "Missing D:1");112 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "h:0"), "Missing h:0");113 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "m:0"), "Missing m:0");114 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "s:0.000"), "Missing s:0.000");115 sqlite3_free(z);116}117 118void test_datedebug_fractional_seconds_and_useSubsec(void){119 char *z = NULL;120 int isNull = 0;121 int rc = get_text_result(gDb,122 "SELECT x_datedebug('2021-02-03 04:05:06.789')", &z, &isNull);123 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);124 TEST_ASSERT_FALSE(isNull);125 TEST_ASSERT_NOT_NULL(z);126 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "s:6.789"), "Missing s:6.789");127 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "useSubsec:1"), "Expected useSubsec:1");128 sqlite3_free(z);129}130 131void test_datedebug_utc_modifier_sets_isUtc(void){132 char *z = NULL;133 int isNull = 0;134 int rc = get_text_result(gDb,135 "SELECT x_datedebug('2020-01-01 12:00:00','utc')", &z, &isNull);136 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);137 TEST_ASSERT_FALSE(isNull);138 TEST_ASSERT_NOT_NULL(z);139 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "isUtc:1"), "Expected isUtc:1");140 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "isLocal:0"), "Expected isLocal:0");141 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "tz:0"), "Expected tz:0 in UTC");142 sqlite3_free(z);143}144 145void test_datedebug_invalid_input_returns_null(void){146 char *z = NULL;147 int isNull = 0;148 int rc = get_text_result(gDb, "SELECT x_datedebug('not-a-date')", &z, &isNull);149 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);150 TEST_ASSERT_TRUE_MESSAGE(isNull, "Expected NULL result for invalid date");151 TEST_ASSERT_NULL(z);152}153 154void test_datedebug_numeric_julian_input(void){155 char *z = NULL;156 int isNull = 0;157 int rc = get_text_result(gDb, "SELECT x_datedebug(2451544.5)", &z, &isNull);158 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);159 TEST_ASSERT_FALSE(isNull);160 TEST_ASSERT_NOT_NULL(z);161 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "validJD:1"), "Expected validJD:1");162 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "validYMS:0"), "Expected validYMS:0 for raw JD input");163 sqlite3_free(z);164}165 166void test_datedebug_normalization_trigger_for_overflow_day(void){167 char *z = NULL;168 int isNull = 0;169 int rc = get_text_result(gDb, "SELECT x_datedebug('2023-02-31')", &z, &isNull);170 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);171 TEST_ASSERT_FALSE(isNull);172 TEST_ASSERT_NOT_NULL(z);173 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "validJD:1"), "Expected validJD:1");174 TEST_ASSERT_TRUE_MESSAGE(str_contains(z, "validYMS:0"), "Expected validYMS:0 due to normalization trigger");175 sqlite3_free(z);176}177 178int main(void) {179 UNITY_BEGIN();180 RUN_TEST(test_datedebug_now_validJD);181 RUN_TEST(test_datedebug_basic_iso_datetime);182 RUN_TEST(test_datedebug_fractional_seconds_and_useSubsec);183 RUN_TEST(test_datedebug_utc_modifier_sets_isUtc);184 RUN_TEST(test_datedebug_invalid_input_returns_null);185 RUN_TEST(test_datedebug_numeric_julian_input);186 RUN_TEST(test_datedebug_normalization_trigger_for_overflow_day);187 return UNITY_END();188}