AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6#include <ctype.h>7 8extern void test_currentTimeFunc(sqlite3_context *context, int argc, sqlite3_value **argv);9 10static sqlite3 *gDb = NULL;11 12/* Helper: register a SQL function using test_currentTimeFunc with a given format string as pApp */13static void register_time_func(const char *zName, const char *zFormat){14 int rc = sqlite3_create_function_v2(15 gDb, zName, 0, SQLITE_UTF8, (void*)zFormat,16 test_currentTimeFunc, NULL, NULL, NULL17 );18 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_create_function_v2 failed");19}20 21/* Helper: prepare, step once, fetch single text column into buf and return length */22static int exec_select_single_text(const char *zSql, char *buf, int buflen){23 sqlite3_stmt *pStmt = NULL;24 int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, NULL);25 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");26 27 rc = sqlite3_step(pStmt);28 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "expected one row");29 30 const unsigned char *pTxt = sqlite3_column_text(pStmt, 0);31 int n = sqlite3_column_bytes(pStmt, 0);32 TEST_ASSERT_NOT_NULL_MESSAGE(pTxt, "result text is NULL");33 TEST_ASSERT_TRUE_MESSAGE(n < buflen, "buffer too small for result");34 35 memcpy(buf, pTxt, n);36 buf[n] = '\0';37 38 rc = sqlite3_step(pStmt);39 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_DONE, rc, "expected only one row");40 41 rc = sqlite3_finalize(pStmt);42 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed");43 return n;44}45 46/* Helper: prepare, step once, fetch two text columns, ensure both non-null and return lengths via out params */47static void exec_select_two_text(const char *zSql, char *buf1, int buflen1, int *len1,48 char *buf2, int buflen2, int *len2){49 sqlite3_stmt *pStmt = NULL;50 int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, NULL);51 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");52 53 rc = sqlite3_step(pStmt);54 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "expected one row");55 56 const unsigned char *pTxt1 = sqlite3_column_text(pStmt, 0);57 int n1 = sqlite3_column_bytes(pStmt, 0);58 const unsigned char *pTxt2 = sqlite3_column_text(pStmt, 1);59 int n2 = sqlite3_column_bytes(pStmt, 1);60 61 TEST_ASSERT_NOT_NULL_MESSAGE(pTxt1, "col0 text is NULL");62 TEST_ASSERT_NOT_NULL_MESSAGE(pTxt2, "col1 text is NULL");63 TEST_ASSERT_TRUE_MESSAGE(n1 < buflen1, "buffer1 too small");64 TEST_ASSERT_TRUE_MESSAGE(n2 < buflen2, "buffer2 too small");65 66 memcpy(buf1, pTxt1, n1); buf1[n1] = '\0';67 memcpy(buf2, pTxt2, n2); buf2[n2] = '\0';68 if (len1) *len1 = n1;69 if (len2) *len2 = n2;70 71 rc = sqlite3_step(pStmt);72 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_DONE, rc, "expected only one row");73 74 rc = sqlite3_finalize(pStmt);75 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed");76}77 78/* Unity setup/teardown */79void setUp(void) {80 int rc = sqlite3_open(":memory:", &gDb);81 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");82}83void tearDown(void) {84 if( gDb ){85 int rc = sqlite3_close(gDb);86 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_close failed");87 gDb = NULL;88 }89}90 91/* Utility checks */92static int is_all_digits(const char *s, int n){93 for(int i=0; i<n; i++){94 if( !isdigit((unsigned char)s[i]) ) return 0;95 }96 return 1;97}98 99/* Tests */100 101void test_currentTimeFunc_timestamp_basic(void){102 static const char *fmt = "%Y-%m-%d %H:%M:%S"; /* 19 chars */103 register_time_func("FTS", fmt);104 105 char out[32];106 int n = exec_select_single_text("SELECT FTS()", out, sizeof(out));107 TEST_ASSERT_EQUAL_INT(19, n);108 109 /* Pattern: YYYY-MM-DD HH:MM:SS */110 TEST_ASSERT_TRUE(is_all_digits(out+0, 4));111 TEST_ASSERT_EQUAL_CHAR('-', out[4]);112 TEST_ASSERT_TRUE(is_all_digits(out+5, 2));113 TEST_ASSERT_EQUAL_CHAR('-', out[7]);114 TEST_ASSERT_TRUE(is_all_digits(out+8, 2));115 TEST_ASSERT_EQUAL_CHAR(' ', out[10]);116 TEST_ASSERT_TRUE(is_all_digits(out+11, 2));117 TEST_ASSERT_EQUAL_CHAR(':', out[13]);118 TEST_ASSERT_TRUE(is_all_digits(out+14, 2));119 TEST_ASSERT_EQUAL_CHAR(':', out[16]);120 TEST_ASSERT_TRUE(is_all_digits(out+17, 2));121}122 123void test_currentTimeFunc_date_basic(void){124 static const char *fmt = "%Y-%m-%d"; /* 10 chars */125 register_time_func("FD", fmt);126 127 char out[32];128 int n = exec_select_single_text("SELECT FD()", out, sizeof(out));129 TEST_ASSERT_EQUAL_INT(10, n);130 131 /* Pattern: YYYY-MM-DD */132 TEST_ASSERT_TRUE(is_all_digits(out+0, 4));133 TEST_ASSERT_EQUAL_CHAR('-', out[4]);134 TEST_ASSERT_TRUE(is_all_digits(out+5, 2));135 TEST_ASSERT_EQUAL_CHAR('-', out[7]);136 TEST_ASSERT_TRUE(is_all_digits(out+8, 2));137}138 139void test_currentTimeFunc_time_basic(void){140 static const char *fmt = "%H:%M:%S"; /* 8 chars */141 register_time_func("FT", fmt);142 143 char out[32];144 int n = exec_select_single_text("SELECT FT()", out, sizeof(out));145 TEST_ASSERT_EQUAL_INT(8, n);146 147 /* Pattern: HH:MM:SS */148 TEST_ASSERT_TRUE(is_all_digits(out+0, 2));149 TEST_ASSERT_EQUAL_CHAR(':', out[2]);150 TEST_ASSERT_TRUE(is_all_digits(out+3, 2));151 TEST_ASSERT_EQUAL_CHAR(':', out[5]);152 TEST_ASSERT_TRUE(is_all_digits(out+6, 2));153}154 155void test_currentTimeFunc_user_data_literal_prefix(void){156 static const char *fmt = "abc%Y"; /* e.g., abc2025 -> 7 chars */157 register_time_func("FABC", fmt);158 159 char out[32];160 int n = exec_select_single_text("SELECT FABC()", out, sizeof(out));161 TEST_ASSERT_EQUAL_INT(7, n);162 163 TEST_ASSERT_EQUAL_CHAR('a', out[0]);164 TEST_ASSERT_EQUAL_CHAR('b', out[1]);165 TEST_ASSERT_EQUAL_CHAR('c', out[2]);166 TEST_ASSERT_TRUE(is_all_digits(out+3, 4));167}168 169void test_currentTimeFunc_stable_within_statement(void){170 static const char *fmt = "%Y-%m-%d %H:%M:%S";171 register_time_func("FSTABLE", fmt);172 173 char a[32], b[32];174 int na = 0, nb = 0;175 exec_select_two_text("SELECT FSTABLE(), FSTABLE()", a, sizeof(a), &na, b, sizeof(b), &nb);176 177 TEST_ASSERT_EQUAL_INT(na, nb);178 TEST_ASSERT_EQUAL_STRING(a, b);179}180 181int main(void) {182 UNITY_BEGIN();183 RUN_TEST(test_currentTimeFunc_timestamp_basic);184 RUN_TEST(test_currentTimeFunc_date_basic);185 RUN_TEST(test_currentTimeFunc_time_basic);186 RUN_TEST(test_currentTimeFunc_user_data_literal_prefix);187 RUN_TEST(test_currentTimeFunc_stable_within_statement);188 return UNITY_END();189}