Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_json_jsonMergePatch.c434 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* Wrapper provided by the module under test */8extern int test_jsonMergePatch(JsonParse *pTarget, u32 iTarget,9                               const JsonParse *pPatch, u32 iPatch);10 11/* Local constants for JSONB type codes (distinct names to avoid conflicts) */12enum {13  JT_NULL   = 0,14  JT_TRUE   = 1,15  JT_FALSE  = 2,16  JT_INT    = 3,17  JT_TEXT   = 7,18  JT_TEXTRAW= 10,19  JT_ARRAY  = 11,20  JT_OBJECT = 1221};22 23typedef struct Buf {24  u8 *a;25  int n;26} Buf;27 28static Buf buf_alloc(int n){29  Buf b;30  b.a = (u8*)sqlite3_malloc(n);31  TEST_ASSERT_NOT_NULL(b.a);32  b.n = n;33  return b;34}35 36static void buf_free(Buf *b){37  if( b && b->a ){38    sqlite3_free(b->a);39    b->a = NULL;40    b->n = 0;41  }42}43 44static Buf make_text_value(const char *s){45  int m = (int)strlen(s);46  TEST_ASSERT(m <= 11); /* keep simple single-byte header */47  Buf b = buf_alloc(1 + m);48  b.a[0] = (u8)((m<<4) | JT_TEXT);49  memcpy(&b.a[1], s, (size_t)m);50  return b;51}52 53static Buf make_int_value_from_str(const char *digits){54  int m = (int)strlen(digits);55  TEST_ASSERT(m <= 11);56  Buf b = buf_alloc(1 + m);57  b.a[0] = (u8)((m<<4) | JT_INT);58  memcpy(&b.a[1], digits, (size_t)m);59  return b;60}61 62static Buf make_int_value(int v){63  char tmp[32];64  snprintf(tmp, sizeof(tmp), "%d", v);65  return make_int_value_from_str(tmp);66}67 68static Buf make_null_value(void){69  Buf b = buf_alloc(1);70  b.a[0] = (u8)((0<<4) | JT_NULL);71  return b;72}73 74/* Create a label/value pair buffer (label is TEXT type) */75static Buf make_pair(const char *label, const Buf *val){76  int L = (int)strlen(label);77  TEST_ASSERT(L <= 11);78  Buf p = buf_alloc(1 + L + val->n);79  p.a[0] = (u8)((L<<4) | JT_TEXT);80  memcpy(&p.a[1], label, (size_t)L);81  memcpy(&p.a[1+L], val->a, (size_t)val->n);82  return p;83}84 85/* Create a label/value pair with an INT label (for malformed object tests) */86static Buf make_bad_pair_intlabel(const char *labelDigits, const Buf *val){87  int L = (int)strlen(labelDigits);88  TEST_ASSERT(L <= 11);89  Buf p = buf_alloc(1 + L + val->n);90  p.a[0] = (u8)((L<<4) | JT_INT);91  memcpy(&p.a[1], labelDigits, (size_t)L);92  memcpy(&p.a[1+L], val->a, (size_t)val->n);93  return p;94}95 96/* Build an OBJECT from an array of pair buffers. Copies pair contents. */97static Buf make_object_from_pairs(const Buf *pairs, int npair){98  int i, payload = 0;99  for(i=0; i<npair; i++){100    payload += pairs[i].n;101  }102  TEST_ASSERT(payload >= 0 && payload <= 255);103  int hdr = (payload <= 11) ? 1 : 2;104  Buf o = buf_alloc(hdr + payload);105  if( hdr==1 ){106    o.a[0] = (u8)((payload<<4) | JT_OBJECT);107  }else{108    o.a[0] = (u8)(((u8)12<<4) | JT_OBJECT); /* 0xCC */109    o.a[1] = (u8)payload;110  }111  int off = hdr;112  for(i=0; i<npair; i++){113    memcpy(&o.a[off], pairs[i].a, (size_t)pairs[i].n);114    off += pairs[i].n;115  }116  TEST_ASSERT_EQUAL_INT(hdr+payload, o.n);117  return o;118}119 120/* Initialize a JsonParse for target with its own writable copy and capacity */121static void initTargetParse(JsonParse *p, const Buf *content, int capacity){122  memset(p, 0, sizeof(*p));123  p->aBlob = (u8*)sqlite3_malloc(capacity);124  TEST_ASSERT_NOT_NULL(p->aBlob);125  memcpy(p->aBlob, content->a, (size_t)content->n);126  p->nBlob = content->n;127  p->nBlobAlloc = capacity;128  p->delta = 0;129  p->oom = 0;130  /* p->db may remain NULL; we pre-allocate enough to avoid growth */131}132 133/* Initialize a read-only patch JsonParse referencing existing bytes */134static void initPatchParse(JsonParse *p, const Buf *content){135  memset(p, 0, sizeof(*p));136  p->aBlob = content->a;137  p->nBlob = content->n;138  p->nBlobAlloc = content->n;139  p->delta = 0;140}141 142/* Common verification helper */143static void assertTargetEquals(const JsonParse *t, const Buf *expected){144  TEST_ASSERT_EQUAL_INT(expected->n, (int)t->nBlob);145  TEST_ASSERT_EQUAL_UINT8_ARRAY(expected->a, t->aBlob, expected->n);146}147 148/* Unity hooks */149void setUp(void) {}150void tearDown(void) {}151 152/* 1) Non-object patch replaces target entirely */153void test_jsonMergePatch_replace_with_non_object(void){154  /* Target: {"a":1} */155  Buf v1 = make_int_value(1);156  Buf pA1 = make_pair("a", &v1);157  Buf targetObj = make_object_from_pairs(&pA1, 1);158 159  /* Patch: TEXT "Z" */160  Buf patchTxt = make_text_value("Z");161 162  /* Expected: patchTxt */163  Buf expected = patchTxt; /* same content */164 165  JsonParse T, P;166  initTargetParse(&T, &targetObj, 128);167  initPatchParse(&P, &patchTxt);168 169  int rc = test_jsonMergePatch(&T, 0, &P, 0);170  TEST_ASSERT_EQUAL_INT(0, rc);171  assertTargetEquals(&T, &expected);172 173  sqlite3_free(T.aBlob);174  buf_free(&targetObj);175  buf_free(&pA1);176  buf_free(&v1);177  buf_free(&patchTxt);178}179 180/* 2) Patch is object; target is non-object -> becomes object with field */181void test_jsonMergePatch_target_non_object_patch_object_adds_field(void){182  /* Target: TEXT "X" */183  Buf targetTxt = make_text_value("X");184  /* Patch: {"a":1} */185  Buf v1 = make_int_value(1);186  Buf pA1 = make_pair("a", &v1);187  Buf patchObj = make_object_from_pairs(&pA1, 1);188 189  /* Expected: {"a":1} */190  Buf expected = patchObj; /* The merge of {} with patch yields patch */191 192  JsonParse T, P;193  initTargetParse(&T, &targetTxt, 128);194  initPatchParse(&P, &patchObj);195 196  int rc = test_jsonMergePatch(&T, 0, &P, 0);197  TEST_ASSERT_EQUAL_INT(0, rc);198  assertTargetEquals(&T, &expected);199 200  sqlite3_free(T.aBlob);201  buf_free(&targetTxt);202  buf_free(&patchObj);203  buf_free(&pA1);204  buf_free(&v1);205}206 207/* 3) Deleting an existing key via null patch value */208void test_jsonMergePatch_delete_existing_key_with_null(void){209  /* Target: {"x":1,"y":2} */210  Buf v1 = make_int_value(1);211  Buf v2 = make_int_value(2);212  Buf px1 = make_pair("x", &v1);213  Buf py2 = make_pair("y", &v2);214  Buf pairsXY[2] = { px1, py2 };215  Buf targetObj = make_object_from_pairs(pairsXY, 2);216 217  /* Patch: {"x": null} */218  Buf vNull = make_null_value();219  Buf pxNull = make_pair("x", &vNull);220  Buf patchObj = make_object_from_pairs(&pxNull, 1);221 222  /* Expected: {"y":2} */223  Buf expected = make_object_from_pairs(&py2, 1);224 225  JsonParse T, P;226  initTargetParse(&T, &targetObj, 128);227  initPatchParse(&P, &patchObj);228 229  int rc = test_jsonMergePatch(&T, 0, &P, 0);230  TEST_ASSERT_EQUAL_INT(0, rc);231  assertTargetEquals(&T, &expected);232 233  sqlite3_free(T.aBlob);234  buf_free(&expected);235  buf_free(&targetObj);236  buf_free(&px1);237  buf_free(&py2);238  buf_free(&v1);239  buf_free(&v2);240  buf_free(&vNull);241  buf_free(&pxNull);242  buf_free(&patchObj);243}244 245/* 4) Updating an existing scalar value */246void test_jsonMergePatch_update_existing_scalar(void){247  /* Target: {"y":2} */248  Buf v2 = make_int_value(2);249  Buf py2 = make_pair("y", &v2);250  Buf targetObj = make_object_from_pairs(&py2, 1);251 252  /* Patch: {"y":3} */253  Buf v3 = make_int_value(3);254  Buf py3 = make_pair("y", &v3);255  Buf patchObj = make_object_from_pairs(&py3, 1);256 257  /* Expected: {"y":3} */258  Buf expected = patchObj;259 260  JsonParse T, P;261  initTargetParse(&T, &targetObj, 128);262  initPatchParse(&P, &patchObj);263 264  int rc = test_jsonMergePatch(&T, 0, &P, 0);265  TEST_ASSERT_EQUAL_INT(0, rc);266  assertTargetEquals(&T, &expected);267 268  sqlite3_free(T.aBlob);269  buf_free(&targetObj);270  buf_free(&py2);271  buf_free(&v2);272  buf_free(&py3);273  buf_free(&v3);274  buf_free(&patchObj);275}276 277/* 5) Recursive merge on nested objects: remove 'b', add 'c' */278void test_jsonMergePatch_recursive_nested_merge(void){279  /* Target: {"nest": {"a":1,"b":2}} */280  Buf va1 = make_int_value(1);281  Buf vb2 = make_int_value(2);282  Buf pA1 = make_pair("a", &va1);283  Buf pB2 = make_pair("b", &vb2);284  Buf innerPairsAB[2] = { pA1, pB2 };285  Buf innerObjAB = make_object_from_pairs(innerPairsAB, 2);286 287  Buf pNestAB = make_pair("nest", &innerObjAB);288  Buf targetObj = make_object_from_pairs(&pNestAB, 1);289 290  /* Patch: {"nest": {"b": null, "c": 3}} */291  Buf vNull = make_null_value();292  Buf pBnull = make_pair("b", &vNull);293  Buf vc3 = make_int_value(3);294  Buf pC3 = make_pair("c", &vc3);295  Buf innerPatchPairs[2] = { pBnull, pC3 };296  Buf innerPatchObj = make_object_from_pairs(innerPatchPairs, 2);297  Buf pNestPatch = make_pair("nest", &innerPatchObj);298  Buf patchObj = make_object_from_pairs(&pNestPatch, 1);299 300  /* Expected: {"nest": {"a":1,"c":3}}  (order preserved: 'a' then 'c') */301  Buf innerExpectedPairs[2] = { pA1, pC3 };302  Buf innerExpectedObj = make_object_from_pairs(innerExpectedPairs, 2);303  Buf pNestExpected = make_pair("nest", &innerExpectedObj);304  Buf expected = make_object_from_pairs(&pNestExpected, 1);305 306  JsonParse T, P;307  initTargetParse(&T, &targetObj, 256);308  initPatchParse(&P, &patchObj);309 310  int rc = test_jsonMergePatch(&T, 0, &P, 0);311  TEST_ASSERT_EQUAL_INT(0, rc);312  assertTargetEquals(&T, &expected);313 314  sqlite3_free(T.aBlob);315  buf_free(&expected);316  buf_free(&pNestExpected);317  buf_free(&innerExpectedObj);318  buf_free(&innerPatchObj);319  buf_free(&pNestPatch);320  buf_free(&patchObj);321  buf_free(&innerObjAB);322  buf_free(&pNestAB);323  buf_free(&targetObj);324  buf_free(&pA1);325  buf_free(&pB2);326  buf_free(&pBnull);327  buf_free(&pC3);328  buf_free(&va1);329  buf_free(&vb2);330  buf_free(&vNull);331  buf_free(&vc3);332}333 334/* 6) Add a new key whose value is an object (exercise placeholder + recursion) */335void test_jsonMergePatch_add_object_value_property(void){336  /* Target: {} */337  Buf emptyPairs[1]; /* unused */338  Buf targetEmpty = make_object_from_pairs(NULL, 0);339 340  /* Patch: {"obj": {"k":1}} */341  Buf vk1 = make_int_value(1);342  Buf pk1 = make_pair("k", &vk1);343  Buf innerObj = make_object_from_pairs(&pk1, 1);344  Buf pobj = make_pair("obj", &innerObj);345  Buf patchObj = make_object_from_pairs(&pobj, 1);346 347  /* Expected identical to patch */348  Buf expected = patchObj;349 350  JsonParse T, P;351  initTargetParse(&T, &targetEmpty, 128);352  initPatchParse(&P, &patchObj);353 354  int rc = test_jsonMergePatch(&T, 0, &P, 0);355  TEST_ASSERT_EQUAL_INT(0, rc);356  assertTargetEquals(&T, &expected);357 358  sqlite3_free(T.aBlob);359  buf_free(&targetEmpty);360  buf_free(&vk1);361  buf_free(&pk1);362  buf_free(&innerObj);363  buf_free(&pobj);364  buf_free(&patchObj);365}366 367/* 7) BADPATCH when patch object has non-text label */368void test_jsonMergePatch_badpatch_non_text_label(void){369  /* Target: {"a":1} (valid) */370  Buf v1 = make_int_value(1);371  Buf pA1 = make_pair("a", &v1);372  Buf targetObj = make_object_from_pairs(&pA1, 1);373 374  /* Patch: object with INT label '1' and value TEXT 'x' -> invalid label */375  Buf vx = make_text_value("x");376  Buf badPair = make_bad_pair_intlabel("1", &vx);377  Buf patchObj = make_object_from_pairs(&badPair, 1);378 379  JsonParse T, P;380  initTargetParse(&T, &targetObj, 128);381  initPatchParse(&P, &patchObj);382 383  int rc = test_jsonMergePatch(&T, 0, &P, 0);384  TEST_ASSERT(rc != 0); /* expect an error (BADPATCH) */385 386  sqlite3_free(T.aBlob);387  buf_free(&targetObj);388  buf_free(&pA1);389  buf_free(&v1);390  buf_free(&vx);391  buf_free(&badPair);392  buf_free(&patchObj);393}394 395/* 8) BADTARGET when target object has non-text label */396void test_jsonMergePatch_badtarget_non_text_label_in_target(void){397  /* Target: object with INT label '1' and value TEXT 'x' -> invalid target */398  Buf vx = make_text_value("x");399  Buf badPair = make_bad_pair_intlabel("1", &vx);400  Buf targetObj = make_object_from_pairs(&badPair, 1);401 402  /* Patch: {"a": null} to ensure a scan occurs */403  Buf vNull = make_null_value();404  Buf pAnull = make_pair("a", &vNull);405  Buf patchObj = make_object_from_pairs(&pAnull, 1);406 407  JsonParse T, P;408  initTargetParse(&T, &targetObj, 128);409  initPatchParse(&P, &patchObj);410 411  int rc = test_jsonMergePatch(&T, 0, &P, 0);412  TEST_ASSERT(rc != 0); /* expect an error (BADTARGET) */413 414  sqlite3_free(T.aBlob);415  buf_free(&targetObj);416  buf_free(&badPair);417  buf_free(&vx);418  buf_free(&patchObj);419  buf_free(&pAnull);420  buf_free(&vNull);421}422 423int main(void){424  UNITY_BEGIN();425  RUN_TEST(test_jsonMergePatch_replace_with_non_object);426  RUN_TEST(test_jsonMergePatch_target_non_object_patch_object_adds_field);427  RUN_TEST(test_jsonMergePatch_delete_existing_key_with_null);428  RUN_TEST(test_jsonMergePatch_update_existing_scalar);429  RUN_TEST(test_jsonMergePatch_recursive_nested_merge);430  RUN_TEST(test_jsonMergePatch_add_object_value_property);431  RUN_TEST(test_jsonMergePatch_badpatch_non_text_label);432  RUN_TEST(test_jsonMergePatch_badtarget_non_text_label_in_target);433  return UNITY_END();434}