From 5166b6dc8df51a2bb603946fdbf985275ce688b6 Mon Sep 17 00:00:00 2001
From: Jakob Olsson <jakob.olsson@iopsys.eu>
Date: Tue, 1 Oct 2019 10:40:41 +0200
Subject: [PATCH] pass null as fmt when adding json_type_object to root

---
 api.c           | 105 ++++++++++++++++++++++++++++++++----------------
 test/api_test.c |  82 ++++++++++++++++++++++++++++++++++---
 2 files changed, 148 insertions(+), 39 deletions(-)

diff --git a/api.c b/api.c
index 6fcd590..77b443c 100644
--- a/api.c
+++ b/api.c
@@ -68,20 +68,25 @@ out:
 
 int get_idx(char *key)
 {
+	if(!key)
+		return -2;
+
 	char *open_brace = strchr(key, '[');
-	printf("open_brace=%s\n", open_brace);
+
 	if (open_brace) {
 		char *close_brace = strchr(open_brace, ']');
+
 		if (close_brace) {
-			int len = close_brace - open_brace;
-			printf("len=%d\n", len);
-			char *idx_str = calloc(1, len);
+			int len, idx;
+			char *idx_str;
+
+			len = close_brace - open_brace;
+			idx_str = calloc(1, len);
 			strncpy(idx_str, open_brace + 1, len-1);
-			printf("idx_str = %s\n", idx_str);
-			int idx = atoi(idx_str);
-			printf("idx = %d\n", idx);
+			idx = atoi(idx_str);
+
 			*open_brace = '\0';
-			printf("key=%s\n", key);
+			free(idx_str);
 			return idx;
 		}
 	}
@@ -89,11 +94,10 @@ int get_idx(char *key)
 	return -2;
 }
 
