commit e79fa9472b693cea8962a610ec6166ad5f95d096
parent 2fe50bd5577465ba2387b9b66d13df3b479b511d
Author: Dave Gamble <davegamble@gmail.com>
Date: Sun, 29 May 2016 17:39:54 +0100
cJSONUtils_MergePatch with tests from the RFC.
Diffstat:
3 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/cJSON_Utils.c b/cJSON_Utils.c
@@ -343,4 +343,20 @@ static cJSON *cJSONUtils_SortList(cJSON *list)
void cJSONUtils_SortObject(cJSON *object) {object->child=cJSONUtils_SortList(object->child);}
+cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) {
+ if (!patch || patch->type != cJSON_Object) {cJSON_Delete(target);return cJSON_Duplicate(patch,1);}
+ if (!target || target->type != cJSON_Object) {cJSON_Delete(target);target=cJSON_CreateObject();}
+ patch=patch->child;
+ while (patch)
+ {
+ if (patch->type == cJSON_NULL) cJSON_DeleteItemFromObject(target,patch->string);
+ else
+ {
+ cJSON *replaceme=cJSON_DetachItemFromObject(target,patch->string);
+ cJSON_AddItemToObject(target,patch->string,cJSONUtils_MergePatch(replaceme,patch));
+ }
+ patch=patch->next;
+ }
+ return target;
+}
diff --git a/cJSON_Utils.h b/cJSON_Utils.h
@@ -21,6 +21,9 @@ int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches); /* Returns 0 for succ
// Code not added to library since this strategy is a LOT slower.
*/
+/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
+cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch); /* target will be modified by patch. return value is new ptr for target. */
+
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target); /* Given a root object and a target object, construct a pointer from one to the other. */
void cJSONUtils_SortObject(cJSON *object); /* Sorts the members of the object into alphabetical order. */
diff --git a/test_utils.c b/test_utils.c
@@ -40,6 +40,25 @@ int main()
{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": 10}]",""},
{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": \"10\"}]",""},
{"{ \"foo\": [\"bar\"] }","[ { \"op\": \"add\", \"path\": \"/foo/-\", \"value\": [\"abc\", \"def\"] }]","{\"foo\": [\"bar\", [\"abc\", \"def\"]] }"}};
+
+ /* JSON Apply Merge tests: */
+ const char *merges[15][3]={
+ {"{\"a\":\"b\"}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
+ {"{\"a\":\"b\"}", "{\"b\":\"c\"}", "{\"a\":\"b\",\"b\":\"c\"}"},
+ {"{\"a\":\"b\"}", "{\"a\":null}", "{}"},
+ {"{\"a\":\"b\",\"b\":\"c\"}", "{\"a\":null}", "{\"b\":\"c\"}"},
+ {"{\"a\":[\"b\"]}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
+ {"{\"a\":\"c\"}", "{\"a\":[\"b\"]}", "{\"a\":[\"b\"]}"},
+ {"{\"a\":{\"b\":\"c\"}}", "{\"a\":{\"b\":\"d\",\"c\":null}}", "{\"a\":{\"b\":\"d\"}}"},
+ {"{\"a\":[{\"b\":\"c\"}]}", "{\"a\":[1]}", "{\"a\":[1]}"},
+ {"[\"a\",\"b\"]", "[\"c\",\"d\"]", "[\"c\",\"d\"]"},
+ {"{\"a\":\"b\"}", "[\"c\"]", "[\"c\"]"},
+ {"{\"a\":\"foo\"}", "null", "null"},
+ {"{\"a\":\"foo\"}", "\"bar\"", "\"bar\""},
+ {"{\"e\":null}", "{\"a\":1}", "{\"e\":null,\"a\":1}"},
+ {"[1,2]", "{\"a\":\"b\",\"c\":null}", "{\"a\":\"b\"}"},
+ {"{}","{\"a\":{\"bb\":{\"ccc\":null}}}", "{\"a\":{\"bb\":{}}}"}};
+
/* Misc tests */
int numbers[10]={0,1,2,3,4,5,6,7,8,9};
@@ -113,4 +132,21 @@ int main()
after=cJSON_PrintUnformatted(sortme);
printf("Before: [%s]\nAfter: [%s]\n\n",before,after);
free(before);free(after);cJSON_Delete(sortme);
+
+ /* Merge tests: */
+ printf("JSON Merge Patch tests\n");
+ for (i=0;i<15;i++)
+ {
+ cJSON *object=cJSON_Parse(merges[i][0]);
+ cJSON *patch=cJSON_Parse(merges[i][1]);
+ char *before=cJSON_PrintUnformatted(object);
+ char *patchtext=cJSON_PrintUnformatted(patch);
+ printf("Before: [%s] -> [%s] = ",before,patchtext);
+ object=cJSONUtils_MergePatch(object,patch);
+ char *after=cJSON_PrintUnformatted(object);
+ printf("[%s] vs [%s] (%s)\n",after,merges[i][2],strcmp(after,merges[i][2])?"FAIL":"OK");
+
+ free(before);free(patchtext);free(after);cJSON_Delete(object);cJSON_Delete(patch);
+ }
+
}