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/* Provided by the module under test (wrapper for static function) */9extern void test_jsonObjectFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);10 11static sqlite3 *gDb = NULL;12 13/* Trampoline function to invoke the target via SQLite SQL layer */14static void xjson_object_test_sqlfunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){15 /* Directly call the provided wrapper */16 test_jsonObjectFunc(ctx, argc, argv);17}18 19/* Helper function to return raw JSON text with JSON subtype */20static void rawjson_sqlfunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){21 (void)argc;22 const unsigned char *z = sqlite3_value_text(argv[0]);23 int n = sqlite3_value_bytes(argv[0]);24 if( z==NULL ){25 sqlite3_result_null(ctx);26 return;27 }28 sqlite3_result_text(ctx, (const char*)z, n, SQLITE_TRANSIENT);29 sqlite3_result_subtype(ctx, JSON_SUBTYPE);30}31 32void setUp(void) {33 int rc = sqlite3_open(":memory:", &gDb);34 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");35 36 /* Register a variable-arg function that forwards to test_jsonObjectFunc */37 rc = sqlite3_create_function(gDb, "xjson_object_test", -1, SQLITE_UTF8, NULL,38 xjson_object_test_sqlfunc, NULL, NULL);39 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "create_function xjson_object_test failed");40 41 /* Register helper to produce TEXT with JSON subtype */42 rc = sqlite3_create_function(gDb, "rawjson", 1, SQLITE_UTF8, NULL,43 rawjson_sqlfunc, NULL, NULL);44 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "create_function rawjson failed");45}46 47void tearDown(void) {48 if( gDb ){49 int rc = sqlite3_close(gDb);50 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_close failed");51 gDb = NULL;52 }53}54 55/* Helper: run SQL that should yield exactly one row, one column, compare to expected,56 and confirm JSON subtype. */57static void assertQueryResultJson(const char *sql, const char *expected){58 sqlite3_stmt *pStmt = NULL;59 int rc = sqlite3_prepare_v2(gDb, sql, -1, &pStmt, NULL);60 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");61 62 rc = sqlite3_step(pStmt);63 if( rc!=SQLITE_ROW ){64 const char *errmsg = sqlite3_errmsg(gDb);65 sqlite3_finalize(pStmt);66 TEST_FAIL_MESSAGE(errmsg ? errmsg : "Expected SQLITE_ROW");67 }68 69 const unsigned char *z = sqlite3_column_text(pStmt, 0);70 int subtype = sqlite3_column_subtype(pStmt, 0);71 TEST_ASSERT_NOT_NULL(z);72 TEST_ASSERT_EQUAL_STRING(expected, (const char*)z);73 TEST_ASSERT_EQUAL_INT(JSON_SUBTYPE, subtype);74 75 rc = sqlite3_step(pStmt);76 TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);77 78 rc = sqlite3_finalize(pStmt);79 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);80}81 82/* Helper: run SQL expected to error; compare error message */83static void assertQueryError(const char *sql, const char *expMsg){84 sqlite3_stmt *pStmt = NULL;85 int rc = sqlite3_prepare_v2(gDb, sql, -1, &pStmt, NULL);86 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");87 88 rc = sqlite3_step(pStmt);89 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);90 91 const char *errmsg = sqlite3_errmsg(gDb);92 TEST_ASSERT_NOT_NULL(errmsg);93 TEST_ASSERT_EQUAL_STRING(expMsg, errmsg);94 95 rc = sqlite3_finalize(pStmt);96 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);97}98 99/* Tests */100 101void test_jsonObjectFunc_empty(void){102 assertQueryResultJson("SELECT xjson_object_test()", "{}", /* subtype JSON */ 0);103}104 105void test_jsonObjectFunc_simple_types(void){106 /* Expect integer, text (quoted), and null */107 assertQueryResultJson(108 "SELECT xjson_object_test('a', 1, 'b', 'x', 'c', NULL)",109 "{\"a\":1,\"b\":\"x\",\"c\":null}"110 );111}112 113void test_jsonObjectFunc_odd_number_of_args_error(void){114 assertQueryError(115 "SELECT xjson_object_test('a')",116 "json_object() requires an even number of arguments"117 );118}119 120void test_jsonObjectFunc_nontext_label_error(void){121 assertQueryError(122 "SELECT xjson_object_test(1, 'x')",123 "json_object() labels must be TEXT"124 );125}126 127void test_jsonObjectFunc_blob_value_error(void){128 assertQueryError(129 "SELECT xjson_object_test('bin', x'0102')",130 "JSON cannot hold BLOB values"131 );132}133 134void test_jsonObjectFunc_label_escaping(void){135 /* Label with double-quote and backslash: a"b\c => "a\"b\\c" */136 assertQueryResultJson(137 "SELECT xjson_object_test('a\"b\\c', 1)",138 "{\"a\\\"b\\\\c\":1}"139 );140}141 142void test_jsonObjectFunc_value_escaping_newline_and_quote(void){143 /* Value contains newline (char(10)) and quote; build via concatenation */144 assertQueryResultJson(145 "SELECT xjson_object_test('nl', char(10), 'q', 'a\"b')",146 "{\"nl\":\"\\n\",\"q\":\"a\\\"b\"}"147 );148}149 150void test_jsonObjectFunc_json_subtype_passthrough(void){151 /* rawjson returns its text argument with JSON subtype => inserted as raw JSON (no quotes) */152 assertQueryResultJson(153 "SELECT xjson_object_test('j', rawjson('{\"a\":1}'))",154 "{\"j\":{\"a\":1}}"155 );156}157 158int main(void){159 UNITY_BEGIN();160 RUN_TEST(test_jsonObjectFunc_empty);161 RUN_TEST(test_jsonObjectFunc_simple_types);162 RUN_TEST(test_jsonObjectFunc_odd_number_of_args_error);163 RUN_TEST(test_jsonObjectFunc_nontext_label_error);164 RUN_TEST(test_jsonObjectFunc_blob_value_error);165 RUN_TEST(test_jsonObjectFunc_label_escaping);166 RUN_TEST(test_jsonObjectFunc_value_escaping_newline_and_quote);167 RUN_TEST(test_jsonObjectFunc_json_subtype_passthrough);168 return UNITY_END();169}