Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonReturnParse.c226 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdint.h>5 6/* External wrapper for the static function under test */7void test_jsonReturnParse(sqlite3_context *ctx, JsonParse *p);8 9static sqlite3 *gDb = NULL;10 11/* Minimal JSONB encoding helper:12   A single TRUE element: header byte = 0x01 (payload size 0, type TRUE) */13static unsigned char jsonb_true_header_byte(void){14  return (unsigned char)0x01;15}16 17void setUp(void) {18  int rc = sqlite3_open(":memory:", &gDb);19  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory SQLite DB");20  TEST_ASSERT_NOT_NULL(gDb);21}22 23void tearDown(void) {24  if( gDb ){25    sqlite3_close(gDb);26    gDb = NULL;27  }28}29 30/* Callback: Return TEXT result (flags=0) via jsonReturnParse from JSONB TRUE */31static void cb_json_return_text(sqlite3_context *ctx, int argc, sqlite3_value **argv){32  (void)argc; (void)argv;33  JsonParse p;34  memset(&p, 0, sizeof(p));35  unsigned char *a = (unsigned char*)sqlite3_malloc(1);36  TEST_ASSERT_NOT_NULL(a);37  a[0] = jsonb_true_header_byte();38  p.aBlob = a;39  p.nBlob = 1;40  p.nBlobAlloc = 0;     /* Not handing ownership to SQLite in text path */41  p.bReadOnly = 0;42  p.oom = 0;43 44  test_jsonReturnParse(ctx, &p);45 46  /* Since text path does not consume/own the blob memory, free it here */47  sqlite3_free(a);48}49 50/* Callback: Return BLOB with SQLITE_DYNAMIC (nBlobAlloc>0 && !bReadOnly)51   Verify that p.nBlobAlloc is cleared to 0 */52static void cb_json_return_blob_dynamic(sqlite3_context *ctx, int argc, sqlite3_value **argv){53  (void)argc; (void)argv;54  JsonParse p;55  memset(&p, 0, sizeof(p));56  unsigned char *a = (unsigned char*)sqlite3_malloc(1);57  TEST_ASSERT_NOT_NULL(a);58  a[0] = jsonb_true_header_byte();59  p.aBlob = a;60  p.nBlob = 1;61  p.nBlobAlloc = 8;   /* >0 signals caller-allocated buffer; allows SQLITE_DYNAMIC path */62  p.bReadOnly = 0;    /* Allow SQLITE_DYNAMIC and clearing nBlobAlloc */63  p.oom = 0;64 65  test_jsonReturnParse(ctx, &p);66 67  TEST_ASSERT_EQUAL_INT_MESSAGE(0, p.nBlobAlloc, "nBlobAlloc should be cleared to 0 after SQLITE_DYNAMIC result");68  /* Do not free 'a' here; ownership transferred to SQLite via SQLITE_DYNAMIC */69}70 71/* Callback: Return BLOB with SQLITE_TRANSIENT (bReadOnly==1)72   Verify that p.nBlobAlloc is unchanged (>0) and then free memory locally */73static void cb_json_return_blob_readonly(sqlite3_context *ctx, int argc, sqlite3_value **argv){74  (void)argc; (void)argv;75  JsonParse p;76  memset(&p, 0, sizeof(p));77  unsigned char *a = (unsigned char*)sqlite3_malloc(1);78  TEST_ASSERT_NOT_NULL(a);79  a[0] = jsonb_true_header_byte();80  p.aBlob = a;81  p.nBlob = 1;82  p.nBlobAlloc = 16;  /* >0 */83  p.bReadOnly = 1;    /* Forces SQLITE_TRANSIENT */84  p.oom = 0;85 86  test_jsonReturnParse(ctx, &p);87 88  TEST_ASSERT_TRUE_MESSAGE(p.nBlobAlloc > 0, "nBlobAlloc should remain >0 when using SQLITE_TRANSIENT");89  /* Since SQLITE_TRANSIENT copies the data, we must free our allocation */90  sqlite3_free(a);91}92 93/* Callback: Force OOM path */94static void cb_json_return_oom(sqlite3_context *ctx, int argc, sqlite3_value **argv){95  (void)argc; (void)argv;96  JsonParse p;97  memset(&p, 0, sizeof(p));98  p.oom = 1;99  test_jsonReturnParse(ctx, &p);100}101 102/* Test: Text path yields "true" with JSON subtype */103void test_jsonReturnParse_returns_text_true_with_json_subtype(void){104  int rc;105  sqlite3_stmt *stmt = NULL;106 107  rc = sqlite3_create_function(gDb, "f_text", 0, SQLITE_UTF8,108                               (void*)(intptr_t)0 /* flags: no JSON_BLOB */,109                               cb_json_return_text, 0, 0);110  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 112  rc = sqlite3_prepare_v2(gDb, "SELECT f_text()", -1, &stmt, 0);113  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);114 115  rc = sqlite3_step(stmt);116  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);117 118  int ctype = sqlite3_column_type(stmt, 0);119  TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, ctype);120 121  int subtype = sqlite3_column_subtype(stmt, 0);122  TEST_ASSERT_EQUAL_INT(JSON_SUBTYPE, subtype);123 124  const unsigned char *txt = sqlite3_column_text(stmt, 0);125  int n = sqlite3_column_bytes(stmt, 0);126  TEST_ASSERT_NOT_NULL(txt);127  TEST_ASSERT_EQUAL_INT(4, n);128  TEST_ASSERT_EQUAL_INT(0, memcmp(txt, "true", 4));129 130  rc = sqlite3_finalize(stmt);131  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);132}133 134/* Test: Blob path with dynamic ownership returns a 1-byte blob {0x01} and clears nBlobAlloc */135void test_jsonReturnParse_returns_blob_and_clears_alloc_on_dynamic(void){136  int rc;137  sqlite3_stmt *stmt = NULL;138 139  rc = sqlite3_create_function(gDb, "f_blob_dyn", 0, SQLITE_UTF8,140                               (void*)(intptr_t)JSON_BLOB /* flags include JSON_BLOB */,141                               cb_json_return_blob_dynamic, 0, 0);142  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);143 144  rc = sqlite3_prepare_v2(gDb, "SELECT f_blob_dyn()", -1, &stmt, 0);145  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);146 147  rc = sqlite3_step(stmt);148  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);149 150  int ctype = sqlite3_column_type(stmt, 0);151  TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, ctype);152 153  const void *blob = sqlite3_column_blob(stmt, 0);154  int n = sqlite3_column_bytes(stmt, 0);155  TEST_ASSERT_NOT_NULL(blob);156  TEST_ASSERT_EQUAL_INT(1, n);157  const unsigned char *b = (const unsigned char*)blob;158  TEST_ASSERT_EQUAL_UINT8(jsonb_true_header_byte(), b[0]);159 160  rc = sqlite3_finalize(stmt);161  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);162}163 164/* Test: Blob path with read-only buffer returns same 1-byte blob and does not clear nBlobAlloc */165void test_jsonReturnParse_returns_blob_and_preserves_alloc_on_readonly(void){166  int rc;167  sqlite3_stmt *stmt = NULL;168 169  rc = sqlite3_create_function(gDb, "f_blob_ro", 0, SQLITE_UTF8,170                               (void*)(intptr_t)JSON_BLOB /* flags include JSON_BLOB */,171                               cb_json_return_blob_readonly, 0, 0);172  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);173 174  rc = sqlite3_prepare_v2(gDb, "SELECT f_blob_ro()", -1, &stmt, 0);175  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);176 177  rc = sqlite3_step(stmt);178  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);179 180  int ctype = sqlite3_column_type(stmt, 0);181  TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, ctype);182 183  const void *blob = sqlite3_column_blob(stmt, 0);184  int n = sqlite3_column_bytes(stmt, 0);185  TEST_ASSERT_NOT_NULL(blob);186  TEST_ASSERT_EQUAL_INT(1, n);187  const unsigned char *b = (const unsigned char*)blob;188  TEST_ASSERT_EQUAL_UINT8(jsonb_true_header_byte(), b[0]);189 190  rc = sqlite3_finalize(stmt);191  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);192}193 194/* Test: OOM path sets an error (sqlite3_result_error_nomem) */195void test_jsonReturnParse_oom_sets_error_nomem(void){196  int rc;197  sqlite3_stmt *stmt = NULL;198 199  rc = sqlite3_create_function(gDb, "f_oom", 0, SQLITE_UTF8,200                               (void*)(intptr_t)0,201                               cb_json_return_oom, 0, 0);202  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);203 204  rc = sqlite3_prepare_v2(gDb, "SELECT f_oom()", -1, &stmt, 0);205  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);206 207  rc = sqlite3_step(stmt);208  TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);209 210  const char *errmsg = sqlite3_errmsg(gDb);211  TEST_ASSERT_NOT_NULL(errmsg);212  /* Ensure the message contains "out of memory" (sqlite3_result_error_nomem) */213  TEST_ASSERT_NOT_NULL_MESSAGE(strstr(errmsg, "out of memory"), "Error message should contain 'out of memory'");214 215  rc = sqlite3_finalize(stmt);216  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);217}218 219int main(void) {220  UNITY_BEGIN();221  RUN_TEST(test_jsonReturnParse_returns_text_true_with_json_subtype);222  RUN_TEST(test_jsonReturnParse_returns_blob_and_clears_alloc_on_dynamic);223  RUN_TEST(test_jsonReturnParse_returns_blob_and_preserves_alloc_on_readonly);224  RUN_TEST(test_jsonReturnParse_oom_sets_error_nomem);225  return UNITY_END();226}