AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdio.h>7 8/* The target wrapper provided by the module under test */9void test_strftimeFunc(sqlite3_context *context, int argc, sqlite3_value **argv);10 11static sqlite3 *gDb = NULL;12 13/* SQLite SQL wrapper that forwards directly to the target function */14static void x_t_strftime(sqlite3_context *ctx, int argc, sqlite3_value **argv){15 test_strftimeFunc(ctx, argc, argv);16}17 18/* Helper: Execute a scalar SQL that returns a single column.19 Returns a malloc'ed copy of the text result (sqlite3_malloc),20 or NULL if the result is SQL NULL. Sets *pIsNull accordingly. */21static char* exec_scalar_text(const char *sql, int *pIsNull){22 sqlite3_stmt *stmt = NULL;23 int rc = sqlite3_prepare_v2(gDb, sql, -1, &stmt, 0);24 if( rc!=SQLITE_OK ){25 TEST_FAIL_MESSAGE("sqlite3_prepare_v2 failed");26 return NULL;27 }28 rc = sqlite3_step(stmt);29 if( rc!=SQLITE_ROW ){30 sqlite3_finalize(stmt);31 TEST_FAIL_MESSAGE("sqlite3_step did not return a row");32 return NULL;33 }34 int t = sqlite3_column_type(stmt, 0);35 char *ret = NULL;36 if( t==SQLITE_NULL ){37 if(pIsNull) *pIsNull = 1;38 }else{39 if(pIsNull) *pIsNull = 0;40 const unsigned char *z = sqlite3_column_text(stmt, 0);41 if( z ){42 ret = (char*)sqlite3_mprintf("%s", z);43 }else{44 ret = NULL;45 }46 }47 sqlite3_finalize(stmt);48 return ret;49}50 51static void assert_sql_result_eq(const char *sql, const char *expected){52 int isNull = 0;53 char *got = exec_scalar_text(sql, &isNull);54 if( expected==NULL ){55 TEST_ASSERT_TRUE_MESSAGE(isNull!=0, "Expected NULL but got non-NULL");56 if(got) sqlite3_free(got);57 return;58 }59 TEST_ASSERT_TRUE_MESSAGE(isNull==0, "Expected non-NULL but got NULL");60 TEST_ASSERT_NOT_NULL(got);61 TEST_ASSERT_EQUAL_STRING(expected, got);62 sqlite3_free(got);63}64 65void setUp(void) {66 int rc = sqlite3_open(":memory:", &gDb);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);68 rc = sqlite3_create_function_v2(69 gDb, "t_strftime", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC,70 NULL, x_t_strftime, NULL, NULL, NULL71 );72 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);73}74 75void tearDown(void) {76 if( gDb ){77 sqlite3_close(gDb);78 gDb = NULL;79 }80}81 82/* Zero-argument call should return NULL */83void test_strftimeFunc_zero_args_returns_null(void){84 assert_sql_result_eq("SELECT t_strftime()", NULL);85}86 87/* Invalid format specifier should result in NULL */88void test_strftimeFunc_invalid_format_returns_null(void){89 assert_sql_result_eq("SELECT t_strftime('%Q','2000-01-01')", NULL);90}91 92/* Invalid date/time string should return NULL */93void test_strftimeFunc_invalid_datetime_returns_null(void){94 assert_sql_result_eq("SELECT t_strftime('%Y','not-a-date')", NULL);95}96 97/* Basic date fields %Y %m %d and %F */98void test_strftimeFunc_basic_date_fields(void){99 assert_sql_result_eq("SELECT t_strftime('%Y','2000-03-02')", "2000");100 assert_sql_result_eq("SELECT t_strftime('%m','2000-03-02')", "03");101 assert_sql_result_eq("SELECT t_strftime('%d','2000-03-02')", "02");102 assert_sql_result_eq("SELECT t_strftime('%F','2000-03-02')", "2000-03-02");103}104 105/* Basic time fields %H %M %S and composed %R %T */106void test_strftimeFunc_basic_time_fields(void){107 assert_sql_result_eq("SELECT t_strftime('%H','2001-02-03 04:05:06')", "04");108 assert_sql_result_eq("SELECT t_strftime('%M','2001-02-03 04:05:06')", "05");109 assert_sql_result_eq("SELECT t_strftime('%S','2001-02-03 04:05:06')", "06");110 assert_sql_result_eq("SELECT t_strftime('%R','2001-02-03 04:05:06')", "04:05");111 assert_sql_result_eq("SELECT t_strftime('%T','2001-02-03 04:05:06')", "04:05:06");112}113 114/* 12-hour clock and AM/PM variants %I, %l, %p, %P; space padding %k and %e */115void test_strftimeFunc_12hr_and_padding(void){116 /* Midnight -> 12 AM */117 assert_sql_result_eq("SELECT t_strftime('%I','2001-02-03 00:05:06')", "12");118 assert_sql_result_eq("SELECT t_strftime('%l','2001-02-03 00:05:06')", "12");119 assert_sql_result_eq("SELECT t_strftime('%p','2001-02-03 00:05:06')", "AM");120 assert_sql_result_eq("SELECT t_strftime('%P','2001-02-03 00:05:06')", "am");121 122 /* Afternoon -> 1 PM */123 assert_sql_result_eq("SELECT t_strftime('%I','2001-02-03 13:00:00')", "01");124 assert_sql_result_eq("SELECT t_strftime('%l','2001-02-03 13:00:00')", " 1");125 assert_sql_result_eq("SELECT t_strftime('%p','2001-02-03 13:00:00')", "PM");126 assert_sql_result_eq("SELECT t_strftime('%P','2001-02-03 13:00:00')", "pm");127 128 /* Space padding for hour %k and day-of-month %e */129 assert_sql_result_eq("SELECT t_strftime('%k','2001-02-03 03:00:00')", " 3");130 assert_sql_result_eq("SELECT t_strftime('%e','2001-02-03')", " 3");131}132 133/* Day of year %j, checking leap year behavior */134void test_strftimeFunc_day_of_year(void){135 /* 2000-03-01 is leap year day 61 */136 assert_sql_result_eq("SELECT t_strftime('%j','2000-03-01')", "061");137 /* 1999-03-01 is non-leap year day 60 */138 assert_sql_result_eq("SELECT t_strftime('%j','1999-03-01')", "060");139}140 141/* Julian day number %J */142void test_strftimeFunc_julian_day_number(void){143 /* 2000-01-01 00:00:00 -> JD 2451544.5 */144 assert_sql_result_eq("SELECT t_strftime('%J','2000-01-01 00:00:00')", "2451544.5");145}146 147/* Unix epoch seconds %s, with and without subseconds; fractional seconds %f */148void test_strftimeFunc_epoch_and_fractional(void){149 /* Exact epoch */150 assert_sql_result_eq("SELECT t_strftime('%s','1970-01-01 00:00:00')", "0");151 152 /* 2000-01-01 00:00:00 -> 946684800 */153 assert_sql_result_eq("SELECT t_strftime('%s','2000-01-01 00:00:00')", "946684800");154 155 /* Fractional seconds formatting and epoch fraction */156 assert_sql_result_eq("SELECT t_strftime('%f','1970-01-01 00:00:00.250')", "00.250");157 assert_sql_result_eq("SELECT t_strftime('%s','1970-01-01 00:00:00.250')", "0.250");158}159 160/* Day of week %u and %w */161void test_strftimeFunc_day_of_week(void){162 /* 2000-01-01 is Saturday */163 assert_sql_result_eq("SELECT t_strftime('%w','2000-01-01')", "6");164 assert_sql_result_eq("SELECT t_strftime('%u','2000-01-01')", "6");165 166 /* 2000-01-02 is Sunday */167 assert_sql_result_eq("SELECT t_strftime('%w','2000-01-02')", "0");168 assert_sql_result_eq("SELECT t_strftime('%u','2000-01-02')", "7");169}170 171/* Week numbers %U and %W */172void test_strftimeFunc_week_numbers_U_W(void){173 /* 2016-01-01 Friday -> Before first Sunday/Monday, both 00 */174 assert_sql_result_eq("SELECT t_strftime('%U','2016-01-01')", "00");175 assert_sql_result_eq("SELECT t_strftime('%W','2016-01-01')", "00");176 177 /* 2017-01-01 Sunday -> First Sunday is week 01; first Monday also yields 01 */178 assert_sql_result_eq("SELECT t_strftime('%U','2017-01-01')", "01");179 assert_sql_result_eq("SELECT t_strftime('%W','2017-01-01')", "01");180}181 182/* ISO week number %V and ISO year %G/%g, including a year-boundary edge case */183void test_strftimeFunc_iso_week_and_year(void){184 /* 2017-01-01 (Sunday) is ISO week 52 of 2016 */185 assert_sql_result_eq("SELECT t_strftime('%V','2017-01-01')", "52");186 assert_sql_result_eq("SELECT t_strftime('%G','2017-01-01')", "2016");187 assert_sql_result_eq("SELECT t_strftime('%g','2017-01-01')", "16");188 189 /* 2015-01-01 (Thursday) is ISO week 01 of 2015 */190 assert_sql_result_eq("SELECT t_strftime('%V','2015-01-01')", "01");191 assert_sql_result_eq("SELECT t_strftime('%G','2015-01-01')", "2015");192 assert_sql_result_eq("SELECT t_strftime('%g','2015-01-01')", "15");193}194 195/* Literal percent %% and mixed literal text */196void test_strftimeFunc_literal_percent_and_text(void){197 assert_sql_result_eq("SELECT t_strftime('%%','2000-01-01')", "%");198 assert_sql_result_eq("SELECT t_strftime('Date=%F Time=%T','2001-02-03 04:05:06')",199 "Date=2001-02-03 Time=04:05:06");200}201 202/* Combined expansion and pass-through characters */203void test_strftimeFunc_mixed_format(void){204 assert_sql_result_eq("SELECT t_strftime('Y:%Y m:%m d:%d j:%j','1999-12-31')",205 "Y:1999 m:12 d:31 j:365");206}207 208int main(void){209 UNITY_BEGIN();210 RUN_TEST(test_strftimeFunc_zero_args_returns_null);211 RUN_TEST(test_strftimeFunc_invalid_format_returns_null);212 RUN_TEST(test_strftimeFunc_invalid_datetime_returns_null);213 RUN_TEST(test_strftimeFunc_basic_date_fields);214 RUN_TEST(test_strftimeFunc_basic_time_fields);215 RUN_TEST(test_strftimeFunc_12hr_and_padding);216 RUN_TEST(test_strftimeFunc_day_of_year);217 RUN_TEST(test_strftimeFunc_julian_day_number);218 RUN_TEST(test_strftimeFunc_epoch_and_fractional);219 RUN_TEST(test_strftimeFunc_day_of_week);220 RUN_TEST(test_strftimeFunc_week_numbers_U_W);221 RUN_TEST(test_strftimeFunc_iso_week_and_year);222 RUN_TEST(test_strftimeFunc_literal_percent_and_text);223 RUN_TEST(test_strftimeFunc_mixed_format);224 return UNITY_END();225}