Jelajahi Sumber

cJSONUtils_MergePatch with tests from the RFC.

Dave Gamble 9 tahun lalu
induk
melakukan
e79fa9472b
3 mengubah file dengan 55 tambahan dan 0 penghapusan
  1. 16 0
      cJSON_Utils.c
  2. 3 0
      cJSON_Utils.h
  3. 36 0
      test_utils.c

+ 16 - 0
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;
+}

+ 3 - 0
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.	*/

+ 36 - 0
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);
+	}
+
 }