AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Wrapper function provided in the source module */7extern void test_concatFuncCore(sqlite3_context *context, int argc, sqlite3_value **argv, int nSep, const char *zSep);8 9static sqlite3 *gDb = NULL;10static sqlite3_context gCtx;11static Mem gOut; /* Output Mem for sqlite3_context */12 13/* Helper: reset the sqlite3_context and output Mem before each call */14static void reset_context(void){15 memset(&gOut, 0, sizeof(gOut));16 gOut.db = gDb; /* Important so sqlite3_result_* can allocate/free */17 memset(&gCtx, 0, sizeof(gCtx));18 gCtx.pOut = &gOut;19}20 21/* Helper: create a sqlite3_value* with a UTF-8 string. If s==NULL, returns a NULL value */22static sqlite3_value* makeTextVal(const char *s){23 sqlite3_value *v = sqlite3ValueNew(gDb);24 TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3ValueNew returned NULL");25 if( s!=NULL ){26 sqlite3ValueSetStr(v, -1, (const void*)s, SQLITE_UTF8, SQLITE_STATIC);27 }28 return v;29}30 31/* Helper: verify the output equals expected string exactly */32static void assert_out_eq(const char *expected){33 size_t nExp = strlen(expected);34 TEST_ASSERT_EQUAL_UINT64_MESSAGE(nExp, (unsigned long long)gOut.n, "Output length mismatch");35 TEST_ASSERT_NOT_NULL_MESSAGE(gOut.z, "Output string pointer is NULL");36 /* Ensure NUL-terminated */37 TEST_ASSERT_EQUAL_INT8_MESSAGE(0, gOut.z[gOut.n], "Output string not NUL-terminated");38 /* Compare exact bytes (including potential embedded NULs if any) */39 TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, gOut.z, nExp, "Output content mismatch");40}41 42/* Unity setup/teardown */43void setUp(void) {44 if( gDb==NULL ){45 int rc = sqlite3_open(":memory:", &gDb);46 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory sqlite3 db");47 }48 reset_context();49}50void tearDown(void) {51 /* Release any memory held by output Mem */52 sqlite3VdbeMemRelease(&gOut);53 memset(&gOut, 0, sizeof(gOut));54}55 56/* Tests */57 58void test_concatFuncCore_simple_no_separator(void){59 sqlite3_value *argv[3];60 argv[0] = makeTextVal("a");61 argv[1] = makeTextVal("b");62 argv[2] = makeTextVal("c");63 64 test_concatFuncCore(&gCtx, 3, argv, 0, NULL);65 66 assert_out_eq("abc");67 68 sqlite3ValueFree(argv[0]);69 sqlite3ValueFree(argv[1]);70 sqlite3ValueFree(argv[2]);71}72 73void test_concatFuncCore_with_separator_all_non_null(void){74 sqlite3_value *argv[3];75 argv[0] = makeTextVal("apple");76 argv[1] = makeTextVal("banana");77 argv[2] = makeTextVal("cherry");78 79 const char *sep = "-";80 test_concatFuncCore(&gCtx, 3, argv, (int)strlen(sep), sep);81 82 assert_out_eq("apple-banana-cherry");83 84 sqlite3ValueFree(argv[0]);85 sqlite3ValueFree(argv[1]);86 sqlite3ValueFree(argv[2]);87}88 89void test_concatFuncCore_with_nulls_ignored_and_separators_only_between_nonnull(void){90 sqlite3_value *argv[4];91 argv[0] = makeTextVal("a");92 argv[1] = makeTextVal(NULL); /* NULL */93 argv[2] = makeTextVal("b");94 argv[3] = makeTextVal(NULL); /* NULL */95 96 const char *sep = ":";97 test_concatFuncCore(&gCtx, 4, argv, (int)strlen(sep), sep);98 99 assert_out_eq("a:b");100 101 sqlite3ValueFree(argv[0]);102 sqlite3ValueFree(argv[1]);103 sqlite3ValueFree(argv[2]);104 sqlite3ValueFree(argv[3]);105}106 107void test_concatFuncCore_all_nulls_returns_empty_string(void){108 sqlite3_value *argv[3];109 argv[0] = makeTextVal(NULL);110 argv[1] = makeTextVal(NULL);111 argv[2] = makeTextVal(NULL);112 113 const char *sep = "/";114 test_concatFuncCore(&gCtx, 3, argv, (int)strlen(sep), sep);115 116 assert_out_eq("");117 118 sqlite3ValueFree(argv[0]);119 sqlite3ValueFree(argv[1]);120 sqlite3ValueFree(argv[2]);121}122 123void test_concatFuncCore_empty_strings_are_nonnull_and_produce_separators(void){124 sqlite3_value *argv[2];125 argv[0] = makeTextVal("");126 argv[1] = makeTextVal("");127 128 const char *sep = ",";129 test_concatFuncCore(&gCtx, 2, argv, (int)strlen(sep), sep);130 131 /* Two empty but non-NULL strings -> separator appears between them */132 assert_out_eq(",");133 134 sqlite3ValueFree(argv[0]);135 sqlite3ValueFree(argv[1]);136}137 138void test_concatFuncCore_utf8_multibyte_inputs_and_separator(void){139 /* Use multibyte UTF-8 characters */140 const char *s1 = "éclair"; /* 'é' is multibyte in UTF-8 */141 const char *s2 = "你"; /* Chinese character */142 const char *s3 = "🙂"; /* Emoji */143 const char *sep = "—"; /* em dash, multibyte */144 145 sqlite3_value *argv[3];146 argv[0] = makeTextVal(s1);147 argv[1] = makeTextVal(s2);148 argv[2] = makeTextVal(s3);149 150 test_concatFuncCore(&gCtx, 3, argv, (int)strlen(sep), sep);151 152 char expected[256];153 memset(expected, 0, sizeof(expected));154 /* Build expected using standard C string concatenation */155 strcpy(expected, s1);156 strcat(expected, sep);157 strcat(expected, s2);158 strcat(expected, sep);159 strcat(expected, s3);160 161 assert_out_eq(expected);162 163 sqlite3ValueFree(argv[0]);164 sqlite3ValueFree(argv[1]);165 sqlite3ValueFree(argv[2]);166}167 168void test_concatFuncCore_zero_length_separator(void){169 sqlite3_value *argv[3];170 argv[0] = makeTextVal("x");171 argv[1] = makeTextVal("y");172 argv[2] = makeTextVal("z");173 174 const char *sep = ""; /* zero-length separator */175 test_concatFuncCore(&gCtx, 3, argv, 0, sep);176 177 assert_out_eq("xyz");178 179 sqlite3ValueFree(argv[0]);180 sqlite3ValueFree(argv[1]);181 sqlite3ValueFree(argv[2]);182}183 184void test_concatFuncCore_mixed_empty_and_null(void){185 sqlite3_value *argv[3];186 argv[0] = makeTextVal("");187 argv[1] = makeTextVal(NULL);188 argv[2] = makeTextVal("");189 190 const char *sep = ":";191 test_concatFuncCore(&gCtx, 3, argv, (int)strlen(sep), sep);192 193 /* Two non-NULL empties with a NULL in the middle -> just the separator */194 assert_out_eq(":");195 196 sqlite3ValueFree(argv[0]);197 sqlite3ValueFree(argv[1]);198 sqlite3ValueFree(argv[2]);199}200 201int main(void) {202 UNITY_BEGIN();203 204 RUN_TEST(test_concatFuncCore_simple_no_separator);205 RUN_TEST(test_concatFuncCore_with_separator_all_non_null);206 RUN_TEST(test_concatFuncCore_with_nulls_ignored_and_separators_only_between_nonnull);207 RUN_TEST(test_concatFuncCore_all_nulls_returns_empty_string);208 RUN_TEST(test_concatFuncCore_empty_strings_are_nonnull_and_produce_separators);209 RUN_TEST(test_concatFuncCore_utf8_multibyte_inputs_and_separator);210 RUN_TEST(test_concatFuncCore_zero_length_separator);211 RUN_TEST(test_concatFuncCore_mixed_empty_and_null);212 213 /* Clean up global DB */214 if( gDb ){215 sqlite3_close(gDb);216 gDb = NULL;217 }218 219 return UNITY_END();220}