Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonObjectStep.c169 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* The step wrapper provided in the module under test */8extern void test_jsonObjectStep(sqlite3_context *ctx, int argc, sqlite3_value **argv);9 10/* Global DB handle for tests */11static sqlite3 *gDb = NULL;12 13/* Finalizer for the test aggregate that uses the aggregate context created by14** test_jsonObjectStep and returns a complete JSON object string.15*/16static void test_jsonObjectFinal(sqlite3_context *ctx){17  JsonString *pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);18  if( pStr==0 || pStr->zBuf==0 ){19    /* No rows or never initialized: return empty object */20    sqlite3_result_text(ctx, "{}", -1, SQLITE_TRANSIENT);21    return;22  }23  if( pStr->eErr ){24    /* An error should already have been reported by the step function. */25    return;26  }27  /* Build result by copying current buffer and appending '}' */28  int n = (int)pStr->nUsed;29  char *zOut = (char*)sqlite3_malloc64((sqlite3_uint64)n + 2);30  if( zOut==0 ){31    sqlite3_result_error_nomem(ctx);32    return;33  }34  memcpy(zOut, pStr->zBuf, (size_t)n);35  zOut[n] = '}';36  zOut[n+1] = 0;37  sqlite3_result_text(ctx, zOut, -1, sqlite3_free);38}39 40/* Helper: register the aggregate function using the target step */41static void register_test_agg(sqlite3 *db, const char *zName){42  int rc = sqlite3_create_function(db, zName, 2, SQLITE_UTF8, 0,43                                   0, /* xFunc */44                                   test_jsonObjectStep, /* xStep */45                                   test_jsonObjectFinal /* xFinal */);46  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);47}48 49/* Helper: evaluate a single-row/single-column SQL and return text result.50   The returned string is allocated by sqlite3 and must be freed using sqlite3_free(). */51static char* eval_sql_text(sqlite3 *db, const char *zSql){52  sqlite3_stmt *pStmt = 0;53  int rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);54  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, sqlite3_errmsg(db));55  rc = sqlite3_step(pStmt);56  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, sqlite3_errmsg(db));57  const unsigned char *z = sqlite3_column_text(pStmt, 0);58  const char *zC = (const char*)z;59  char *zRet = zC ? sqlite3_mprintf("%s", zC) : sqlite3_mprintf("");60  sqlite3_finalize(pStmt);61  return zRet;62}63 64/* Helper: execute SQL without expecting a result row */65static void exec_sql(sqlite3 *db, const char *zSql){66  char *zErr = 0;67  int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);68  if( rc!=SQLITE_OK ){69    const char *msg = zErr ? zErr : sqlite3_errmsg(db);70    TEST_FAIL_MESSAGE(msg);71  }72}73 74void setUp(void) {75  int rc = sqlite3_open(":memory:", &gDb);76  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);77  register_test_agg(gDb, "tjo"); /* test json object aggregate */78}79 80void tearDown(void) {81  if( gDb ){82    sqlite3_close(gDb);83    gDb = NULL;84  }85}86 87/* Basic: two simple name/value pairs */88void test_jsonObjectStep_basic_two_pairs(void){89  exec_sql(gDb, "CREATE TABLE t(name TEXT, val);"90                "INSERT INTO t(rowid,name,val) VALUES "91                "(1,'a',1),(2,'b',2)");92  char *z = eval_sql_text(gDb,93      "SELECT tjo(name, val ORDER BY rowid) FROM t");94  TEST_ASSERT_NOT_NULL(z);95  TEST_ASSERT_EQUAL_STRING("{\"a\":1,\"b\":2}", z);96  sqlite3_free(z);97}98 99/* Skip rows where name is NULL */100void test_jsonObjectStep_skip_null_name(void){101  exec_sql(gDb, "CREATE TABLE t2(name TEXT, val);"102                "INSERT INTO t2(rowid,name,val) VALUES "103                "(1,NULL,99),(2,'x',3)");104  char *z = eval_sql_text(gDb,105      "SELECT tjo(name, val ORDER BY rowid) FROM t2");106  TEST_ASSERT_NOT_NULL(z);107  TEST_ASSERT_EQUAL_STRING("{\"x\":3}", z);108  sqlite3_free(z);109}110 111/* Properly escape quotes and backslashes in the name */112void test_jsonObjectStep_escapes_name_quotes_and_backslash(void){113  exec_sql(gDb, "CREATE TABLE t3(name TEXT, val);"114                "INSERT INTO t3(rowid,name,val) VALUES "115                "(1,'a\"b\\\\c','hi')");116  char *z = eval_sql_text(gDb,117      "SELECT tjo(name, val ORDER BY rowid) FROM t3");118  TEST_ASSERT_NOT_NULL(z);119  TEST_ASSERT_EQUAL_STRING("{\"a\\\"b\\\\c\":\"hi\"}", z);120  sqlite3_free(z);121}122 123/* Value handling: NULL, TEXT (quoted), and JSON-typed (raw) */124void test_jsonObjectStep_value_types_text_null_and_json_subtype(void){125  exec_sql(gDb, "CREATE TABLE t4(name TEXT, val);"126                "INSERT INTO t4(rowid,name,val) VALUES "127                "(1,'n',NULL),"128                "(2,'s','str'),"129                "(3,'j',json('[1,2]'))");130  char *z = eval_sql_text(gDb,131      "SELECT tjo(name, val ORDER BY rowid) FROM t4");132  TEST_ASSERT_NOT_NULL(z);133  TEST_ASSERT_EQUAL_STRING("{\"n\":null,\"s\":\"str\",\"j\":[1,2]}", z);134  sqlite3_free(z);135}136 137/* Error on BLOB values */138void test_jsonObjectStep_error_on_blob_value(void){139  sqlite3_stmt *pStmt = 0;140  int rc = sqlite3_prepare_v2(gDb, "SELECT tjo('x', X'AB')", -1, &pStmt, 0);141  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, sqlite3_errmsg(gDb));142  rc = sqlite3_step(pStmt);143  TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);144  const char *zErr = sqlite3_errmsg(gDb);145  TEST_ASSERT_NOT_NULL(zErr);146  /* The error should mention that JSON cannot hold BLOB values */147  TEST_ASSERT_NOT_NULL(strstr(zErr, "JSON cannot hold BLOB values"));148  sqlite3_finalize(pStmt);149}150 151/* Empty input should produce an empty object {} */152void test_jsonObjectStep_empty_input_returns_empty_object(void){153  char *z = eval_sql_text(gDb, "SELECT tjo(name, val) FROM (SELECT 1 WHERE 0)");154  /* The subselect returns no rows; aggregate finalizer should return "{}" */155  TEST_ASSERT_NOT_NULL(z);156  TEST_ASSERT_EQUAL_STRING("{}", z);157  sqlite3_free(z);158}159 160int main(void){161  UNITY_BEGIN();162  RUN_TEST(test_jsonObjectStep_basic_two_pairs);163  RUN_TEST(test_jsonObjectStep_skip_null_name);164  RUN_TEST(test_jsonObjectStep_escapes_name_quotes_and_backslash);165  RUN_TEST(test_jsonObjectStep_value_types_text_null_and_json_subtype);166  RUN_TEST(test_jsonObjectStep_error_on_blob_value);167  RUN_TEST(test_jsonObjectStep_empty_input_returns_empty_object);168  return UNITY_END();169}