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 wrapper symbol provided in the module under test */9extern void test_jsonArrayFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);10 11static sqlite3 *gDb = NULL;12 13/* SQL function trampoline that invokes the target wrapper */14static void xTestJsonArrayFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){15 test_jsonArrayFunc(ctx, argc, argv);16}17 18/* Helper: register the SQL function that calls the target wrapper */19static void register_test_function(sqlite3 *db){20 /* Deterministic is fine. No user-data flags so results are text, not JSONB */21 int rc = sqlite3_create_function(db, "test_jsonArrayFunc", -1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,22 0, xTestJsonArrayFunc, 0, 0);23 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);24}25 26/* Helper: prepare, step once, assert row, return stmt for caller to inspect */27static sqlite3_stmt* prepare_and_step(const char *sql){28 sqlite3_stmt *stmt = NULL;29 int rc = sqlite3_prepare_v2(gDb, sql, -1, &stmt, 0);30 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");31 rc = sqlite3_step(stmt);32 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "expected a single row result");33 return stmt;34}35 36/* Helper: execute expecting SQLITE_ERROR with an error message containing a substring */37static void expect_sql_error_contains(const char *sql, const char *needle){38 sqlite3_stmt *stmt = NULL;39 int rc = sqlite3_prepare_v2(gDb, sql, -1, &stmt, 0);40 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");41 rc = sqlite3_step(stmt);42 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ERROR, rc, "expected SQLITE_ERROR from step");43 const char *emsg = sqlite3_errmsg(gDb);44 TEST_ASSERT_NOT_NULL(emsg);45 TEST_ASSERT_NOT_NULL(needle);46 TEST_ASSERT_NOT_EQUAL(-1, (int)(strstr(emsg, needle) - emsg >= 0 ? strstr(emsg, needle) - emsg : -1));47 sqlite3_finalize(stmt);48}49 50/* Helper: check single TEXT result equals expected and subtype is JSON_SUBTYPE */51static void expect_single_text_and_json_subtype(const char *sql, const char *expected){52 sqlite3_stmt *stmt = prepare_and_step(sql);53 const unsigned char *txt = sqlite3_column_text(stmt, 0);54 int subtype = sqlite3_column_subtype(stmt, 0);55 TEST_ASSERT_NOT_NULL(txt);56 TEST_ASSERT_EQUAL_STRING(expected, (const char*)txt);57 TEST_ASSERT_EQUAL_INT(JSON_SUBTYPE, subtype);58 sqlite3_finalize(stmt);59}60 61void setUp(void) {62 int rc = sqlite3_open(":memory:", &gDb);63 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64 register_test_function(gDb);65}66 67void tearDown(void) {68 if( gDb ){69 sqlite3_close(gDb);70 gDb = NULL;71 }72}73 74/* Test: no arguments -> [] with JSON subtype */75void test_jsonArrayFunc_empty(void){76 expect_single_text_and_json_subtype("SELECT test_jsonArrayFunc()", "[]");77}78 79/* Test: NULL handling -> [null,null] */80void test_jsonArrayFunc_nulls(void){81 expect_single_text_and_json_subtype("SELECT test_jsonArrayFunc(NULL,NULL)", "[null,null]");82}83 84/* Test: mixed types: INTEGER, FLOAT, TEXT */85void test_jsonArrayFunc_mixed_types(void){86 /* '1' (TEXT) should be quoted, float formatting should be 3.5 */87 expect_single_text_and_json_subtype(88 "SELECT test_jsonArrayFunc(1, -2, 3.5, 'x', '1')",89 "[1,-2,3.5,\"x\",\"1\"]"90 );91}92 93/* Test: string quoting and escaping of quotes */94void test_jsonArrayFunc_string_escaping(void){95 /* input: a"b -> JSON string should be \" escaped */96 expect_single_text_and_json_subtype(97 "SELECT test_jsonArrayFunc('a\"b')",98 "[\"a\\\"b\"]"99 );100}101 102/* Test: passthrough for JSON-typed text (subtype JSON_SUBTYPE) using json() */103void test_jsonArrayFunc_json_subtype_passthrough(void){104 /* json('{"x":1}') yields JSON-subtype text; it should be inserted raw, not quoted */105 expect_single_text_and_json_subtype(106 "SELECT test_jsonArrayFunc(json('{\"x\":1}'), 'y')",107 "[{\"x\":1},\"y\"]"108 );109}110 111/* Test: BLOB argument should raise an error: "JSON cannot hold BLOB values" */112void test_jsonArrayFunc_blob_error(void){113 expect_sql_error_contains("SELECT test_jsonArrayFunc(x'313233')", "BLOB");114}115 116/* Test: buffer growth by using many arguments; verify length is as expected */117void test_jsonArrayFunc_many_args_growth(void){118 /* Build a SELECT with 200 'a' literals */119 char sql[8192];120 strcpy(sql, "SELECT test_jsonArrayFunc(");121 for(int i=0; i<200; i++){122 strcat(sql, "'a'");123 if( i!=199 ) strcat(sql, ",");124 }125 strcat(sql, ")");126 sqlite3_stmt *stmt = prepare_and_step(sql);127 const unsigned char *txt = sqlite3_column_text(stmt, 0);128 int subtype = sqlite3_column_subtype(stmt, 0);129 TEST_ASSERT_NOT_NULL(txt);130 TEST_ASSERT_EQUAL_INT(JSON_SUBTYPE, subtype);131 int n = sqlite3_column_bytes(stmt, 0);132 /* Each 'a' becomes "a" (3 chars), 199 commas, and 2 brackets: 200*3 + 199 + 2 = 801 */133 TEST_ASSERT_EQUAL_INT(801, n);134 sqlite3_finalize(stmt);135}136 137int main(void){138 UNITY_BEGIN();139 RUN_TEST(test_jsonArrayFunc_empty);140 RUN_TEST(test_jsonArrayFunc_nulls);141 RUN_TEST(test_jsonArrayFunc_mixed_types);142 RUN_TEST(test_jsonArrayFunc_string_escaping);143 RUN_TEST(test_jsonArrayFunc_json_subtype_passthrough);144 RUN_TEST(test_jsonArrayFunc_blob_error);145 RUN_TEST(test_jsonArrayFunc_many_args_growth);146 return UNITY_END();147}