AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdint.h>5#include <stdio.h>6 7/* Extern wrapper provided in the module */8extern void test_substrFunc(sqlite3_context *context, int argc, sqlite3_value **argv);9 10static sqlite3 *gDb = NULL;11 12static void initMem(Mem *m){13 memset(m, 0, sizeof(*m));14 m->db = gDb;15}16 17static void releaseMem(Mem *m){18 sqlite3VdbeMemRelease(m);19 memset(m, 0, sizeof(*m));20 m->db = gDb;21}22 23static void prepareContext(sqlite3_context *ctx, Mem *out){24 memset(ctx, 0, sizeof(*ctx));25 initMem(out);26 sqlite3VdbeMemSetNull(out);27 ctx->pOut = out;28 /* Ensure db handle is available to context if needed */29 ctx->s.db = gDb;30}31 32/* Helpers to build arguments */33static void setArgText(Mem *m, const char *z){34 initMem(m);35 TEST_ASSERT_EQUAL_INT(SQLITE_OK,36 sqlite3VdbeMemSetStr(m, z, -1, SQLITE_UTF8, SQLITE_TRANSIENT)37 );38}39 40static void setArgBlob(Mem *m, const void *z, int n){41 initMem(m);42 /* enc==0 signals BLOB to sqlite3VdbeMemSetStr */43 TEST_ASSERT_EQUAL_INT(SQLITE_OK,44 sqlite3VdbeMemSetStr(m, (const char*)z, n, 0, SQLITE_TRANSIENT)45 );46}47 48static void setArgInt(Mem *m, sqlite3_int64 v){49 initMem(m);50 sqlite3VdbeMemSetInt64(m, v);51}52 53static void setArgNull(Mem *m){54 initMem(m);55 sqlite3VdbeMemSetNull(m);56}57 58/* Call substrFunc with 2 or 3 args */59static void call_substr(Mem *arg0, Mem *arg1, Mem *arg2, int argc, Mem *outRes){60 sqlite3_context ctx;61 sqlite3_value *argv3[3];62 sqlite3_value **argv = argv3;63 int i;64 prepareContext(&ctx, outRes);65 for(i=0;i<argc;i++){66 Mem *pm = (i==0?arg0:(i==1?arg1:arg2));67 argv3[i] = (sqlite3_value*)pm;68 }69 test_substrFunc(&ctx, argc, argv);70}71 72/* Extractors for assertions */73static const unsigned char* resultText(const Mem *out, int *pN){74 const unsigned char *z = sqlite3_value_text((sqlite3_value*)out);75 if( pN ) *pN = sqlite3_value_bytes((sqlite3_value*)out);76 return z;77}78 79static const void* resultBlob(const Mem *out, int *pN){80 const void *z = sqlite3_value_blob((sqlite3_value*)out);81 if( pN ) *pN = sqlite3_value_bytes((sqlite3_value*)out);82 return z;83}84 85void setUp(void) {86 int rc = sqlite3_open(":memory:", &gDb);87 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);88}89 90void tearDown(void) {91 int rc = sqlite3_close(gDb);92 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);93 gDb = NULL;94}95 96/* Tests */97 98void test_substrFunc_text_basic(void){99 Mem a0, a1, a2, out;100 /* substr("abcdef", 2, 3) -> "bcd" */101 setArgText(&a0, "abcdef");102 setArgInt(&a1, 2);103 setArgInt(&a2, 3);104 call_substr(&a0, &a1, &a2, 3, &out);105 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));106 int n = 0;107 const unsigned char *z = resultText(&out, &n);108 TEST_ASSERT_EQUAL_INT(3, n);109 TEST_ASSERT_EQUAL_STRING_LEN("bcd", (const char*)z, 3);110 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);111 112 /* substr("abcdef", 1, 1) -> "a" */113 setArgText(&a0, "abcdef");114 setArgInt(&a1, 1);115 setArgInt(&a2, 1);116 call_substr(&a0, &a1, &a2, 3, &out);117 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));118 z = resultText(&out, &n);119 TEST_ASSERT_EQUAL_INT(1, n);120 TEST_ASSERT_EQUAL_STRING_LEN("a", (const char*)z, 1);121 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);122 123 /* p1 beyond end: substr("abcdef", 7, 2) -> "" */124 setArgText(&a0, "abcdef");125 setArgInt(&a1, 7);126 setArgInt(&a2, 2);127 call_substr(&a0, &a1, &a2, 3, &out);128 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));129 z = resultText(&out, &n);130 TEST_ASSERT_EQUAL_INT(0, n);131 /* empty string is ok; z may be "" */132 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);133}134 135void test_substrFunc_two_args_to_end(void){136 Mem a0, a1, out;137 /* substr("abcdef", 4) -> "def" */138 setArgText(&a0, "abcdef");139 setArgInt(&a1, 4);140 call_substr(&a0, &a1, NULL, 2, &out);141 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));142 int n=0; const unsigned char *z = resultText(&out, &n);143 TEST_ASSERT_EQUAL_INT(3, n);144 TEST_ASSERT_EQUAL_STRING_LEN("def", (const char*)z, 3);145 releaseMem(&out); releaseMem(&a0); releaseMem(&a1);146 147 /* substr("abcdef", 1) -> "abcdef" */148 setArgText(&a0, "abcdef");149 setArgInt(&a1, 1);150 call_substr(&a0, &a1, NULL, 2, &out);151 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));152 z = resultText(&out, &n);153 TEST_ASSERT_EQUAL_INT(6, n);154 TEST_ASSERT_EQUAL_STRING_LEN("abcdef", (const char*)z, 6);155 releaseMem(&out); releaseMem(&a0); releaseMem(&a1);156}157 158void test_substrFunc_negative_start_text(void){159 Mem a0, a1, a2, out;160 /* substr("abcdef", -2, 2) -> "ef" */161 setArgText(&a0, "abcdef");162 setArgInt(&a1, -2);163 setArgInt(&a2, 2);164 call_substr(&a0, &a1, &a2, 3, &out);165 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));166 int n=0; const unsigned char *z = resultText(&out, &n);167 TEST_ASSERT_EQUAL_INT(2, n);168 TEST_ASSERT_EQUAL_STRING_LEN("ef", (const char*)z, 2);169 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);170}171 172void test_substrFunc_negative_length_preceding(void){173 Mem a0, a1, a2, out;174 /* substr("abcdef", 5, -2) -> "cd" */175 setArgText(&a0, "abcdef");176 setArgInt(&a1, 5);177 setArgInt(&a2, -2);178 call_substr(&a0, &a1, &a2, 3, &out);179 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));180 int n=0; const unsigned char *z = resultText(&out, &n);181 TEST_ASSERT_EQUAL_INT(2, n);182 TEST_ASSERT_EQUAL_STRING_LEN("cd", (const char*)z, 2);183 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);184 185 /* substr("abcdef", 1, -1) -> "" */186 setArgText(&a0, "abcdef");187 setArgInt(&a1, 1);188 setArgInt(&a2, -1);189 call_substr(&a0, &a1, &a2, 3, &out);190 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));191 z = resultText(&out, &n);192 TEST_ASSERT_EQUAL_INT(0, n);193 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);194}195 196void test_substrFunc_zero_p1_behavior(void){197 Mem a0, a1, a2, out;198 /* Without SQLITE_SUBSTR_COMPATIBILITY: substr("abcdef", 0, 2) -> "a" */199 setArgText(&a0, "abcdef");200 setArgInt(&a1, 0);201 setArgInt(&a2, 2);202 call_substr(&a0, &a1, &a2, 3, &out);203 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));204 int n=0; const unsigned char *z = resultText(&out, &n);205 TEST_ASSERT_EQUAL_INT(1, n);206 TEST_ASSERT_EQUAL_STRING_LEN("a", (const char*)z, 1);207 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);208 209 /* Negative length with p1==0: substr("abcdef", 0, -2) -> "" */210 setArgText(&a0, "abcdef");211 setArgInt(&a1, 0);212 setArgInt(&a2, -2);213 call_substr(&a0, &a1, &a2, 3, &out);214 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));215 z = resultText(&out, &n);216 TEST_ASSERT_EQUAL_INT(0, n);217 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);218}219 220void test_substrFunc_null_cases(void){221 Mem a0, a1, a2, out;222 223 /* arg0 NULL -> result NULL */224 setArgNull(&a0);225 setArgInt(&a1, 1);226 setArgInt(&a2, 2);227 call_substr(&a0, &a1, &a2, 3, &out);228 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&out));229 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);230 231 /* arg2 NULL (p2==NULL) -> result NULL */232 setArgText(&a0, "abcdef");233 setArgInt(&a1, 2);234 setArgNull(&a2);235 call_substr(&a0, &a1, &a2, 3, &out);236 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&out));237 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);238}239 240void test_substrFunc_blob_basic_and_bounds(void){241 Mem a0, a1, a2, out;242 const unsigned char blob[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };243 244 /* substr(BLOB, 2, 2) -> {0x02,0x03} */245 setArgBlob(&a0, blob, (int)sizeof(blob));246 setArgInt(&a1, 2);247 setArgInt(&a2, 2);248 call_substr(&a0, &a1, &a2, 3, &out);249 TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, sqlite3_value_type((sqlite3_value*)&out));250 int n=0; const unsigned char *bz = resultBlob(&out, &n);251 TEST_ASSERT_EQUAL_INT(2, n);252 TEST_ASSERT_EQUAL_UINT8_ARRAY((const uint8_t*)"\x02\x03", bz, 2);253 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);254 255 /* p1 beyond end -> empty blob */256 setArgBlob(&a0, blob, (int)sizeof(blob));257 setArgInt(&a1, 10);258 setArgInt(&a2, 5);259 call_substr(&a0, &a1, &a2, 3, &out);260 TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, sqlite3_value_type((sqlite3_value*)&out));261 bz = resultBlob(&out, &n);262 TEST_ASSERT_EQUAL_INT(0, n);263 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);264 265 /* Negative length (preceding bytes): substr(BLOB, 4, -2) -> {0x02,0x03} */266 setArgBlob(&a0, blob, (int)sizeof(blob));267 setArgInt(&a1, 4);268 setArgInt(&a2, -2);269 call_substr(&a0, &a1, &a2, 3, &out);270 TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, sqlite3_value_type((sqlite3_value*)&out));271 bz = resultBlob(&out, &n);272 TEST_ASSERT_EQUAL_INT(2, n);273 TEST_ASSERT_EQUAL_UINT8_ARRAY((const uint8_t*)"\x02\x03", bz, 2);274 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);275}276 277void test_substrFunc_utf8_character_counting(void){278 Mem a0, a1, a2, out;279 /* "a猫b犬c": '猫' and '犬' are 3-byte UTF-8; total 5 characters */280 const char *utf8 = "a猫b犬c";281 282 /* substr("a猫b犬c", 2, 3) -> "猫b犬" */283 setArgText(&a0, utf8);284 setArgInt(&a1, 2);285 setArgInt(&a2, 3);286 call_substr(&a0, &a1, &a2, 3, &out);287 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));288 int n=0; const unsigned char *z = resultText(&out, &n);289 TEST_ASSERT_EQUAL_STRING("猫b犬", (const char*)z);290 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);291 292 /* substr("a猫b犬c", -1, 1) -> "c" (last character) */293 setArgText(&a0, utf8);294 setArgInt(&a1, -1);295 setArgInt(&a2, 1);296 call_substr(&a0, &a1, &a2, 3, &out);297 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_value_type((sqlite3_value*)&out));298 z = resultText(&out, &n);299 TEST_ASSERT_EQUAL_STRING_LEN("c", (const char*)z, 1);300 releaseMem(&out); releaseMem(&a0); releaseMem(&a1); releaseMem(&a2);301}302 303int main(void){304 UNITY_BEGIN();305 RUN_TEST(test_substrFunc_text_basic);306 RUN_TEST(test_substrFunc_two_args_to_end);307 RUN_TEST(test_substrFunc_negative_start_text);308 RUN_TEST(test_substrFunc_negative_length_preceding);309 RUN_TEST(test_substrFunc_zero_p1_behavior);310 RUN_TEST(test_substrFunc_null_cases);311 RUN_TEST(test_substrFunc_blob_basic_and_bounds);312 RUN_TEST(test_substrFunc_utf8_character_counting);313 return UNITY_END();314}