-int add_array(struct json_object *ptr, int idx, char *val, enum json_type type, char *key)
+struct json_object *dummy_val(char *val, enum json_type type)
 {
-	struct json_object *tmp;
 	struct json_object *j_val;
-	printf("%s %d\n", __func__, __LINE__);
+
 	switch(type) {
 	case json_type_array:
 		j_val = json_tokener_parse(val);
@@ -111,23 +115,34 @@ int add_array(struct json_object *ptr, int idx, char *val, enum json_type type,
 		j_val = json_object_new_double(atof(val));
 	break;
 	case json_type_int:
-		j_val = json_object_new_double(atoi(val));
+		j_val = json_object_new_int(atoi(val));
 	break;
 	default:
-		return -1;
+		return NULL;
 	break;
 	}
-printf("%s %d\n", __func__, __LINE__);
+
+	return j_val;
+}
+
+int add_array(struct json_object *ptr, int idx, char *val, enum json_type type, char *key)
+{
+	struct json_object *tmp;
+	struct json_object *j_val;
+
+	j_val = dummy_val(val, type);
+	if (!j_val)
+		return -1;
+
 	json_object_object_get_ex(ptr, key, &tmp);
-	if (json_object_is_type(tmp, json_type_array)) {
-		if (tmp && idx != -1) {
+	if (tmp && json_object_is_type(tmp, json_type_array)) {
+		if (idx != -1)
 			json_object_array_put_idx(tmp, idx, j_val);
-		} else if (tmp && idx == -1) {
+		else {
 			printf("%s %d\n", __func__, __LINE__);
 			json_object_array_add(tmp, j_val);
 		}
 	} else {
-		printf("%s %d\n", __func__, __LINE__);
 		tmp = json_object_new_array();
 		json_object_array_add(tmp, j_val);
 		printf("%s %d type=%s, ptr_type=%s\n", __func__, __LINE__, json_type_to_name(json_object_get_type(tmp)), json_type_to_name(json_object_get_type(ptr)));
@@ -136,7 +151,7 @@ printf("%s %d\n", __func__, __LINE__);
 		printf("key=%s\n", key);
 		json_object_object_add(ptr, key, tmp);
 	}
-printf("%s %d\n", __func__, __LINE__);
+
 	return 0;
 }
 
@@ -157,10 +172,13 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 	printf("set val = %s\n", val);
 
 	ptr = tmp = *src;
-
+	if (!fmt)
+		goto add_key;
+	printf("%s %d\n", __func__, __LINE__);
 	strcpy(buffer, fmt);
-
+	printf("%s %d\n", __func__, __LINE__);
 	p = strtok(buffer,delimiter);
+	printf("%s %d\n", __func__, __LINE__);
 	while (p != NULL) {
 		prev = p;
 		p = strtok(NULL, delimiter);
@@ -172,19 +190,25 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 			json_object_object_get_ex(tmp, prev, &ptr);
 			/* if we need to step further and currently marked value isnt an object, we need to overwrite it */
 			if (!json_object_is_type(ptr, json_type_object) && !json_object_is_type(ptr, json_type_array)) {
-				printf("lets create new object hahah! key = %s\n", prev);
 				ptr = json_object_new_object();
 				json_object_object_add(tmp, prev, ptr);
 			}
 			printf("p=%s\n", p);
 
-			/* TODO: if prev contains [x], get idx of x */
-			printf("%s %d\n", __func__, __LINE__);
 			/* TODO: make enums for rv of get_idx */
 			if (idx != -2) {
+				printf("%s %d\n", __func__, __LINE__);
 				if (ptr && json_object_get_type(ptr) == json_type_array) {
 					printf("%s %d\n", __func__, __LINE__);
-					ptr = json_object_array_get_idx(ptr, idx);
+					if (idx > -1 && idx < json_object_array_length(ptr))
+						ptr = json_object_array_get_idx(ptr, idx);
+					else {
+						printf("%s %d\n", __func__, __LINE__);
+						json_object_array_add(ptr, json_object_new_object());
+						printf("ptr=%s\n", json_object_get_string(ptr));
+						ptr = json_object_array_get_idx(ptr, json_object_array_length(ptr) - 1);
+						printf("ptr=%s\n", json_object_get_string(ptr));
+					}
 				} else {
 					ptr = json_object_new_array();
 					printf("%s %d type=%s, ptr_type=%s\n", __func__, __LINE__, json_type_to_name(json_object_get_type(tmp)), json_type_to_name(json_object_get_type(ptr)));
@@ -192,6 +216,8 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 					printf("ptr=%s\n", json_object_get_string(ptr));
 					printf("prev=%s\n", prev);
 					json_object_object_add(tmp, prev, ptr);
+					json_object_array_add(ptr, json_object_new_object());
+					ptr = json_object_array_get_idx(ptr, json_object_array_length(ptr) - 1);
 					//json_object_array_add(tmp, ptr);
 				}
 			}
@@ -199,24 +225,30 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 			/* create prev object if it does not exist */
 			if (!ptr) {
 				ptr = json_object_new_object();
-				printf("%s %d\n", __func__, __LINE__);
 				if (json_object_get_type(tmp) == json_type_array)
 					json_object_array_add(tmp, ptr);
 				else if (json_object_get_type(tmp) == json_type_object)
 					json_object_object_add(tmp, prev, ptr);
+				printf("%s %d: ptr=%s\n", __func__, __LINE__, json_object_get_string(ptr));
+				printf("%s %d: tmp=%s\n", __func__, __LINE__, json_object_get_string(tmp));
 			}
 		}
 
 		tmp = ptr;
 	}
 
+	printf("%s %d prev=%s\n", __func__, __LINE__, prev);
+
 	json_object_object_get_ex(ptr, prev, &tar);
 
+add_key:
+printf("%s %d\n", __func__, __LINE__);
 	switch(type) {
 	case json_type_object:
 	{
 		struct json_object *parsed_val = json_tokener_parse(val);
 
+		printf("%s %d\n", __func__, __LINE__);
 		if (!parsed_val) {
 			fprintf(stderr, "Invalid object format\n");
 			return -1;
@@ -225,13 +257,18 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 			return -1;
 		}
 
+		printf("%s %d\n", __func__, __LINE__);
 		/* TODO: does this actually work? what would be the test case for this? */
 		idx = get_idx(prev);
+		printf("%s %d\n", __func__, __LINE__);
 		if (idx == -2) {
+			if (prev)
+				ptr = json_object_new_object();
 			json_object_object_foreach(parsed_val, key1, val1)
-				json_object_object_add(*src, key1, val1);
+				json_object_object_add(ptr, key1, val1);
+			if (prev)
+				json_object_object_add(tmp, prev, ptr);
 		} else {
-			printf("%s %d\n", __func__, __LINE__);
 			add_array(ptr, idx, val, type, prev);
 		}
 	}
@@ -246,11 +283,12 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 		}
 	break;
 	case json_type_int:
-		printf("%s %d\n", __func__, __LINE__);
+		printf("%s %d prev = %s\n", __func__, __LINE__, prev);
 		idx = get_idx(prev);
-		if (idx == -2)
+		if (idx == -2) {
+			printf("%s %d ptr=%s, idx=%d\n", __func__, __LINE__, json_object_get_string(ptr), idx);
 			json_object_object_add(ptr, prev, json_object_new_int(atoi(val)));
-		else {
+		} else {
 			printf("%s %d\n", __func__, __LINE__);
 			add_array(ptr, idx, val, type, prev);
 		}
@@ -273,12 +311,11 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type
 	case json_type_double:
 		idx = get_idx(prev);
 		if (idx == -2)
-			json_object_object_add(ptr, prev, json_object_new_int(atof(val)));
+			json_object_object_add(ptr, prev, json_object_new_double(atof(val)));
 		else {
 			printf("%s %d\n", __func__, __LINE__);
 			add_array(ptr, idx, val, type, prev);
 		}
-		
 	break;
 	case json_type_boolean:
 	{
@@ -368,7 +405,7 @@ int main()
 
 	printf("%s\n", json_object_get_string(ptr));
 
-	set_by_string("test.apdfgj[1].test", &obj, "gå och häng dig", json_type_string);
+	set_by_string("test.asd[-1].test.tested", &obj, "{\"api_test\":\"hej\"}", json_type_object);
 
 	printf("result: %s\n", json_object_get_string(obj));
 
diff --git a/test/api_test.c b/test/api_test.c
index f7af316..54756c0 100644
--- a/test/api_test.c
+++ b/test/api_test.c
@@ -43,18 +43,21 @@ static void test_build_from_scratch(void **state)
 	struct json_object *file = path_to_obj("/home/jakob/git/json-editor-api/test.json");
     struct json_object *jobj = NULL;
 
-    set_by_string("", &jobj, "{ \"test\":\"success\", \"nested\": { \"api\":\"test2\"} }", json_type_object);
+    set_by_string(NULL, &jobj, "{ \"test\":\"success\", \"nested\": { \"api\":\"test2\"} }", json_type_object);
 
-    assert_int_equal(1, json_object_equal(file, jobj));
+    printf("file_obj=%s\n", json_object_get_string(file));
+    printf("modify_obj=%s\n", json_object_get_string(jobj));
 
+    assert_int_equal(1, json_object_equal(file, jobj));
 }
 
 static void test_json_add_object(void **state)
 {
     (void) state;
 
-	//struct json_object *obj = json_object_new_object();
-    json_object_object_add(file_obj, "test2", json_object_new_string("success"));
+	struct json_object *obj = json_object_new_object();
+    json_object_object_add(obj, "test2", json_object_new_string("success"));
+    json_object_object_add(file_obj, "string", obj);
     //json_object_object_add(file_obj, "string", json_object_new_string("1"));
 
     set_by_string("string", &modify_obj, "{\"test2\":\"success\"}", json_type_object);
@@ -138,7 +141,7 @@ static void test_json_add_multi_obj(void **state)
     json_object_object_add(file_obj, "string", json_object_new_string("1"));
     json_object_object_add(file_obj, "integer", json_object_new_int(1));
 
-    set_by_string("", &modify_obj, "{ \"nested0\": {\"nested1\": {\"integer\": 1}}, \"ints\": [1, 2, 3], \"string\":\"1\", \"integer\": 1}", json_type_object);
+    set_by_string(NULL, &modify_obj, "{ \"nested0\": {\"nested1\": {\"integer\": 1}}, \"ints\": [1, 2, 3], \"string\":\"1\", \"integer\": 1}", json_type_object);
 
     printf("file_obj=%s\n", json_object_get_string(file_obj));
     printf("modify_obj=%s\n", json_object_get_string(modify_obj));
@@ -226,6 +229,72 @@ static void test_json_add_int_nested(void **state)
     assert_int_equal(1, json_object_equal(modify_obj, file_obj));
 }
 
+static void test_json_add_array_int(void **state)
+{
+    (void) state;
+
+    struct json_object *arr = json_object_new_array();
+
+    json_object_array_add(arr, json_object_new_int(1));
+    json_object_object_add(file_obj, "array", arr);
+
+    set_by_string("array[-1]", &modify_obj, "1", json_type_int);
+
+    printf("file_obj=%s\n", json_object_get_string(file_obj));
+    printf("modify_obj=%s\n", json_object_get_string(modify_obj));
+
+    assert_int_equal(1, json_object_equal(modify_obj, file_obj));
+}
+
+static void test_json_add_array_object(void **state)
+{
+    (void) state;
+
+    struct json_object *arr = json_object_new_array();
+    struct json_object *obj = json_object_new_object();
+
+    json_object_object_add(obj, "integer", json_object_new_int(1));
+    json_object_object_add(obj, "string", json_object_new_string("test"));
+
+    json_object_array_add(arr, obj);
+    json_object_array_add(arr, json_object_get(obj)); // array will now hold two references to the same object (will double free otherwise)
+    json_object_object_add(file_obj, "array", arr);
+
+    set_by_string("array[-1].integer", &modify_obj, "1", json_type_int);
+    set_by_string("array[0].string", &modify_obj, "test", json_type_string);
+    set_by_string("array[-1]", &modify_obj, "{\"integer\": 1, \"string\":\"test\"}", json_type_object);
+
+    printf("file_obj=%s\n", json_object_get_string(file_obj));
+    printf("modify_obj=%s\n", json_object_get_string(modify_obj));
+
+    assert_int_equal(1, json_object_equal(modify_obj, file_obj));
+}
+
+static void test_json_add_array_nested_object(void **state)
+{
+    (void) state;
+
+    struct json_object *arr = json_object_new_array();
+    struct json_object *obj = json_object_new_object();
+    struct json_object *nested = json_object_new_object();
+    struct json_object *nested1 = json_object_new_object();
+
+    json_object_object_add(nested, "integer", json_object_new_int(1));
+    json_object_object_add(nested1, "nested1", nested);
+    json_object_object_add(obj, "nested", nested1);
+    json_object_array_add(arr, obj);
+    json_object_array_add(arr, json_object_get(obj));
+    json_object_object_add(file_obj, "array", arr);
+
+    set_by_string("array[-1].nested.nested1.integer", &modify_obj, "1", json_type_int);
+    set_by_string("array[-1].nested.nested1", &modify_obj, "{\"integer\": 1}", json_type_object);
+
+    printf("file_obj=%s\n", json_object_get_string(file_obj));
+    printf("modify_obj=%s\n", json_object_get_string(modify_obj));
+
+    assert_int_equal(1, json_object_equal(modify_obj, file_obj));
+}
+
 static int setup (void** state) {
     file_obj = path_to_obj("/home/jakob/git/json-editor-api/test.json");
     modify_obj = path_to_obj("/home/jakob/git/json-editor-api/test.json");
@@ -251,6 +320,9 @@ int main(void) {
         cmocka_unit_test_setup_teardown(test_json_add_multi_types, setup, teardown),
         cmocka_unit_test_setup_teardown(test_json_add_multi_obj, setup, teardown),
         cmocka_unit_test_setup_teardown(test_json_overwrite_string, setup, teardown),
+        cmocka_unit_test_setup_teardown(test_json_add_array_int, setup, teardown),
+        cmocka_unit_test_setup_teardown(test_json_add_array_object, setup, teardown),
+        cmocka_unit_test_setup_teardown(test_json_add_array_nested_object, setup, teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
GitLab