Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonValidFunc.c231 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6 7/* The auto-generated wrapper for the static function under test */8extern void test_jsonValidFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);9 10/* Global database handle used by tests */11static sqlite3 *gDb = NULL;12 13/* SQL function that forwards directly to the target function wrapper */14static void sql_call_jsonValidFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){15  test_jsonValidFunc(ctx, argc, argv);16}17 18/* Helper: run a scalar SELECT and capture column-0 as integer or NULL */19static void runScalar(const char *zSql, int *pIsNull, int *pIntVal){20  sqlite3_stmt *pStmt = 0;21  int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);22  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");23  rc = sqlite3_step(pStmt);24  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "step did not return a row");25  int ctype = sqlite3_column_type(pStmt, 0);26  if( pIsNull ) *pIsNull = (ctype == SQLITE_NULL);27  if( pIntVal ){28    if( ctype == SQLITE_NULL ){29      *pIntVal = 0;30    }else{31      *pIntVal = sqlite3_column_int(pStmt, 0);32    }33  }34  rc = sqlite3_finalize(pStmt);35  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed");36}37 38/* Helper: run SELECT call_jsonValidFunc(?1, ?2) with bound blob and flags */39static void runScalarWithBlobAndFlags(const void *pBlob, int nBlob, int flags,40                                      int *pIsNull, int *pIntVal){41  sqlite3_stmt *pStmt = 0;42  const char *zSql = "SELECT call_jsonValidFunc(?1, ?2)";43  int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);44  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");45  rc = sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_TRANSIENT);46  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "bind blob failed");47  rc = sqlite3_bind_int(pStmt, 2, flags);48  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "bind int failed");49  rc = sqlite3_step(pStmt);50  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "step did not return a row");51  int ctype = sqlite3_column_type(pStmt, 0);52  if( pIsNull ) *pIsNull = (ctype == SQLITE_NULL);53  if( pIntVal ){54    if( ctype == SQLITE_NULL ){55      *pIntVal = 0;56    }else{57      *pIntVal = sqlite3_column_int(pStmt, 0);58    }59  }60  rc = sqlite3_finalize(pStmt);61  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed");62}63 64/* Helper: run statement expecting an SQLITE_ERROR and check message substring */65static void runExpectError(const char *zSql, const char *zSubstr){66  sqlite3_stmt *pStmt = 0;67  int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);68  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");69  rc = sqlite3_step(pStmt);70  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ERROR, rc, "expected SQLITE_ERROR");71  const char *zErr = sqlite3_errmsg(gDb);72  TEST_ASSERT_NOT_NULL_MESSAGE(zErr, "no error message");73  if( zSubstr ){74    TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zErr, zSubstr), "error message mismatch");75  }76  sqlite3_finalize(pStmt);77}78 79void setUp(void) {80  int rc = sqlite3_open(":memory:", &gDb);81  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");82  rc = sqlite3_create_function(gDb, "call_jsonValidFunc", -1, SQLITE_UTF8, NULL,83                               sql_call_jsonValidFunc, NULL, NULL);84  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "create_function failed");85}86 87void tearDown(void) {88  if( gDb ){89    int rc = sqlite3_close(gDb);90    TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_close failed");91    gDb = NULL;92  }93}94 95/* Tests */96 97/* NULL input returns NULL (default FLAGS) */98void test_jsonValidFunc_null_returns_null(void){99  int isNull = 0, val = -1;100  runScalar("SELECT call_jsonValidFunc(NULL)", &isNull, &val);101  TEST_ASSERT_TRUE(isNull);102}103 104/* FLAGS out of range (outside 1..15) raises an error */105void test_jsonValidFunc_flags_out_of_range_error(void){106  runExpectError("SELECT call_jsonValidFunc('null', 16)",107                 "between 1 and 15");108  runExpectError("SELECT call_jsonValidFunc('null', 0)",109                 "between 1 and 15");110}111 112/* Canonical JSON text accepted with default FLAGS (1) */113void test_jsonValidFunc_text_valid_canonical(void){114  int isNull = 0, val = 0;115  runScalar("SELECT call_jsonValidFunc('{\"a\":[1,2,3],\"b\":\"x\"}')", &isNull, &val);116  TEST_ASSERT_FALSE(isNull);117  TEST_ASSERT_EQUAL_INT(1, val);118}119 120/* Malformed JSON text rejected (returns 0) */121void test_jsonValidFunc_text_invalid(void){122  int isNull = 0, val = 1;123  runScalar("SELECT call_jsonValidFunc('{bad json}')", &isNull, &val);124  TEST_ASSERT_FALSE(isNull);125  TEST_ASSERT_EQUAL_INT(0, val);126}127 128/* JSON5 feature (hex integer) requires FLAGS include 0x02 */129void test_jsonValidFunc_json5_integer_requires_flag(void){130  int isNull = 0, val = -1;131  runScalar("SELECT call_jsonValidFunc('0x10')", &isNull, &val);132  TEST_ASSERT_FALSE(isNull);133  TEST_ASSERT_EQUAL_INT(0, val); /* default FLAGS=1 => reject JSON5 */134  runScalar("SELECT call_jsonValidFunc('0x10', 2)", &isNull, &val);135  TEST_ASSERT_FALSE(isNull);136  TEST_ASSERT_EQUAL_INT(1, val); /* FLAGS=2 => accept JSON5 */137}138 139/* BLOB containing text JSON falls through to text parsing if text flags set */140void test_jsonValidFunc_blob_text_fallthrough(void){141  int isNull = 0, val = -1;142  /* CAST('123' AS BLOB) with FLAGS=1 => treated as text JSON => valid */143  runScalar("SELECT call_jsonValidFunc(CAST('123' AS BLOB), 1)", &isNull, &val);144  TEST_ASSERT_FALSE(isNull);145  TEST_ASSERT_EQUAL_INT(1, val);146 147  /* Same input with FLAGS=4 (superficial JSONB only) => not JSONB => 0 */148  runScalar("SELECT call_jsonValidFunc(CAST('123' AS BLOB), 4)", &isNull, &val);149  TEST_ASSERT_FALSE(isNull);150  TEST_ASSERT_EQUAL_INT(0, val);151}152 153/* Valid JSONB BLOB: superficial and strict checks */154void test_jsonValidFunc_blob_jsonb_superficial_and_strict(void){155  int isNull = 0, val = -1;156 157  /* Superficial JSONB validation passes */158  runScalar("SELECT call_jsonValidFunc(jsonb('{\"x\":1}'), 4)", &isNull, &val);159  TEST_ASSERT_FALSE(isNull);160  TEST_ASSERT_EQUAL_INT(1, val);161 162  /* Strict JSONB validation passes */163  runScalar("SELECT call_jsonValidFunc(jsonb('{\"x\":1}'), 8)", &isNull, &val);164  TEST_ASSERT_FALSE(isNull);165  TEST_ASSERT_EQUAL_INT(1, val);166 167  /* With only text flags (1), JSONB BLOB is not accepted => 0 */168  runScalar("SELECT call_jsonValidFunc(jsonb('{\"x\":1}'), 1)", &isNull, &val);169  TEST_ASSERT_FALSE(isNull);170  TEST_ASSERT_EQUAL_INT(0, val);171 172  /* Combined flags including superficial (5 = 1|4) => accept */173  runScalar("SELECT call_jsonValidFunc(jsonb('{\"x\":1}'), 5)", &isNull, &val);174  TEST_ASSERT_FALSE(isNull);175  TEST_ASSERT_EQUAL_INT(1, val);176 177  /* Combined flags including strict (9 = 1|8) => accept */178  runScalar("SELECT call_jsonValidFunc(jsonb('{\"x\":1}'), 9)", &isNull, &val);179  TEST_ASSERT_FALSE(isNull);180  TEST_ASSERT_EQUAL_INT(1, val);181}182 183/* Superficially valid but strictly invalid JSONB BLOB */184void test_jsonValidFunc_blob_superficial_accept_strict_reject(void){185  /* Construct a JSONB blob:186     - Top-level: ARRAY with extended 1-byte size header (0xCB) and payload size 8187       (header bytes: 0xCB, 0x08)188     - Payload: 8 bytes beginning with 0xF0 (type=NULL with 8-byte size field).189       This makes inner element header require 9 bytes, but only 8 bytes of payload190       exist. Superficial check succeeds (outer size matches), strict check fails. */191  unsigned char blob[10];192  blob[0] = 0xCB;  /* high nibble 12 => 1-byte size; low nibble 11 => ARRAY */193  blob[1] = 0x08;  /* payload size = 8 */194  blob[2] = 0xF0;  /* inner element: type NULL (0) with 8-byte size field indicated */195  /* Fill the remaining 7 bytes with zeros */196  for(int i=3; i<10; i++) blob[i] = 0x00;197 198  int isNull = 0, val = -1;199 200  /* Superficial JSONB validation: should return 1 */201  runScalarWithBlobAndFlags(blob, (int)sizeof(blob), 4, &isNull, &val);202  TEST_ASSERT_FALSE(isNull);203  TEST_ASSERT_EQUAL_INT(1, val);204 205  /* Strict JSONB validation: should return 0 */206  runScalarWithBlobAndFlags(blob, (int)sizeof(blob), 8, &isNull, &val);207  TEST_ASSERT_FALSE(isNull);208  TEST_ASSERT_EQUAL_INT(0, val);209 210  /* Combined strict or superficial flags behave accordingly */211  runScalarWithBlobAndFlags(blob, (int)sizeof(blob), 5, &isNull, &val); /* includes superficial */212  TEST_ASSERT_FALSE(isNull);213  TEST_ASSERT_EQUAL_INT(1, val);214 215  runScalarWithBlobAndFlags(blob, (int)sizeof(blob), 9, &isNull, &val); /* includes strict */216  TEST_ASSERT_FALSE(isNull);217  TEST_ASSERT_EQUAL_INT(0, val);218}219 220int main(void){221  UNITY_BEGIN();222  RUN_TEST(test_jsonValidFunc_null_returns_null);223  RUN_TEST(test_jsonValidFunc_flags_out_of_range_error);224  RUN_TEST(test_jsonValidFunc_text_valid_canonical);225  RUN_TEST(test_jsonValidFunc_text_invalid);226  RUN_TEST(test_jsonValidFunc_json5_integer_requires_flag);227  RUN_TEST(test_jsonValidFunc_blob_text_fallthrough);228  RUN_TEST(test_jsonValidFunc_blob_jsonb_superficial_and_strict);229  RUN_TEST(test_jsonValidFunc_blob_superficial_accept_strict_reject);230  return UNITY_END();231}