Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonLookupStep.c377 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/* Wrapper declared in module to access static function */8u32 test_jsonLookupStep(JsonParse *pParse, u32 iRoot, const char *zPath, u32 iLabel);9 10/* Local copies of JSONB type-nibble values (not redefining internal macros) */11static const u8 T_NULL    = 0;12static const u8 T_TRUE    = 1;13static const u8 T_FALSE   = 2;14static const u8 T_INT     = 3;15static const u8 T_INT5    = 4;16static const u8 T_FLOAT   = 5;17static const u8 T_FLOAT5  = 6;18static const u8 T_TEXT    = 7;19static const u8 T_TEXTJ   = 8;20static const u8 T_TEXT5   = 9;21static const u8 T_TEXTRAW = 10;22static const u8 T_ARRAY   = 11;23static const u8 T_OBJECT  = 12;24 25/* JSON_LOOKUP error code numeric values (avoid using internal macros) */26static const u32 JL_ERROR     = 0xffffffffu;27static const u32 JL_NOTFOUND  = 0xfffffffeu;28static const u32 JL_PATHERROR = 0xfffffffdu;29 30/* Guessed edit-mode numeric values typically used by SQLite json code.31   These are not macro names from the core; we just set eEdit integers. */32static const int EEDIT_DEL  = 1;33static const int EEDIT_REPL = 2;34static const int EEDIT_INS  = 3;35static const int EEDIT_SET  = 4;36 37/* Emit a JSONB header for the given element type and payload size.38   Returns the new index after writing the header at buf[idx]. */39static int emit_hdr(u8 *buf, int idx, u8 eType, u32 szPayload){40  if( szPayload <= 11 ){41    buf[idx++] = (u8)(eType | (szPayload<<4));42  }else if( szPayload <= 0xff ){43    buf[idx++] = (u8)(eType | 0xc0);44    buf[idx++] = (u8)(szPayload & 0xff);45  }else if( szPayload <= 0xffff ){46    buf[idx++] = (u8)(eType | 0xd0);47    buf[idx++] = (u8)((szPayload>>8) & 0xff);48    buf[idx++] = (u8)(szPayload & 0xff);49  }else{50    buf[idx++] = (u8)(eType | 0xe0);51    buf[idx++] = (u8)((szPayload>>24) & 0xff);52    buf[idx++] = (u8)((szPayload>>16) & 0xff);53    buf[idx++] = (u8)((szPayload>>8) & 0xff);54    buf[idx++] = (u8)(szPayload & 0xff);55  }56  return idx;57}58 59/* Build an OBJECT with a single key/value pair: { key: (valueType)valueText }60   Returns total length in *pLen. All sizes are small to keep single-byte headers. */61static void build_object_kv(const char *key, u8 valueType, const char *valText,62                            u8 *out, u32 *pLen){63  int idx = 0;64  u32 keyLen = (u32)strlen(key);65  u32 valLen = (u32)strlen(valText);66  u32 labelElemLen = 1 + keyLen;     /* 1-byte header + key payload */67  u32 valueElemLen = 1 + valLen;     /* 1-byte header + value payload */68  u32 payloadLen   = labelElemLen + valueElemLen;69 70  idx = emit_hdr(out, idx, T_OBJECT, payloadLen);71  /* label element: TEXT */72  idx = emit_hdr(out, idx, T_TEXT, keyLen);73  memcpy(&out[idx], key, keyLen); idx += keyLen;74  /* value element: valueType with valText payload */75  idx = emit_hdr(out, idx, valueType, valLen);76  memcpy(&out[idx], valText, valLen); idx += valLen;77 78  *pLen = (u32)idx;79}80 81/* Build an ARRAY of INT elements given N number-strings values[].82   Returns total length in *pLen. */83static void build_array_ints(const char **values, int N, u8 *out, u32 *pLen){84  int idx = 0;85  int i;86  /* Compute total payload length: sum over elements (1-byte header + payload) */87  u32 payloadLen = 0;88  for(i=0;i<N;i++){89    payloadLen += 1 + (u32)strlen(values[i]);90  }91  idx = emit_hdr(out, idx, T_ARRAY, payloadLen);92  for(i=0;i<N;i++){93    u32 vlen = (u32)strlen(values[i]);94    idx = emit_hdr(out, idx, T_INT, vlen);95    memcpy(&out[idx], values[i], vlen); idx += vlen;96  }97  *pLen = (u32)idx;98}99 100static sqlite3 *gDb = NULL;101 102void setUp(void) {103  int rc = sqlite3_open(":memory:", &gDb);104  TEST_ASSERT_EQUAL_INT(0, rc);105  TEST_ASSERT_NOT_NULL(gDb);106}107void tearDown(void) {108  if( gDb ){109    sqlite3_close(gDb);110    gDb = NULL;111  }112}113 114/* Test: object key lookup success: {"a":123}, path ".a" -> index 3, iLabel==1 */115void test_jsonLookupStep_object_key_found(void){116  u8 blob[32];117  u32 n;118  build_object_kv("a", T_INT, "123", blob, &n);119  /* Layout expectation:120     [0]: OBJECT hdr payload=6 -> 0x6c121     [1]: TEXT hdr payload=1   -> 0x17122     [2]: 'a'123     [3]: INT hdr payload=3    -> 0x33124     [4..6]: '1''2''3'125   */126  TEST_ASSERT_EQUAL_UINT8(0x6c, blob[0]);127  TEST_ASSERT_EQUAL_UINT8(0x17, blob[1]);128  TEST_ASSERT_EQUAL_UINT8('a', blob[2]);129  TEST_ASSERT_EQUAL_UINT8(0x33, blob[3]);130 131  JsonParse p;132  memset(&p, 0, sizeof(p));133  p.aBlob = blob;134  p.nBlob = n;135  p.nBlobAlloc = 0; /* read-only buffer; no edits expected */136  p.bReadOnly = 0;  /* allow edits if attempted */137  p.db = gDb;138 139  u32 rc = test_jsonLookupStep(&p, 0, ".a", 0);140  TEST_ASSERT_EQUAL_UINT32(3u, rc);141  TEST_ASSERT_EQUAL_UINT32(1u, p.iLabel);142}143 144/* Test: object key lookup not found: {"a":123}, path ".b" -> NOTFOUND */145void test_jsonLookupStep_object_key_not_found(void){146  u8 blob[32];147  u32 n;148  build_object_kv("a", T_INT, "123", blob, &n);149 150  JsonParse p;151  memset(&p, 0, sizeof(p));152  p.aBlob = blob;153  p.nBlob = n;154  p.bReadOnly = 0;155 156  u32 rc = test_jsonLookupStep(&p, 0, ".b", 0);157  TEST_ASSERT_EQUAL_HEX32(JL_NOTFOUND, rc);158}159 160/* Test: path syntax error for "." alone */161void test_jsonLookupStep_path_error_dot(void){162  u8 blob[32];163  u32 n;164  build_object_kv("a", T_INT, "1", blob, &n);165 166  JsonParse p;167  memset(&p, 0, sizeof(p));168  p.aBlob = blob; p.nBlob = n;169 170  u32 rc = test_jsonLookupStep(&p, 0, ".", 0);171  TEST_ASSERT_EQUAL_HEX32(JL_PATHERROR, rc);172}173 174/* Test: quoted key with space: {"a b":7}, path ".\"a b\"" -> found */175void test_jsonLookupStep_object_quoted_key(void){176  u8 blob[32];177  u32 n;178  build_object_kv("a b", T_INT, "7", blob, &n);179 180  JsonParse p;181  memset(&p, 0, sizeof(p));182  p.aBlob = blob; p.nBlob = n; p.db = gDb;183 184  u32 rc = test_jsonLookupStep(&p, 0, ".\"a b\"", 0);185  /* Value element starts at index:186     OBJECT hdr (1) + label elem header (1) + label payload (3) = 5 */187  TEST_ASSERT_EQUAL_UINT32(5u, rc);188  TEST_ASSERT_EQUAL_UINT32(1u, p.iLabel);189}190 191/* Test: array index lookup: [10,20], path "[1]" -> index of second element */192void test_jsonLookupStep_array_index_found(void){193  const char *vals[] = { "10", "20" };194  u8 blob[32];195  u32 n;196  build_array_ints(vals, 2, blob, &n);197  /* Expect:198     [0]: ARRAY hdr payload=6 -> 0x6b199     First element at [1] (len 3), second at [4]200   */201  TEST_ASSERT_EQUAL_UINT8(0x6b, blob[0]);202 203  JsonParse p;204  memset(&p, 0, sizeof(p));205  p.aBlob = blob; p.nBlob = n;206 207  u32 rc = test_jsonLookupStep(&p, 0, "[1]", 0);208  TEST_ASSERT_EQUAL_UINT32(4u, rc);209}210 211/* Test: array last element via "[#-1]" */212void test_jsonLookupStep_array_last_element(void){213  const char *vals[] = { "10", "20" };214  u8 blob[32];215  u32 n;216  build_array_ints(vals, 2, blob, &n);217 218  JsonParse p;219  memset(&p, 0, sizeof(p));220  p.aBlob = blob; p.nBlob = n;221 222  u32 rc = test_jsonLookupStep(&p, 0, "[#-1]", 0);223  TEST_ASSERT_EQUAL_UINT32(4u, rc);224}225 226/* Test: array index out of range and path syntax error */227void test_jsonLookupStep_array_errors(void){228  const char *vals[] = { "10", "20" };229  u8 blob[32];230  u32 n;231  build_array_ints(vals, 2, blob, &n);232 233  JsonParse p;234  memset(&p, 0, sizeof(p));235  p.aBlob = blob; p.nBlob = n;236 237  u32 rc1 = test_jsonLookupStep(&p, 0, "[3]", 0);238  TEST_ASSERT_EQUAL_HEX32(JL_NOTFOUND, rc1);239 240  u32 rc2 = test_jsonLookupStep(&p, 0, "[#-3]", 0);241  TEST_ASSERT_EQUAL_HEX32(JL_NOTFOUND, rc2);242 243  u32 rc3 = test_jsonLookupStep(&p, 0, "[a]", 0);244  TEST_ASSERT_EQUAL_HEX32(JL_PATHERROR, rc3);245 246  u32 rc4 = test_jsonLookupStep(&p, 0, "[1", 0);247  TEST_ASSERT_EQUAL_HEX32(JL_PATHERROR, rc4);248}249 250/* Test: NOTFOUND when using object path on array */251void test_jsonLookupStep_wrong_type_notfound(void){252  const char *vals[] = { "10" };253  u8 blob[16]; u32 n;254  build_array_ints(vals, 1, blob, &n);255 256  JsonParse p;257  memset(&p, 0, sizeof(p));258  p.aBlob = blob; p.nBlob = n;259 260  u32 rc = test_jsonLookupStep(&p, 0, ".x", 0);261  TEST_ASSERT_EQUAL_HEX32(JL_NOTFOUND, rc);262}263 264/* Test: JEDIT_INS - insert new key/value into object.265   Start: {"a":123}. Insert .b := 5. Verify updated blob bytes. */266void test_jsonLookupStep_insert_new_key_value(void){267  u8 blob[32]; u32 n;268  build_object_kv("a", T_INT, "123", blob, &n);269 270  /* Value to insert: INT '5' -> header (size=1) + payload */271  u8 ins[4]; int idx=0;272  idx = emit_hdr(ins, idx, T_INT, 1);273  ins[idx++] = (u8)'5';274  u32 nIns = (u32)idx;275 276  JsonParse p;277  memset(&p, 0, sizeof(p));278  p.aBlob = blob; p.nBlob = n; p.nBlobAlloc = 0;279  p.db = gDb; p.bReadOnly = 0;280  p.eEdit = EEDIT_INS;         /* trigger insertion when missing */281  p.aIns = ins; p.nIns = nIns;282 283  u32 rc = test_jsonLookupStep(&p, 0, ".b", 0);284  TEST_ASSERT_NOT_EQUAL_HEX32(JL_ERROR, rc);285  TEST_ASSERT_NOT_EQUAL_HEX32(JL_PATHERROR, rc);286 287  /* Expected final blob:288     OBJECT payload = 10:289       label "a", value 123, label "b", value 5290     Sequence of bytes:291       obj hdr (0x0c | (10<<4) = 0xac),292       label "a": 0x17 'a',293       value 123: 0x33 '1''2''3',294       label "b": Textraw header used by insertion path (size=1) -> 0x1a, 'b'295       value 5:   0x13 '5'296  */297  u8 expected[32]; int e=0;298  e = emit_hdr(expected, e, T_OBJECT, 10);299  e = emit_hdr(expected, e, T_TEXT, 1); expected[e++] = (u8)'a';300  e = emit_hdr(expected, e, T_INT, 3);  expected[e++] = (u8)'1'; expected[e++] = (u8)'2'; expected[e++] = (u8)'3';301  /* inserted label uses TEXTRAW per code path (rawKey true) */302  e = emit_hdr(expected, e, T_TEXTRAW, 1); expected[e++] = (u8)'b';303  e = emit_hdr(expected, e, T_INT, 1);     expected[e++] = (u8)'5';304 305  TEST_ASSERT_EQUAL_UINT32((u32)e, p.nBlob);306  TEST_ASSERT_EQUAL_MEMORY(expected, p.aBlob, e);307}308 309/* Test: JEDIT_DEL - delete existing key (and its label) from object.310   Start: {"a":123}. Delete ".a". Final: {} (OBJECT with payload 0). */311void test_jsonLookupStep_delete_key(void){312  u8 blob[32]; u32 n;313  build_object_kv("a", T_INT, "123", blob, &n);314 315  JsonParse p;316  memset(&p, 0, sizeof(p));317  p.aBlob = blob; p.nBlob = n; p.nBlobAlloc = 0;318  p.db = gDb; p.bReadOnly = 0;319  p.eEdit = EEDIT_DEL;320 321  u32 rc = test_jsonLookupStep(&p, 0, ".a", 0);322  TEST_ASSERT_NOT_EQUAL_HEX32(JL_ERROR, rc);323  TEST_ASSERT_NOT_EQUAL_HEX32(JL_PATHERROR, rc);324  /* Expect OBJECT hdr with payload 0 -> single byte 0x0c */325  TEST_ASSERT_EQUAL_UINT32(1u, p.nBlob);326  TEST_ASSERT_EQUAL_UINT8((u8)(T_OBJECT | (0<<4)), p.aBlob[0]);327}328 329/* Test: JEDIT_SET - replace existing value.330   Start: {"a":123}. Set ".a" := 7. Final: {"a":7}. */331void test_jsonLookupStep_set_existing_value(void){332  u8 blob[32]; u32 n;333  build_object_kv("a", T_INT, "123", blob, &n);334 335  u8 ins[4]; int idx=0;336  idx = emit_hdr(ins, idx, T_INT, 1);337  ins[idx++] = (u8)'7';338  u32 nIns = (u32)idx;339 340  JsonParse p;341  memset(&p, 0, sizeof(p));342  p.aBlob = blob; p.nBlob = n; p.nBlobAlloc = 0;343  p.db = gDb; p.bReadOnly = 0;344  p.eEdit = EEDIT_SET;345  p.aIns = ins; p.nIns = nIns;346 347  u32 rc = test_jsonLookupStep(&p, 0, ".a", 0);348  TEST_ASSERT_NOT_EQUAL_HEX32(JL_ERROR, rc);349  TEST_ASSERT_NOT_EQUAL_HEX32(JL_PATHERROR, rc);350 351  /* Expected final blob: OBJECT payload=4:352     hdr: 0x4c, label: 0x17 'a', value: 0x13 '7'353  */354  u8 expected[16]; int e=0;355  e = emit_hdr(expected, e, T_OBJECT, 4);356  e = emit_hdr(expected, e, T_TEXT, 1); expected[e++] = (u8)'a';357  e = emit_hdr(expected, e, T_INT, 1);  expected[e++] = (u8)'7';358 359  TEST_ASSERT_EQUAL_UINT32((u32)e, p.nBlob);360  TEST_ASSERT_EQUAL_MEMORY(expected, p.aBlob, e);361}362 363int main(void){364  UNITY_BEGIN();365  RUN_TEST(test_jsonLookupStep_object_key_found);366  RUN_TEST(test_jsonLookupStep_object_key_not_found);367  RUN_TEST(test_jsonLookupStep_path_error_dot);368  RUN_TEST(test_jsonLookupStep_object_quoted_key);369  RUN_TEST(test_jsonLookupStep_array_index_found);370  RUN_TEST(test_jsonLookupStep_array_last_element);371  RUN_TEST(test_jsonLookupStep_array_errors);372  RUN_TEST(test_jsonLookupStep_wrong_type_notfound);373  RUN_TEST(test_jsonLookupStep_insert_new_key_value);374  RUN_TEST(test_jsonLookupStep_delete_key);375  RUN_TEST(test_jsonLookupStep_set_existing_value);376  return UNITY_END();377}