AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdint.h>5 6/* Prototype of the auto-generated wrapper provided in the module */7void test_trimFunc(sqlite3_context *context, int argc, sqlite3_value **argv);8 9static void init_context(sqlite3 *db, sqlite3_context *pCtx, FuncDef *pDef, Mem *pOut, int flags){10 memset(pCtx, 0, sizeof(*pCtx));11 memset(pDef, 0, sizeof(*pDef));12 memset(pOut, 0, sizeof(*pOut));13 14 /* Set user data flags: 1=L, 2=R, 3=both */15 pDef->pUserData = SQLITE_INT_TO_PTR(flags);16 17 /* Initialize output Mem with db so result_text allocations work */18 sqlite3VdbeMemInit(pOut, db, 0);19 20 pCtx->pFunc = pDef;21 pCtx->pOut = pOut;22}23 24static void free_value(sqlite3_value *v){25 if( v ){26 sqlite3ValueFree(v);27 }28}29 30static sqlite3_value* make_text_value(sqlite3 *db, const char *z){31 sqlite3_value *v = sqlite3ValueNew(db);32 if( z ){33 sqlite3ValueSetStr(v, -1, z, SQLITE_UTF8, SQLITE_TRANSIENT);34 }35 return v;36}37 38void setUp(void) {39 /* No global setup required */40}41 42void tearDown(void) {43 /* No global teardown required */44}45 46/* Helper to run trim and return output as C string (owned by out Mem).47 expectedNull==1 means expect NULL output. */48static void run_trim_case(49 int flags, /* 1=L, 2=R, 3=both */50 const char *zIn, /* Input text, or NULL for SQL NULL */51 int passCharsetArg, /* 0: argc=1 (default space), 1: argc=2 */52 const char *zCharset, /* Charset text; if passCharsetArg and NULL => SQL NULL */53 const char *zExpected /* Expected string; if NULL => expect SQL NULL */54){55 sqlite3 *db = 0;56 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));57 58 /* Build context and output */59 sqlite3_context ctx;60 FuncDef func;61 Mem outMem;62 init_context(db, &ctx, &func, &outMem, flags);63 64 /* Build arguments */65 sqlite3_value *argv[2] = {0,0};66 int argc = passCharsetArg ? 2 : 1;67 68 sqlite3_value *vIn = make_text_value(db, zIn);69 argv[0] = vIn;70 71 sqlite3_value *vSet = 0;72 if( passCharsetArg ){73 vSet = make_text_value(db, zCharset);74 argv[1] = vSet;75 }76 77 /* Call the function under test */78 test_trimFunc(&ctx, argc, argv);79 80 if( zExpected==NULL ){81 /* Expect NULL result */82 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&outMem));83 }else{84 /* Expect text result matching zExpected */85 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&outMem));86 const unsigned char *zOut = sqlite3_value_text((sqlite3_value*)&outMem);87 TEST_ASSERT_NOT_NULL(zOut);88 TEST_ASSERT_EQUAL_STRING(zExpected, (const char*)zOut);89 }90 91 /* Cleanup */92 free_value(vIn);93 free_value(vSet);94 sqlite3VdbeMemRelease(&outMem);95 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));96}97 98/* Tests */99 100/* Default TRIM (space only), both sides */101void test_trimFunc_default_both_basic(void){102 run_trim_case(3, " abc ", 0, NULL, "abc");103}104 105/* Default LTRIM (space only) */106void test_trimFunc_default_left_only(void){107 run_trim_case(1, " abc ", 0, NULL, "abc ");108}109 110/* Default RTRIM (space only) */111void test_trimFunc_default_right_only(void){112 run_trim_case(2, " abc ", 0, NULL, " abc");113}114 115/* Explicit ASCII charset "xyz", both sides */116void test_trimFunc_explicit_charset_ascii_both(void){117 run_trim_case(3, "xyxabczyx", 1, "xyz", "abc");118}119 120/* Explicit single-space charset behaves like default */121void test_trimFunc_explicit_space_same_as_default(void){122 run_trim_case(3, " abc ", 1, " ", "abc");123}124 125/* Empty charset (no characters) should be a no-op */126void test_trimFunc_empty_charset_is_noop(void){127 run_trim_case(3, " abc ", 1, "", " abc ");128}129 130/* NULL input -> result is NULL */131void test_trimFunc_null_input_returns_null(void){132 run_trim_case(3, NULL, 0, NULL, NULL);133}134 135/* Non-NULL input but NULL charset argument -> result is NULL (propagate NULL) */136void test_trimFunc_null_charset_returns_null(void){137 run_trim_case(3, "abc", 1, NULL, NULL);138}139 140/* Default does not trim tabs, only spaces */141void test_trimFunc_default_does_not_trim_tabs(void){142 run_trim_case(3, " \tabc\t ", 0, NULL, "\tabc\t");143}144 145/* Explicit charset with space and tab trims both */146void test_trimFunc_explicit_space_and_tab(void){147 run_trim_case(3, " \tabc\t ", 1, " \t", "abc");148}149 150/* Multibyte UTF-8 charset: NBSP and EURO, both sides */151void test_trimFunc_multibyte_charset_both(void){152 const char *NBSP = "\xC2\xA0"; /* U+00A0 */153 const char *EURO = "\xE2\x82\xAC"; /* U+20AC */154 const char *in =155 "\xC2\xA0" "\xC2\xA0" "abc" "\xE2\x82\xAC" "\xE2\x82\xAC";156 char charset[16];157 /* Build charset string containing NBSP and EURO (two UTF-8 characters) */158 strcpy(charset, NBSP);159 strcat(charset, EURO);160 run_trim_case(3, in, 1, charset, "abc");161}162 163/* Right-only trim with multibyte charset: keep left NBSP, remove right EURO */164void test_trimFunc_right_only_multibyte(void){165 const char *NBSP = "\xC2\xA0"; /* U+00A0 */166 const char *EURO = "\xE2\x82\xAC"; /* U+20AC */167 char in[32];168 char charset[16];169 strcpy(in, NBSP);170 strcat(in, "abc");171 strcat(in, EURO);172 strcpy(charset, NBSP);173 strcat(charset, EURO);174 /* Expect left NBSP preserved, right EURO removed */175 char expected[16];176 strcpy(expected, NBSP);177 strcat(expected, "abc");178 run_trim_case(2, in, 1, charset, expected);179}180 181/* Empty input should remain empty */182void test_trimFunc_empty_input(void){183 run_trim_case(3, "", 0, NULL, "");184}185 186int main(void) {187 UNITY_BEGIN();188 RUN_TEST(test_trimFunc_default_both_basic);189 RUN_TEST(test_trimFunc_default_left_only);190 RUN_TEST(test_trimFunc_default_right_only);191 RUN_TEST(test_trimFunc_explicit_charset_ascii_both);192 RUN_TEST(test_trimFunc_explicit_space_same_as_default);193 RUN_TEST(test_trimFunc_empty_charset_is_noop);194 RUN_TEST(test_trimFunc_null_input_returns_null);195 RUN_TEST(test_trimFunc_null_charset_returns_null);196 RUN_TEST(test_trimFunc_default_does_not_trim_tabs);197 RUN_TEST(test_trimFunc_explicit_space_and_tab);198 RUN_TEST(test_trimFunc_multibyte_charset_both);199 RUN_TEST(test_trimFunc_right_only_multibyte);200 RUN_TEST(test_trimFunc_empty_input);201 return UNITY_END();202}