Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonReturnString.c327 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* The target under test is static, use the provided wrapper */8void test_jsonReturnString(JsonString *p, JsonParse *pParse, sqlite3_context *ctx);9 10/* Global database handle for tests */11static sqlite3 *gDb = NULL;12 13/* Helper: Prepare, step once, and finalize statement. Returns step rc. */14static int step_sql(const char *zSql, sqlite3_stmt **ppStmt){15  sqlite3_stmt *pStmt = NULL;16  int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);17  if( rc!=SQLITE_OK ){18    if( ppStmt ) *ppStmt = NULL;19    return rc;20  }21  rc = sqlite3_step(pStmt);22  if( ppStmt ){23    *ppStmt = pStmt;24  }else{25    sqlite3_finalize(pStmt);26  }27  return rc;28}29 30/* UDF: Return small text using static buffer path (bStatic=1), no caching. */31static void ut_jsonReturnString_text_small(sqlite3_context *ctx, int argc, sqlite3_value **argv){32  (void)argc;33  const unsigned char *zArg = sqlite3_value_text(argv[0]);34  int nArg = sqlite3_value_bytes(argv[0]);35  /* Construct JsonString using static buffer */36  JsonString js;37  memset(&js, 0, sizeof(js));38  js.pCtx = ctx;39  js.eErr = 0;40  js.bStatic = 1;41  js.zBuf = js.zSpace;42  js.nAlloc = (u32)sizeof(js.zSpace);43  if( (u32)nArg > js.nAlloc ){44    sqlite3_result_error(ctx, "argument too large for static buffer test", -1);45    return;46  }47  memcpy(js.zSpace, zArg, (size_t)nArg);48  js.nUsed = (u32)nArg;49 50  /* Per jsonReturnString assert: pass pParse==NULL => ctx==NULL */51  test_jsonReturnString(&js, NULL, NULL);52  /* Result already set by jsonReturnString */53}54 55/* UDF: Return large text using dynamic buffer path (bStatic=0), no caching. */56static void ut_jsonReturnString_text_large(sqlite3_context *ctx, int argc, sqlite3_value **argv){57  (void)argc;58  int n = 1000; /* ensure dynamic path */59  const char fill = 'x';60  char *zDyn = (char*)sqlite3RCStrNew((u64)n+1);61  if( zDyn==0 ){62    sqlite3_result_error_nomem(ctx);63    return;64  }65  memset(zDyn, fill, (size_t)n);66  zDyn[n] = 0;67 68  JsonString js;69  memset(&js, 0, sizeof(js));70  js.pCtx = ctx;71  js.eErr = 0;72  js.bStatic = 0;73  js.zBuf = zDyn;74  js.nAlloc = (u32)(n+1);75  js.nUsed = (u32)n;76 77  /* pParse==NULL => ctx==NULL (for assertion) */78  test_jsonReturnString(&js, NULL, NULL);79  /* Result already set */80}81 82/* UDF: JSON_BLOB flag set: convert valid text JSON input to JSONB blob. */83static void ut_jsonReturnString_blob(sqlite3_context *ctx, int argc, sqlite3_value **argv){84  (void)argc;85  const unsigned char *zArg = sqlite3_value_text(argv[0]);86  int nArg = sqlite3_value_bytes(argv[0]);87 88  /* Construct using dynamic buffer (not necessary, but fine) */89  char *zDyn = (char*)sqlite3RCStrNew((u64)nArg+1);90  if( zDyn==0 ){91    sqlite3_result_error_nomem(ctx);92    return;93  }94  memcpy(zDyn, zArg, (size_t)nArg);95  zDyn[nArg] = 0;96 97  JsonString js;98  memset(&js, 0, sizeof(js));99  js.pCtx = ctx;100  js.eErr = 0;101  js.bStatic = 0;102  js.zBuf = zDyn;103  js.nAlloc = (u32)(nArg+1);104  js.nUsed = (u32)nArg;105 106  /* The JSON_BLOB flag is taken from sqlite3_user_data(js.pCtx).107  ** Here we simply call; the flag is supplied when registering the SQL function.108  ** pParse==NULL => ctx==NULL per assertion. */109  test_jsonReturnString(&js, NULL, NULL);110}111 112/* UDF: Exercise caching branch: pParse!=NULL and ctx!=NULL and bStatic==0. 113** Returns 1 if cache insert and fields look correct; else returns 0. */114static void ut_jsonReturnString_cachecheck(sqlite3_context *ctx, int argc, sqlite3_value **argv){115  (void)argc;116  /* Create a long string to force dynamic buffer */117  int n = 400;118  char *zDyn = (char*)sqlite3RCStrNew((u64)n+1);119  if( zDyn==0 ){120    sqlite3_result_error_nomem(ctx);121    return;122  }123  for(int i=0;i<n;i++) zDyn[i] = 'A' + (i%26);124  zDyn[n] = 0;125 126  JsonString js;127  memset(&js, 0, sizeof(js));128  js.pCtx = ctx;129  js.eErr = 0;130  js.bStatic = 0;131  js.zBuf = zDyn;132  js.nAlloc = (u32)(n+1);133  js.nUsed = (u32)n;134 135  JsonParse px;136  memset(&px, 0, sizeof(px));137  px.nBlobAlloc = 1; /* non-zero to enable caching path */138 139  /* Now call with pParse!=NULL and ctx!=NULL for caching */140  test_jsonReturnString(&js, &px, ctx);141 142  /* Verify px got updated and cache was inserted, and js reset */143  int ok = 1;144  if( px.bJsonIsRCStr==0 ) ok = 0;145  if( px.zJson==0 ) ok = 0;146  if( (int)px.nJson != n ) ok = 0;147 148  JsonCache *pCache = (JsonCache*)sqlite3_get_auxdata(ctx, JSON_CACHE_ID);149  if( pCache==0 ) ok = 0;150  else{151    if( pCache->nUsed==0 ) ok = 0;152    else if( pCache->a[pCache->nUsed-1] != &px ) ok = 0;153  }154 155  /* jsonReturnString should have reset the JsonString */156  if( js.bStatic!=1 || js.nUsed!=0 || js.zBuf!=js.zSpace ) ok = 0;157 158  sqlite3_result_int(ctx, ok);159}160 161/* UDF: Force malformed error path. */162static void ut_jsonReturnString_errMalformed(sqlite3_context *ctx, int argc, sqlite3_value **argv){163  (void)argc; (void)argv;164  JsonString js;165  memset(&js, 0, sizeof(js));166  js.pCtx = ctx;167  js.eErr = JSTRING_MALFORMED;168  js.bStatic = 1;169  js.zBuf = js.zSpace;170  js.nAlloc = (u32)sizeof(js.zSpace);171  js.nUsed = 0;172  /* pParse==NULL, ctx==NULL for assertion */173  test_jsonReturnString(&js, NULL, NULL);174}175 176/* UDF: Force OOM error path. */177static void ut_jsonReturnString_errOOM(sqlite3_context *ctx, int argc, sqlite3_value **argv){178  (void)argc; (void)argv;179  JsonString js;180  memset(&js, 0, sizeof(js));181  js.pCtx = ctx;182  js.eErr = JSTRING_OOM;183  js.bStatic = 1;184  js.zBuf = js.zSpace;185  js.nAlloc = (u32)sizeof(js.zSpace);186  js.nUsed = 0;187  /* pParse==NULL, ctx==NULL for assertion */188  test_jsonReturnString(&js, NULL, NULL);189}190 191void setUp(void) {192  int rc = sqlite3_open(":memory:", &gDb);193  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);194 195  /* Register UDFs. Note: pApp sets sqlite3_user_data, used for flags in jsonReturnString. */196  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_text_small", 1, SQLITE_UTF8, NULL,197                               ut_jsonReturnString_text_small, NULL, NULL);198  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);199 200  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_text_large", 0, SQLITE_UTF8, NULL,201                               ut_jsonReturnString_text_large, NULL, NULL);202  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);203 204  /* Register blob version with JSON_BLOB flag in user_data */205  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_blob", 1, SQLITE_UTF8,206                               (void*)(uintptr_t)JSON_BLOB,207                               ut_jsonReturnString_blob, NULL, NULL);208  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);209 210  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_cachecheck", 0, SQLITE_UTF8, NULL,211                               ut_jsonReturnString_cachecheck, NULL, NULL);212  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);213 214  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_errMalformed", 0, SQLITE_UTF8, NULL,215                               ut_jsonReturnString_errMalformed, NULL, NULL);216  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);217 218  rc = sqlite3_create_function(gDb, "ut_jsonReturnString_errOOM", 0, SQLITE_UTF8, NULL,219                               ut_jsonReturnString_errOOM, NULL, NULL);220  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);221}222 223void tearDown(void) {224  if( gDb ){225    sqlite3_close(gDb);226    gDb = NULL;227  }228}229 230/* Test: static buffer path returns correct text. */231static void test_jsonReturnString_text_small_static(void){232  sqlite3_stmt *pStmt = NULL;233  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_text_small(?)", -1, &pStmt, 0);234  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);235  rc = sqlite3_bind_text(pStmt, 1, "hello", -1, SQLITE_STATIC);236  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);237  rc = sqlite3_step(pStmt);238  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);239  TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_column_type(pStmt, 0));240  const unsigned char *z = sqlite3_column_text(pStmt, 0);241  TEST_ASSERT_NOT_NULL(z);242  TEST_ASSERT_EQUAL_STRING("hello", (const char*)z);243  sqlite3_finalize(pStmt);244}245 246/* Test: dynamic buffer path returns correct large text length. */247static void test_jsonReturnString_text_large_dynamic(void){248  sqlite3_stmt *pStmt = NULL;249  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_text_large()", -1, &pStmt, 0);250  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);251  rc = sqlite3_step(pStmt);252  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);253  TEST_ASSERT_EQUAL_INT(SQLITE_TEXT, sqlite3_column_type(pStmt, 0));254  const unsigned char *z = sqlite3_column_text(pStmt, 0);255  int n = sqlite3_column_bytes(pStmt, 0);256  TEST_ASSERT_NOT_NULL(z);257  TEST_ASSERT_EQUAL_INT(1000, n);258  /* Optional: ensure it's the expected pattern */259  TEST_ASSERT_EQUAL_INT('x', z[0]);260  TEST_ASSERT_EQUAL_INT('x', z[999]);261  sqlite3_finalize(pStmt);262}263 264/* Test: JSON_BLOB flag produces a BLOB result. */265static void test_jsonReturnString_blob_flag(void){266  sqlite3_stmt *pStmt = NULL;267  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_blob('[1,2,3]')", -1, &pStmt, 0);268  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);269  rc = sqlite3_step(pStmt);270  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);271  TEST_ASSERT_EQUAL_INT(SQLITE_BLOB, sqlite3_column_type(pStmt, 0));272  const void *pBlob = sqlite3_column_blob(pStmt, 0);273  int nBlob = sqlite3_column_bytes(pStmt, 0);274  TEST_ASSERT_NOT_NULL(pBlob);275  TEST_ASSERT_MESSAGE(nBlob>0, "JSONB blob should be non-empty");276  sqlite3_finalize(pStmt);277}278 279/* Test: caching branch sets auxdata and updates JsonParse; function returns 1. */280static void test_jsonReturnString_cache_insert(void){281  sqlite3_stmt *pStmt = NULL;282  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_cachecheck()", -1, &pStmt, 0);283  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);284  rc = sqlite3_step(pStmt);285  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);286  TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_column_type(pStmt, 0));287  int ok = sqlite3_column_int(pStmt, 0);288  TEST_ASSERT_EQUAL_INT(1, ok);289  sqlite3_finalize(pStmt);290}291 292/* Test: malformed error path returns SQLITE_ERROR with expected message. */293static void test_jsonReturnString_error_malformed(void){294  sqlite3_stmt *pStmt = NULL;295  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_errMalformed()", -1, &pStmt, 0);296  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);297  rc = sqlite3_step(pStmt);298  TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);299  const char *zErr = sqlite3_errmsg(gDb);300  TEST_ASSERT_NOT_NULL(zErr);301  TEST_ASSERT_MESSAGE(strstr(zErr, "malformed JSON")!=NULL, "Expected 'malformed JSON' in error message");302  sqlite3_finalize(pStmt);303}304 305/* Test: OOM error path sets NOMEM error code. */306static void test_jsonReturnString_error_oom(void){307  sqlite3_stmt *pStmt = NULL;308  int rc = sqlite3_prepare_v2(gDb, "SELECT ut_jsonReturnString_errOOM()", -1, &pStmt, 0);309  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);310  rc = sqlite3_step(pStmt);311  /* step generally returns SQLITE_ERROR, but db errcode should be SQLITE_NOMEM */312  TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);313  int ec = sqlite3_errcode(gDb);314  TEST_ASSERT_EQUAL_INT(SQLITE_NOMEM, ec);315  sqlite3_finalize(pStmt);316}317 318int main(void){319  UNITY_BEGIN();320  RUN_TEST(test_jsonReturnString_text_small_static);321  RUN_TEST(test_jsonReturnString_text_large_dynamic);322  RUN_TEST(test_jsonReturnString_blob_flag);323  RUN_TEST(test_jsonReturnString_cache_insert);324  RUN_TEST(test_jsonReturnString_error_malformed);325  RUN_TEST(test_jsonReturnString_error_oom);326  return UNITY_END();327}