AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdint.h>5 6/* Declare the test wrapper provided in the module */7extern int test_jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p);8 9static sqlite3 *gDb = NULL;10 11/* Helpers to create sqlite3_value instances */12static sqlite3_value* make_blob_value(const void *data, int n){13 Mem *v = sqlite3ValueNew(gDb);14 TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3ValueNew failed");15 /* enc==0 means BLOB. Use SQLITE_TRANSIENT to copy data into the Mem. */16 int rc = sqlite3VdbeMemSetStr(v, (const char*)data, n, 0, SQLITE_TRANSIENT);17 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3VdbeMemSetStr (BLOB) failed");18 return (sqlite3_value*)v;19}20static sqlite3_value* make_text_value(const char *z){21 Mem *v = sqlite3ValueNew(gDb);22 TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3ValueNew failed");23 int rc = sqlite3VdbeMemSetStr(v, z, -1, SQLITE_UTF8, SQLITE_TRANSIENT);24 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3VdbeMemSetStr (TEXT) failed");25 return (sqlite3_value*)v;26}27static void free_value(sqlite3_value *pVal){28 if( pVal ){29 sqlite3ValueFree((Mem*)pVal);30 }31}32 33void setUp(void) {34 int rc = sqlite3_open(":memory:", &gDb);35 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");36}37void tearDown(void) {38 if( gDb ){39 sqlite3_close(gDb);40 gDb = NULL;41 }42}43 44/* 1) Non-BLOB argument: expect return 0, and JsonParse unchanged */45void test_jsonArgIsJsonb_non_blob_argument(void){46 sqlite3_value *v = make_text_value("not a blob");47 JsonParse p;48 memset(&p, 0, sizeof(p));49 p.aBlob = (u8*)0x1; /* sentinel to verify unchanged */50 p.nBlob = 12345;51 52 int rc = test_jsonArgIsJsonb(v, &p);53 TEST_ASSERT_EQUAL_INT(0, rc);54 TEST_ASSERT_EQUAL_PTR((u8*)0x1, p.aBlob);55 TEST_ASSERT_EQUAL_UINT32(12345u, p.nBlob);56 57 free_value(v);58}59 60/* 2) Valid minimal JSONB: NULL (type 0, payload 0). Single byte {0x00}. */61void test_jsonArgIsJsonb_valid_null_minimal(void){62 const unsigned char blob[] = { 0x00 };63 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));64 65 const void *expectPtr = sqlite3_value_blob(v);66 int expectN = sqlite3_value_bytes(v);67 68 JsonParse p;69 memset(&p, 0, sizeof(p));70 int rc = test_jsonArgIsJsonb(v, &p);71 TEST_ASSERT_EQUAL_INT(1, rc);72 TEST_ASSERT_EQUAL_PTR(expectPtr, p.aBlob);73 TEST_ASSERT_EQUAL_UINT32((unsigned)expectN, p.nBlob);74 75 free_value(v);76}77 78/* 3) Invalid: header says payload exists but total size mismatch.79 Use first byte 0x17 => payload size 1, type TEXT (7), but provide only header byte. */80void test_jsonArgIsJsonb_invalid_length_mismatch(void){81 const unsigned char blob[] = { 0x17 };82 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));83 84 JsonParse p;85 memset(&p, 0, sizeof(p));86 int rc = test_jsonArgIsJsonb(v, &p);87 TEST_ASSERT_EQUAL_INT(0, rc);88 TEST_ASSERT_NULL(p.aBlob);89 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);90 91 free_value(v);92}93 94/* 4) Small payload with ASCII digit header '3' (0x33): INT "123"95 Header: high nibble=3 (payload 3), low nibble=3 (INT). Payload: '1','2','3'. */96void test_jsonArgIsJsonb_small_ascii_digit_valid(void){97 const unsigned char blob[] = { 0x33, '1', '2', '3' };98 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));99 100 const void *expectPtr = sqlite3_value_blob(v);101 int expectN = sqlite3_value_bytes(v);102 103 JsonParse p;104 memset(&p, 0, sizeof(p));105 int rc = test_jsonArgIsJsonb(v, &p);106 TEST_ASSERT_EQUAL_INT(1, rc);107 TEST_ASSERT_EQUAL_PTR(expectPtr, p.aBlob);108 TEST_ASSERT_EQUAL_UINT32((unsigned)expectN, p.nBlob);109 110 free_value(v);111}112 113/* 5) Small payload with ASCII '[' (0x5b): ARRAY of five single-byte elements114 Payload (5 bytes): NULL(0x00), TRUE(0x01), FALSE(0x02), NULL(0x00), TRUE(0x01) */115void test_jsonArgIsJsonb_small_ascii_bracket_array_valid(void){116 const unsigned char blob[] = {117 0x5b, /* '[' -> ARRAY, payload size 5 */118 0x00, 0x01, 0x02, 0x00, 0x01119 };120 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));121 122 const void *expectPtr = sqlite3_value_blob(v);123 int expectN = sqlite3_value_bytes(v);124 125 JsonParse p;126 memset(&p, 0, sizeof(p));127 int rc = test_jsonArgIsJsonb(v, &p);128 TEST_ASSERT_EQUAL_INT(1, rc);129 TEST_ASSERT_EQUAL_PTR(expectPtr, p.aBlob);130 TEST_ASSERT_EQUAL_UINT32((unsigned)expectN, p.nBlob);131 132 free_value(v);133}134 135/* 6) Small payload with ASCII '{' (0x7b): ARRAY containing invalid sub-element136 First sub-element: INT with payload 'a' (invalid INT), followed by 4 single-byte elements to fill size.137 Payload bytes (7 total): 0x13 'a' 0x00 0x01 0x02 0x00 0x01 */138void test_jsonArgIsJsonb_small_ascii_brace_invalid_deep_check(void){139 const unsigned char blob[] = {140 0x7b, /* '{' -> ARRAY, payload size 7 */141 0x13, /* INT with payload size 1 (high nibble 1, low nibble 3) */142 'a', /* invalid INT char */143 0x00, 0x01, 0x02, 0x00, 0x01144 };145 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));146 147 JsonParse p;148 memset(&p, 0, sizeof(p));149 int rc = test_jsonArgIsJsonb(v, &p);150 TEST_ASSERT_EQUAL_INT(0, rc);151 TEST_ASSERT_NULL(p.aBlob);152 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);153 154 free_value(v);155}156 157/* 7) Large payload using multi-byte size header x==12158 First byte: 0xc7 -> type TEXT (7), size header code 12; next byte: 0x08 (size 8),159 followed by eight 'a' bytes. Total size = 2 + 8 = 10. */160void test_jsonArgIsJsonb_large_payload_novalidation_needed(void){161 unsigned char blob[10];162 blob[0] = 0xc7; /* x==12, type TEXT */163 blob[1] = 0x08; /* payload size 8 */164 memset(&blob[2], 'a', 8);165 166 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));167 168 const void *expectPtr = sqlite3_value_blob(v);169 int expectN = sqlite3_value_bytes(v);170 171 JsonParse p;172 memset(&p, 0, sizeof(p));173 int rc = test_jsonArgIsJsonb(v, &p);174 TEST_ASSERT_EQUAL_INT(1, rc);175 TEST_ASSERT_EQUAL_PTR(expectPtr, p.aBlob);176 TEST_ASSERT_EQUAL_UINT32((unsigned)expectN, p.nBlob);177 178 free_value(v);179}180 181/* 8) Invalid typecode: low nibble > JSONB_OBJECT; using 0x0f (type 15) */182void test_jsonArgIsJsonb_invalid_typecode(void){183 const unsigned char blob[] = { 0x0f };184 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));185 186 JsonParse p;187 memset(&p, 0, sizeof(p));188 int rc = test_jsonArgIsJsonb(v, &p);189 TEST_ASSERT_EQUAL_INT(0, rc);190 TEST_ASSERT_NULL(p.aBlob);191 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);192 193 free_value(v);194}195 196/* 9) Invalid: NULL/TRUE/FALSE must have zero payload.197 Use 0x20 (high nibble 2 -> payload size 2, low nibble 0 -> NULL), payload 2 bytes. */198void test_jsonArgIsJsonb_invalid_boolean_with_payload(void){199 const unsigned char blob[] = { 0x20, 0x00, 0x00 };200 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));201 202 JsonParse p;203 memset(&p, 0, sizeof(p));204 int rc = test_jsonArgIsJsonb(v, &p);205 TEST_ASSERT_EQUAL_INT(0, rc);206 TEST_ASSERT_NULL(p.aBlob);207 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);208 209 free_value(v);210}211 212/* 10) BLOB that is actually JSON text (e.g., "{}") should not be accepted as JSONB. */213void test_jsonArgIsJsonb_blob_is_plain_text_json_should_fail(void){214 const unsigned char blob[] = { '{', '}' };215 sqlite3_value *v = make_blob_value(blob, (int)sizeof(blob));216 217 JsonParse p;218 memset(&p, 0, sizeof(p));219 int rc = test_jsonArgIsJsonb(v, &p);220 TEST_ASSERT_EQUAL_INT(0, rc);221 TEST_ASSERT_NULL(p.aBlob);222 TEST_ASSERT_EQUAL_UINT32(0u, p.nBlob);223 224 free_value(v);225}226 227int main(void){228 UNITY_BEGIN();229 RUN_TEST(test_jsonArgIsJsonb_non_blob_argument);230 RUN_TEST(test_jsonArgIsJsonb_valid_null_minimal);231 RUN_TEST(test_jsonArgIsJsonb_invalid_length_mismatch);232 RUN_TEST(test_jsonArgIsJsonb_small_ascii_digit_valid);233 RUN_TEST(test_jsonArgIsJsonb_small_ascii_bracket_array_valid);234 RUN_TEST(test_jsonArgIsJsonb_small_ascii_brace_invalid_deep_check);235 RUN_TEST(test_jsonArgIsJsonb_large_payload_novalidation_needed);236 RUN_TEST(test_jsonArgIsJsonb_invalid_typecode);237 RUN_TEST(test_jsonArgIsJsonb_invalid_boolean_with_payload);238 RUN_TEST(test_jsonArgIsJsonb_blob_is_plain_text_json_should_fail);239 return UNITY_END();240}