AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdint.h>7 8/* Forward declaration of the auto-generated test wrapper from the module */9void test_jsonRemoveFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);10 11/* Global database handle for tests */12static sqlite3 *gDb = NULL;13 14/* SQLite wrapper function that forwards to the target under test */15static void xJsonRemove(sqlite3_context *ctx, int argc, sqlite3_value **argv){16 /* Use wrapper to directly call the function-under-test in a valid SQLite context */17 test_jsonRemoveFunc(ctx, argc, argv);18}19 20/* Helper: prepare a statement and bind a sequence of text parameters.21 Any const char* in params[] that is NULL will bind as SQL NULL. */22static sqlite3_stmt* prepare_with_text_binds(const char *sql, const char **params, int nParams){23 sqlite3_stmt *stmt = NULL;24 int rc = sqlite3_prepare_v2(gDb, sql, -1, &stmt, 0);25 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");26 for(int i=0; i<nParams; i++){27 if( params[i]==NULL ){28 rc = sqlite3_bind_null(stmt, i+1);29 }else{30 rc = sqlite3_bind_text(stmt, i+1, params[i], -1, SQLITE_TRANSIENT);31 }32 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "bind failed");33 }34 return stmt;35}36 37/* Helper: step a scalar SELECT and return the first column as const char*.38 Asserts that row is returned and value is TEXT. */39static const unsigned char* step_text_result(sqlite3_stmt *stmt){40 int rc = sqlite3_step(stmt);41 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "expected one row result");42 TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_column_type(stmt, 0));43 return sqlite3_column_text(stmt, 0);44}45 46/* Helper: step a scalar SELECT and assert the first column is NULL */47static void step_null_result(sqlite3_stmt *stmt){48 int rc = sqlite3_step(stmt);49 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "expected one row (NULL) result");50 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_column_type(stmt, 0));51}52 53/* Helper: step expecting an error */54static void step_expect_error(sqlite3_stmt *stmt){55 int rc = sqlite3_step(stmt);56 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ERROR, rc, "expected SQLITE_ERROR during step");57}58 59/* Unity setUp/tearDown */60void setUp(void) {61 int rc = sqlite3_open(":memory:", &gDb);62 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");63 64 /* Register our forwarding function. No JSON_BLOB flag (user-data = 0) so results are text. */65 rc = sqlite3_create_function_v2(66 gDb, "x_json_remove", -1, SQLITE_UTF8, (void*)(intptr_t)0,67 xJsonRemove, 0, 0, 068 );69 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "create_function failed");70}71 72void tearDown(void) {73 if( gDb ){74 sqlite3_close(gDb);75 gDb = NULL;76 }77}78 79/* Tests */80 81void test_jsonRemoveFunc_basic_object_key_removal(void){82 const char *sql = "SELECT x_json_remove(?1, ?2)";83 const char *params[] = { "{\"a\":1,\"b\":2}", "$.a" };84 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);85 const unsigned char *res = step_text_result(stmt);86 TEST_ASSERT_EQUAL_STRING("{\"b\":2}", (const char*)res);87 sqlite3_finalize(stmt);88}89 90void test_jsonRemoveFunc_array_index_removal(void){91 const char *sql = "SELECT x_json_remove(?1, ?2)";92 const char *params[] = { "[10,20,30]", "$[1]" };93 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);94 const unsigned char *res = step_text_result(stmt);95 TEST_ASSERT_EQUAL_STRING("[10,30]", (const char*)res);96 sqlite3_finalize(stmt);97}98 99void test_jsonRemoveFunc_nested_object_removal(void){100 const char *sql = "SELECT x_json_remove(?1, ?2)";101 const char *params[] = { "{\"a\":{\"b\":1,\"c\":2},\"d\":3}", "$.a.b" };102 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);103 const unsigned char *res = step_text_result(stmt);104 TEST_ASSERT_EQUAL_STRING("{\"a\":{\"c\":2},\"d\":3}", (const char*)res);105 sqlite3_finalize(stmt);106}107 108void test_jsonRemoveFunc_root_path_returns_null(void){109 const char *sql = "SELECT x_json_remove(?1, '$')";110 const char *params[] = { "{\"x\":1}" };111 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 1);112 step_null_result(stmt);113 sqlite3_finalize(stmt);114}115 116void test_jsonRemoveFunc_nonexistent_path_is_noop(void){117 const char *sql = "SELECT x_json_remove(?1, ?2)";118 const char *params[] = { "{\"a\":1}", "$.x" };119 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);120 const unsigned char *res = step_text_result(stmt);121 TEST_ASSERT_EQUAL_STRING("{\"a\":1}", (const char*)res);122 sqlite3_finalize(stmt);123}124 125void test_jsonRemoveFunc_multiple_paths_remove_two_keys(void){126 const char *sql = "SELECT x_json_remove(?1, ?2, ?3)";127 const char *params[] = { "{\"a\":1,\"b\":2,\"c\":3}", "$.a", "$.b" };128 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 3);129 const unsigned char *res = step_text_result(stmt);130 TEST_ASSERT_EQUAL_STRING("{\"c\":3}", (const char*)res);131 sqlite3_finalize(stmt);132}133 134void test_jsonRemoveFunc_array_oob_index_is_noop(void){135 const char *sql = "SELECT x_json_remove(?1, ?2)";136 const char *params[] = { "[1,2]", "$[5]" };137 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);138 const unsigned char *res = step_text_result(stmt);139 TEST_ASSERT_EQUAL_STRING("[1,2]", (const char*)res);140 sqlite3_finalize(stmt);141}142 143void test_jsonRemoveFunc_array_last_element_with_hash_minus_one(void){144 const char *sql = "SELECT x_json_remove(?1, ?2)";145 const char *params[] = { "[1,2,3,4]", "$[#-1]" };146 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);147 const unsigned char *res = step_text_result(stmt);148 TEST_ASSERT_EQUAL_STRING("[1,2,3]", (const char*)res);149 sqlite3_finalize(stmt);150}151 152void test_jsonRemoveFunc_path_error_reports_error(void){153 const char *sql = "SELECT x_json_remove(?1, ?2)";154 /* Path does not start with '$' -> path error */155 const char *params[] = { "{\"a\":1}", "a" };156 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);157 step_expect_error(stmt);158 sqlite3_finalize(stmt);159}160 161void test_jsonRemoveFunc_malformed_json_reports_error(void){162 const char *sql = "SELECT x_json_remove(?1, ?2)";163 const char *params[] = { "not json", "$.a" };164 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);165 step_expect_error(stmt);166 sqlite3_finalize(stmt);167}168 169void test_jsonRemoveFunc_null_path_argument_returns_null(void){170 const char *sql = "SELECT x_json_remove(?1, ?2)";171 const char *params[] = { "{\"a\":1}", NULL };172 sqlite3_stmt *stmt = prepare_with_text_binds(sql, params, 2);173 step_null_result(stmt);174 sqlite3_finalize(stmt);175}176 177int main(void) {178 UNITY_BEGIN();179 RUN_TEST(test_jsonRemoveFunc_basic_object_key_removal);180 RUN_TEST(test_jsonRemoveFunc_array_index_removal);181 RUN_TEST(test_jsonRemoveFunc_nested_object_removal);182 RUN_TEST(test_jsonRemoveFunc_root_path_returns_null);183 RUN_TEST(test_jsonRemoveFunc_nonexistent_path_is_noop);184 RUN_TEST(test_jsonRemoveFunc_multiple_paths_remove_two_keys);185 RUN_TEST(test_jsonRemoveFunc_array_oob_index_is_noop);186 RUN_TEST(test_jsonRemoveFunc_array_last_element_with_hash_minus_one);187 RUN_TEST(test_jsonRemoveFunc_path_error_reports_error);188 RUN_TEST(test_jsonRemoveFunc_malformed_json_reports_error);189 RUN_TEST(test_jsonRemoveFunc_null_path_argument_returns_null);190 return UNITY_END();191}