AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <math.h>6 7/* Wrapper provided in module */8int test_jsonFunctionArgToBlob(sqlite3_context *ctx, sqlite3_value *pArg, JsonParse *pParse);9 10static sqlite3 *gDb = NULL;11 12static void init_context(sqlite3 *db, sqlite3_context *pCtx, Mem *pOut){13 memset(pCtx, 0, sizeof(*pCtx));14 sqlite3VdbeMemInit(pOut, db, 0);15 pCtx->pOut = pOut;16}17 18static void cleanup_context_out(Mem *pOut){19 sqlite3VdbeMemRelease(pOut);20 memset(pOut, 0, sizeof(*pOut));21}22 23void setUp(void) {24 if( gDb==NULL ){25 int rc = sqlite3_open(":memory:", &gDb);26 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);27 }28}29void tearDown(void) {30 /* Keep db open across tests; close in main after Unity_END */31}32 33/* Helper to free JsonParse->aBlob if it was allocated */34static void free_parse_blob(JsonParse *p){35 if( p && p->nBlobAlloc>0 && p->aBlob ){36 sqlite3DbFree(p->db, p->aBlob);37 p->aBlob = NULL;38 p->nBlob = 0;39 p->nBlobAlloc = 0;40 }41}42 43/* Test: default branch (e.g., NULL argument) -> JSONB NULL single byte */44void test_jsonFunctionArgToBlob_null_input(void){45 sqlite3_context ctx;46 Mem out;47 init_context(gDb, &ctx, &out);48 49 sqlite3_value *v = sqlite3ValueNew(gDb);50 /* v is NULL by default, or explicitly: */51 sqlite3VdbeMemSetNull((Mem*)v);52 53 JsonParse p;54 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);55 56 TEST_ASSERT_EQUAL_INT(0, rc);57 TEST_ASSERT_EQUAL_PTR(gDb, p.db);58 TEST_ASSERT_EQUAL_UINT32(1u, p.nBlob);59 TEST_ASSERT_NOT_NULL(p.aBlob);60 /* JSONB NULL is type 0 with zero payload -> first byte is 0x00 */61 TEST_ASSERT_EQUAL_HEX8(0x00, p.aBlob[0]);62 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlobAlloc); /* should not be allocated */63 64 sqlite3ValueFree(v);65 cleanup_context_out(&out);66}67 68/* Test: BLOB not JSONB -> error and return 1 */69void test_jsonFunctionArgToBlob_blob_not_jsonb_errors(void){70 sqlite3_context ctx;71 Mem out;72 init_context(gDb, &ctx, &out);73 74 static const char blobData[] = "abc";75 sqlite3_value *v = sqlite3ValueNew(gDb);76 sqlite3VdbeMemSetStr((Mem*)v, blobData, (int)sizeof(blobData)-1, 0 /*enc=0 => BLOB*/, SQLITE_STATIC);77 78 JsonParse p;79 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);80 81 TEST_ASSERT_EQUAL_INT(1, rc);82 TEST_ASSERT_NULL(p.aBlob);83 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);84 /* Check error message */85 const unsigned char *zErr = sqlite3_value_text((sqlite3_value*)&out);86 TEST_ASSERT_NOT_NULL(zErr);87 TEST_ASSERT_NOT_EQUAL(-1, (int)sqlite3StrlikeCompare((const char*)zErr, "JSON cannot hold BLOB values", 0));88 89 sqlite3ValueFree(v);90 cleanup_context_out(&out);91}92 93/* Test: BLOB valid JSONB (single 0x00 byte) -> accepted, no copy */94void test_jsonFunctionArgToBlob_blob_jsonb_accepted(void){95 sqlite3_context ctx;96 Mem out;97 init_context(gDb, &ctx, &out);98 99 static const unsigned char jsonbNull[] = { 0x00 };100 sqlite3_value *v = sqlite3ValueNew(gDb);101 sqlite3VdbeMemSetStr((Mem*)v, jsonbNull, 1, 0 /*blob*/, SQLITE_STATIC);102 103 /* Capture pointer to underlying blob for later pointer equality check */104 const void *valBlobPtr = sqlite3_value_blob(v);105 106 JsonParse p;107 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);108 109 TEST_ASSERT_EQUAL_INT(0, rc);110 TEST_ASSERT_EQUAL_UINT32(1u, p.nBlob);111 TEST_ASSERT_EQUAL_PTR(valBlobPtr, (const void*)p.aBlob);112 TEST_ASSERT_EQUAL_HEX8(0x00, p.aBlob[0]);113 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlobAlloc); /* borrowed memory */114 115 sqlite3ValueFree(v);116 cleanup_context_out(&out);117}118 119/* Test: TEXT without JSON subtype => TEXTRAW with payload */120void test_jsonFunctionArgToBlob_text_raw_textraw_encoding(void){121 sqlite3_context ctx;122 Mem out;123 init_context(gDb, &ctx, &out);124 125 const char *txt = "hello";126 const int n = (int)strlen(txt);127 128 sqlite3_value *v = sqlite3ValueNew(gDb);129 sqlite3VdbeMemSetStr((Mem*)v, txt, n, SQLITE_UTF8, SQLITE_STATIC);130 131 JsonParse p;132 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);133 134 TEST_ASSERT_EQUAL_INT(0, rc);135 TEST_ASSERT_NOT_NULL(p.aBlob);136 TEST_ASSERT_TRUE(p.nBlob >= 1u + (unsigned)n);137 /* First byte: type JSONB_TEXTRAW | (n<<4) if n<=11 */138 TEST_ASSERT_LESS_OR_EQUAL(11, n); /* ensure small payload path; n=5 OK */139 TEST_ASSERT_EQUAL_HEX8((JSONB_TEXTRAW | (n<<4)), p.aBlob[0]);140 TEST_ASSERT_EQUAL_UINT32((unsigned)(1 + n), p.nBlob);141 TEST_ASSERT_EQUAL_MEMORY(txt, p.aBlob+1, (size_t)n);142 TEST_ASSERT_TRUE(p.nBlobAlloc > 0);143 144 free_parse_blob(&p);145 sqlite3ValueFree(v);146 cleanup_context_out(&out);147}148 149/* Test: TEXT with JSON subtype "null" => JSONB NULL */150void test_jsonFunctionArgToBlob_text_jsonsubtype_valid_null(void){151 sqlite3_context ctx;152 Mem out;153 init_context(gDb, &ctx, &out);154 155 const char *txt = "null";156 sqlite3_value *v = sqlite3ValueNew(gDb);157 sqlite3VdbeMemSetStr((Mem*)v, txt, (int)strlen(txt), SQLITE_UTF8, SQLITE_STATIC);158 sqlite3VdbeMemSetSubtype((Mem*)v, JSON_SUBTYPE);159 160 JsonParse p;161 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);162 163 TEST_ASSERT_EQUAL_INT(0, rc);164 TEST_ASSERT_NOT_NULL(p.aBlob);165 TEST_ASSERT_EQUAL_UINT32(1u, p.nBlob);166 TEST_ASSERT_EQUAL_HEX8(0x00, p.aBlob[0]); /* JSONB NULL */167 168 free_parse_blob(&p);169 sqlite3ValueFree(v);170 cleanup_context_out(&out);171}172 173/* Test: TEXT with JSON subtype malformed => error */174void test_jsonFunctionArgToBlob_text_jsonsubtype_malformed_error(void){175 sqlite3_context ctx;176 Mem out;177 init_context(gDb, &ctx, &out);178 179 const char *txt = "x"; /* malformed JSON */180 sqlite3_value *v = sqlite3ValueNew(gDb);181 sqlite3VdbeMemSetStr((Mem*)v, txt, (int)strlen(txt), SQLITE_UTF8, SQLITE_STATIC);182 sqlite3VdbeMemSetSubtype((Mem*)v, JSON_SUBTYPE);183 184 JsonParse p;185 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);186 187 TEST_ASSERT_EQUAL_INT(1, rc);188 /* pParse reset to empty on error */189 TEST_ASSERT_NULL(p.aBlob);190 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);191 /* confirm error message */192 const unsigned char *zErr = sqlite3_value_text((sqlite3_value*)&out);193 TEST_ASSERT_NOT_NULL(zErr);194 TEST_ASSERT_NOT_EQUAL(-1, (int)sqlite3StrlikeCompare((const char*)zErr, "malformed JSON", 0));195 196 sqlite3ValueFree(v);197 cleanup_context_out(&out);198}199 200/* Test: FLOAT finite => JSONB_FLOAT with textual payload */201void test_jsonFunctionArgToBlob_float_finite(void){202 sqlite3_context ctx;203 Mem out;204 init_context(gDb, &ctx, &out);205 206 sqlite3_value *v = sqlite3ValueNew(gDb);207 sqlite3VdbeMemSetDouble((Mem*)v, 1.25);208 209 /* Capture expected textual representation before calling */210 const unsigned char *zExp = sqlite3_value_text(v);211 int nExp = sqlite3_value_bytes(v);212 TEST_ASSERT_NOT_NULL(zExp);213 TEST_ASSERT_TRUE(nExp > 0 && nExp <= 11); /* ensure small-header path */214 215 JsonParse p;216 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);217 218 TEST_ASSERT_EQUAL_INT(0, rc);219 TEST_ASSERT_NOT_NULL(p.aBlob);220 TEST_ASSERT_EQUAL_UINT32((unsigned)(1 + nExp), p.nBlob);221 TEST_ASSERT_EQUAL_HEX8((JSONB_FLOAT | (nExp<<4)), p.aBlob[0]);222 TEST_ASSERT_EQUAL_MEMORY(zExp, p.aBlob+1, (size_t)nExp);223 224 free_parse_blob(&p);225 sqlite3ValueFree(v);226 cleanup_context_out(&out);227}228 229/* Test: FLOAT NaN => JSONB NULL */230void test_jsonFunctionArgToBlob_float_nan_becomes_null(void){231 sqlite3_context ctx;232 Mem out;233 init_context(gDb, &ctx, &out);234 235 sqlite3_value *v = sqlite3ValueNew(gDb);236 double x = NAN;237 sqlite3VdbeMemSetDouble((Mem*)v, x);238 239 JsonParse p;240 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);241 242 TEST_ASSERT_EQUAL_INT(0, rc);243 TEST_ASSERT_NOT_NULL(p.aBlob);244 TEST_ASSERT_EQUAL_UINT32(1u, p.nBlob);245 TEST_ASSERT_EQUAL_HEX8(0x00, p.aBlob[0]); /* JSONB NULL */246 247 free_parse_blob(&p);248 sqlite3ValueFree(v);249 cleanup_context_out(&out);250}251 252/* Test: INTEGER => JSONB_INT with textual payload */253void test_jsonFunctionArgToBlob_integer_basic(void){254 sqlite3_context ctx;255 Mem out;256 init_context(gDb, &ctx, &out);257 258 sqlite3_value *v = sqlite3ValueNew(gDb);259 sqlite3VdbeMemSetInt64((Mem*)v, 12345);260 261 /* Capture expected textual representation */262 const unsigned char *zExp = sqlite3_value_text(v);263 int nExp = sqlite3_value_bytes(v);264 TEST_ASSERT_NOT_NULL(zExp);265 TEST_ASSERT_TRUE(nExp > 0 && nExp <= 11);266 267 JsonParse p;268 int rc = test_jsonFunctionArgToBlob(&ctx, v, &p);269 270 TEST_ASSERT_EQUAL_INT(0, rc);271 TEST_ASSERT_NOT_NULL(p.aBlob);272 TEST_ASSERT_EQUAL_UINT32((unsigned)(1 + nExp), p.nBlob);273 TEST_ASSERT_EQUAL_HEX8((JSONB_INT | (nExp<<4)), p.aBlob[0]);274 TEST_ASSERT_EQUAL_MEMORY(zExp, p.aBlob+1, (size_t)nExp);275 276 free_parse_blob(&p);277 sqlite3ValueFree(v);278 cleanup_context_out(&out);279}280 281int main(void){282 UNITY_BEGIN();283 RUN_TEST(test_jsonFunctionArgToBlob_null_input);284 RUN_TEST(test_jsonFunctionArgToBlob_blob_not_jsonb_errors);285 RUN_TEST(test_jsonFunctionArgToBlob_blob_jsonb_accepted);286 RUN_TEST(test_jsonFunctionArgToBlob_text_raw_textraw_encoding);287 RUN_TEST(test_jsonFunctionArgToBlob_text_jsonsubtype_valid_null);288 RUN_TEST(test_jsonFunctionArgToBlob_text_jsonsubtype_malformed_error);289 RUN_TEST(test_jsonFunctionArgToBlob_float_finite);290 RUN_TEST(test_jsonFunctionArgToBlob_float_nan_becomes_null);291 RUN_TEST(test_jsonFunctionArgToBlob_integer_basic);292 int rc = UNITY_END();293 if( gDb ){294 sqlite3_close(gDb);295 gDb = NULL;296 }297 return rc;298}