AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5#include <stdlib.h>6#include <stdint.h>7 8/* Wrapper for the static function under test, provided by the module */9int test_jsonEachPathLength(JsonEachCursor *p);10 11/* Hand-crafted minimal JSONB blob for {"a":[1,2,3]}12 Bytes:13 0: 0x9c OBJECT, payload 9 bytes14 1: 0x17 TEXT label, payload 1 byte15 2: 0x61 'a'16 3: 0x6b ARRAY, payload 6 bytes17 4: 0x13 INT, payload 1 byte18 5: 0x31 '1'19 6: 0x13 INT, payload 1 byte20 7: 0x32 '2'21 8: 0x13 INT, payload 1 byte22 9: 0x33 '3'23*/24static unsigned char gBlob_ObjAArray123[] = {25 0x9c, 0x17, 0x61, 0x6b, 0x13, 0x31, 0x13, 0x32, 0x13, 0x3326};27 28static void initCursor(JsonEachCursor *pCur,29 unsigned char *aBlob, int nBlob,30 char *zPath, int iVal, sqlite3_int64 iRowid,31 int bRecursive){32 memset(pCur, 0, sizeof(*pCur));33 /* Minimal fields used by jsonEachPathLength and called internals */34 pCur->sParse.aBlob = aBlob;35 pCur->sParse.nBlob = (u32)nBlob;36 pCur->sParse.eEdit = 0; /* assert in function requires this */37 pCur->sParse.delta = 0;38 39 pCur->path.zBuf = zPath;40 pCur->path.nUsed = (u32)strlen(zPath);41 42 pCur->i = (u32)iVal;43 pCur->iRowid = iRowid;44 pCur->bRecursive = (u8)bRecursive;45}46 47/* Utility to duplicate a path into a mutable buffer */48static char* dupPath(const char *z){49 size_t n = strlen(z);50 char *p = (char*)sqlite3_malloc64(n+1);51 TEST_ASSERT_NOT_NULL(p);52 memcpy(p, z, n+1);53 return p;54}55 56void setUp(void) {57 /* No global setup needed */58}59void tearDown(void) {60 /* No global teardown needed */61}62 63/* bRecursive==0: function should return nUsed unchanged */64static void test_jsonEachPathLength_non_recursive_returns_full_length(void){65 JsonEachCursor cur;66 char *z = dupPath("$.a[2].b");67 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),68 z, 9 /* arbitrary */, 0 /* rowid */, 0 /* bRecursive */);69 int got = test_jsonEachPathLength(&cur);70 TEST_ASSERT_EQUAL_INT((int)strlen(z), got);71 sqlite3_free(z);72}73 74/* iRowid!=0: function should return nUsed unchanged */75static void test_jsonEachPathLength_non_zero_rowid_returns_full_length(void){76 JsonEachCursor cur;77 char *z = dupPath("$.a[2].b");78 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),79 z, 9, 5 /* rowid!=0 */, 1 /* bRecursive */);80 int got = test_jsonEachPathLength(&cur);81 TEST_ASSERT_EQUAL_INT((int)strlen(z), got);82 sqlite3_free(z);83}84 85/* Short path n<2: return nUsed unchanged (which is 1 for "$") */86static void test_jsonEachPathLength_short_path_returns_one(void){87 JsonEachCursor cur;88 char *z = dupPath("$");89 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),90 z, 1 /* any */, 0 /* rowid */, 1 /* bRecursive */);91 int got = test_jsonEachPathLength(&cur);92 TEST_ASSERT_EQUAL_INT(1, got);93 sqlite3_free(z);94}95 96/* Match on last '.' before 'b' for "$.a[2].b": p->i = payload start of ".a[2]" = 9, expect index of that dot (6) */97static void test_jsonEachPathLength_matches_after_last_dot(void){98 JsonEachCursor cur;99 char *z = dupPath("$.a[2].b");100 /* For ".a[2]": header index x=8, header len n=1 => payload start p->i=9 */101 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),102 z, 9 /* p->i */, 0 /* rowid */, 1 /* bRecursive */);103 /* Keep a copy to verify no corruption */104 char before[32]; memset(before, 0, sizeof(before)); strncpy(before, z, sizeof(before)-1);105 int got = test_jsonEachPathLength(&cur);106 TEST_ASSERT_EQUAL_INT(6, got);107 TEST_ASSERT_EQUAL_STRING(before, z);108 sqlite3_free(z);109}110 111/* Match on '[' for "$.a[2]": p->i = payload start of ".a" = 4, expect index of '[' (3) */112static void test_jsonEachPathLength_matches_at_bracket(void){113 JsonEachCursor cur;114 char *z = dupPath("$.a[2]");115 /* For ".a": header index x=3, header len n=1 => payload start p->i=4 */116 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),117 z, 4 /* p->i */, 0 /* rowid */, 1 /* bRecursive */);118 int got = test_jsonEachPathLength(&cur);119 TEST_ASSERT_EQUAL_INT(3, got);120 sqlite3_free(z);121}122 123/* No match at last separators; earlier match at ".a": expect index 3 for "$.a[2].b.c" with p->i = payload of ".a" */124static void test_jsonEachPathLength_skips_to_earlier_matching_prefix(void){125 JsonEachCursor cur;126 char *z = dupPath("$.a[2].b.c");127 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),128 z, 4 /* payload start of ".a" */, 0 /* rowid */, 1 /* bRecursive */);129 int got = test_jsonEachPathLength(&cur);130 TEST_ASSERT_EQUAL_INT(3, got);131 sqlite3_free(z);132}133 134/* Prefix causing PATHERROR should be skipped; earlier valid ".a" still matches */135static void test_jsonEachPathLength_ignores_error_prefix_and_matches_earlier(void){136 JsonEachCursor cur;137 char *z = dupPath("$.a[xyz].b");138 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),139 z, 4 /* payload start of ".a" */, 0 /* rowid */, 1 /* bRecursive */);140 int got = test_jsonEachPathLength(&cur);141 TEST_ASSERT_EQUAL_INT(3, got);142 sqlite3_free(z);143}144 145/* No matching prefix: return 1 */146static void test_jsonEachPathLength_no_match_returns_one(void){147 JsonEachCursor cur;148 char *z = dupPath("$.a[2].b");149 initCursor(&cur, gBlob_ObjAArray123, (int)sizeof(gBlob_ObjAArray123),150 z, 42 /* not a valid payload-start for any prefix */, 0 /* rowid */, 1 /* bRecursive */);151 int got = test_jsonEachPathLength(&cur);152 TEST_ASSERT_EQUAL_INT(1, got);153 sqlite3_free(z);154}155 156int main(void){157 UNITY_BEGIN();158 RUN_TEST(test_jsonEachPathLength_non_recursive_returns_full_length);159 RUN_TEST(test_jsonEachPathLength_non_zero_rowid_returns_full_length);160 RUN_TEST(test_jsonEachPathLength_short_path_returns_one);161 RUN_TEST(test_jsonEachPathLength_matches_after_last_dot);162 RUN_TEST(test_jsonEachPathLength_matches_at_bracket);163 RUN_TEST(test_jsonEachPathLength_skips_to_earlier_matching_prefix);164 RUN_TEST(test_jsonEachPathLength_ignores_error_prefix_and_matches_earlier);165 RUN_TEST(test_jsonEachPathLength_no_match_returns_one);166 return UNITY_END();167}