cJSONUtils_MergePatch with tests from the RFC.

This commit is contained in:
Dave Gamble 2016-05-29 17:39:54 +01:00
parent 2fe50bd557
commit e79fa9472b
3 changed files with 55 additions and 0 deletions

View File

@ -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;
}

View File

@ -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. */

View File

@ -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);
}
}