diff --git a/api.c b/api.c index d697ed56835b2e28750ced7ed204162a42dd9968..cd46a5d00a736f1aad9dd4e111ba3b9b79894aee 100644 --- a/api.c +++ b/api.c @@ -66,126 +66,274 @@ out: return NULL; } +int get_idx(char *key, int *idx, char *out) +{ + char *open_brace; + int len = 0; + char buffer[64] = {0}; + char *ptr; + + printf("%s %d key=%s\n", __func__, __LINE__, key); + + if(!key) + return -1; + + + strncpy(buffer, key, sizeof(buffer) - 1); + ptr = (char *)buffer; + printf("%s %d ptr=%s\n", __func__, __LINE__, ptr); + + while((open_brace = strchr(ptr, '['))) { + char *close_brace = strchr(open_brace, ']'); + + if (close_brace) { + int str_len; + char *idx_str; + + str_len = close_brace - open_brace; + idx_str = calloc(1, str_len); + strncpy(idx_str, open_brace + 1, str_len-1); + idx[len++] = atoi(idx_str); + + *open_brace = '\0'; + free(idx_str); + ptr = close_brace; + } + } + + strncpy(out, buffer, 31); + printf("%s %d, out=%s, buffer=%s", __func__, __LINE__, out, buffer); + return len; +} + +struct json_object *dummy_val(char *val, enum json_type type) +{ + struct json_object *j_val; + + switch(type) { + case json_type_array: + j_val = json_tokener_parse(val); + break; + case json_type_boolean: + ;; + break; + case json_type_object: + j_val = json_tokener_parse(val); + break; + case json_type_string: + j_val = json_object_new_string(val); + break; + case json_type_double: + j_val = json_object_new_double(atof(val)); + break; + case json_type_int: + j_val = json_object_new_int(atoi(val)); + break; + default: + return NULL; + break; + } + + return j_val; +} + +int add_array(struct json_object *ptr, int *idx, int len, char *val, enum json_type type, char *key) +{ + struct json_object *tmp, *tmp1; + 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 (!tmp || !json_object_is_type(tmp, json_type_array)) { + tmp = json_object_new_array(); + json_object_object_add(ptr, key, tmp); + } + + for (int i = 0; i < len; i++) { + struct json_object *tmp1; + + tmp1 = json_object_array_get_idx(tmp, idx[i]); + printf("%s %d ptr = %s, tmp = %s\n", __func__, __LINE__, json_object_get_string(ptr), json_object_get_string(tmp)); + if (i < len -1) { + if (!tmp1 || !json_object_is_type(tmp1, json_type_array)) { + tmp1 = json_object_new_array(); + if (idx[i] > -1) + json_object_array_put_idx(tmp, idx[i], tmp1); + else + json_object_array_add(tmp, tmp1); + } + tmp = tmp1; + } else { + printf("%s %d ptr = %s, tmp = %s, tmp1=%s\n", __func__, __LINE__, json_object_get_string(ptr), json_object_get_string(tmp), json_object_get_string(tmp1)); + if (idx[i] > -1) + json_object_array_put_idx(tmp, idx[i], j_val); + else + json_object_array_add(tmp, j_val); + } + + } + + printf("%s %d ptr = %s, tmp = %s\n", __func__, __LINE__, json_object_get_string(ptr), json_object_get_string(tmp)); + + + return 0; +} + +int add_val(struct json_object *ptr, char *key, char *val, enum json_type type) +{ + struct json_object *j_val; + int idx[32]; + int len; + char parsed_key[32] = {0}; + + len = get_idx(key, idx, parsed_key); + printf("%s %d parsed_key=%s\n", __func__, __LINE__, parsed_key); + j_val = dummy_val(val, type); + if (!j_val || !json_object_is_type(j_val, type)) { + fprintf(stderr, "Invalid input value!\n"); + return -1; + } + + printf("%s %d val=%s, j_val=%s, ptr=%s\n", __func__, __LINE__, val, json_object_get_string(j_val), json_object_get_string(ptr)); + + if (json_type_object == type) { + printf("%s %d\n", __func__, __LINE__); + /* TODO: does this actually work? what would be the test case for this? */ + if (len < 1) { + struct json_object *tmp = ptr; + + if (key) + ptr = json_object_new_object(); + + json_object_object_foreach(j_val, key1, val1) + json_object_object_add(ptr, key1, val1); + if (key) { + printf("%s %d\n", __func__, __LINE__); + json_object_object_add(tmp, parsed_key, ptr); + } + } else { + printf("%s %d\n", __func__, __LINE__); + add_array(ptr, idx, len, val, type, parsed_key); + } + + return 0; + } + + + if (len < 1 || type == json_type_array) + json_object_object_add(ptr, parsed_key, j_val); + else { + add_array(ptr, idx, len, val, type, parsed_key); + } + + return 0; +} + int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type type) { - struct json_object *ptr, *tmp, *tar; + struct json_object *ptr, *tmp; const char *delimiter = "."; - char buffer[1024] = {0}; - char *p, *prev = fmt; + char fmt_cpy[1024] = {0}, parsed_key[32] = {0}; + char *p, *key = fmt; + int idx[32]; + int len; if (!*src) { printf("lets allocate new object\n"); *src = json_object_new_object(); } + printf("format = %s\n", fmt); + printf("set val = %s\n", val); + ptr = tmp = *src; + if (!fmt) + goto add_key; - strcpy(buffer, fmt); + strcpy(fmt_cpy, fmt); + p = strtok(fmt_cpy,delimiter); - p = strtok(buffer,delimiter); while (p != NULL) { - prev = p; + key = p; p = strtok(NULL, delimiter); - /* if next key exists, parse prev key, let switch-case add/alter last key */ + /* if next key exists, parse key, let switch-case add/alter last key */ if (p) { - json_object_object_get_ex(tmp, prev, &ptr); - - printf("p=%s\n", p); - - /* TODO: if prev contains [x], get idx of x */ - char *open_brace = strchr(prev, '['); - 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); - 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); - *open_brace = '\0'; - printf("prev=%s\n", prev); + /* TODO: pretty wonky order with get idx first to overwrite braces?*/ + + memset(idx, 0, sizeof(idx)); + + len = get_idx(key, idx, parsed_key); + + printf("parsed_key=%s\n", parsed_key); + printf("len=%d\n", len); + + /* if we need to step further and currently marked value isnt an object, we need to overwrite it */ + json_object_object_get_ex(tmp, parsed_key, &ptr); + if (!json_object_is_type(ptr, json_type_object) && !json_object_is_type(ptr, json_type_array)) { + ptr = json_object_new_object(); + json_object_object_add(tmp, parsed_key, ptr); + } + + + /* TODO: make enums for rv of get_idx */ + if (len > 0) { + for (int i = 0; i < len; i++) { + printf("%s %d, ptr = %s\n", __func__, __LINE__, json_object_get_string(ptr)); if (ptr && json_object_get_type(ptr) == json_type_array) { - ptr = json_object_array_get_idx(ptr, idx); + printf("%s %d\n", __func__, __LINE__); + if (idx[i] > -1 && idx[i] < json_object_array_length(ptr)) + ptr = json_object_array_get_idx(ptr, idx[i]); + else { + printf("%s %d\n", __func__, __LINE__); + if (i == len - 1) + json_object_array_add(ptr, json_object_new_object()); + else if (i < len -1) + json_object_array_add(ptr, json_object_new_array()); + 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(); - json_object_object_add(tmp, prev, ptr); + 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))); + printf("tmp=%s\n", json_object_get_string(tmp)); + printf("ptr=%s\n", json_object_get_string(ptr)); + printf("key=%s\n", key); + json_object_object_add(tmp, parsed_key, ptr); + if (i == len - 1) { + 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); } } } - /* create prev object if it does not exist */ + /* create key object if it does not exist */ if (!ptr) { ptr = json_object_new_object(); - json_object_object_add(tmp, prev, ptr); + 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, parsed_key, 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; } - json_object_object_get_ex(ptr, prev, &tar); - - switch(type) { - case json_type_object: - { - struct json_object *parsed_val = json_tokener_parse(val); - - if (!parsed_val) { - fprintf(stderr, "Invalid object format\n"); - return -1; - } else if (type != json_object_get_type(parsed_val)) { - fprintf(stderr, "Types don't match!\n"); - return -1; - } - - json_object_object_foreach(parsed_val, key1, val1) - json_object_object_add(*src, key1, val1); - } - break; - case json_type_string: - json_object_object_add(ptr, prev, json_object_new_string(val)); - break; - case json_type_int: - json_object_object_add(ptr, prev, json_object_new_int(atoi(val))); - break; - case json_type_array: - { - struct json_object *parsed_val = json_tokener_parse(val); - - if (!parsed_val) { - fprintf(stderr, "Invalid array format\n"); - return -1; - } else if (type != json_object_get_type(parsed_val)) { - fprintf(stderr, "Types don't match!\n"); - return -1; - } - - json_object_object_add(ptr, prev, parsed_val); - } - break; - case json_type_double: - json_object_object_add(ptr, prev, json_object_new_int(atof(val))); - break; - case json_type_boolean: - { - bool bool_val = false; - - if (strncasecmp(val, "true", 4) || atoi(val) == 1) - bool_val = true; + printf("%s %d key=%s\n", __func__, __LINE__, parsed_key); - - json_object_object_add(ptr, prev, json_object_new_boolean(bool_val)); - } - break; - default: - fprintf(stderr, "Not valid input type!\n"); - break; - } +add_key: +printf("%s %d\n", __func__, __LINE__); + add_val(ptr, key, val, type); return 0; } @@ -193,7 +341,7 @@ int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type int set(char *fmt, struct json_object *src, struct json_object *val) { const char *delimiter = "."; - char buffer[1024] = {0}; + char fmt_cpy[1024] = {0}; char *p; if (json_object_get_type(val) != json_type_object) { @@ -203,10 +351,10 @@ int set(char *fmt, struct json_object *src, struct json_object *val) src = get(fmt, src); - strcpy(buffer, fmt); + strcpy(fmt_cpy, fmt); /* TODO: put this in some separate function */ - for (p = strtok(buffer,delimiter); p != NULL; p = strtok(NULL, delimiter)) { + for (p = strtok(fmt_cpy,delimiter); p != NULL; p = strtok(NULL, delimiter)) { struct json_object *ptr, *tmp = src; json_object_object_get_ex(tmp, p, &ptr); @@ -228,11 +376,11 @@ struct json_object *get(char *fmt, struct json_object *src) { struct json_object *ptr, *tmp = src; const char *delimiter = "."; - char buffer[1024] = {0}; + char fmt_cpy[1024] = {0}; - strcpy(buffer, fmt); + strcpy(fmt_cpy, fmt); - for (char *p = strtok(buffer,delimiter); p != NULL; p = strtok(NULL, delimiter)) { + for (char *p = strtok(fmt_cpy,delimiter); p != NULL; p = strtok(NULL, delimiter)) { json_object_object_get_ex(tmp, p, &ptr); tmp = ptr; } @@ -242,18 +390,26 @@ struct json_object *get(char *fmt, struct json_object *src) int main() { - struct json_object *obj = path_to_obj("/home/jakob/git/json-editor-api/test.json"); + struct json_object *obj = path_to_obj("/home/jakob/git/json-editor/test.json"); struct json_object *ptr; - printf("%s %d obj=%s\n", __func__, __LINE__, json_object_get_string(obj)); + printf("%s %d\n", __func__, __LINE__); + struct json_object *arr = json_object_new_array(); + struct json_object *obj_arr = json_object_new_object(); + + json_object_object_add(obj_arr, "test_arr", arr); + printf("tets_arr = %s\n", json_object_get_string(obj_arr)); + + + printf("original obj=%s\n", json_object_get_string(obj)); ptr = get("nested", obj); printf("%s\n", json_object_get_string(ptr)); - set_by_string("nested.api[1].test", &obj, "1", json_type_string); + set_by_string("test.asd[-1].test.tested", &obj, "{\"api_test\":\"hej\"}", json_type_object); - printf("%s\n", json_object_get_string(obj)); + printf("result: %s\n", json_object_get_string(obj)); json_object_put(obj); return 0; diff --git a/test/api_test.c b/test/api_test.c index f7af316f2ec7e5ca7c7711e26870d0019bc90bd5..73bb48dbc46ca562dd246d6aeb592dec02ba65bb 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,118 @@ 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(); + struct json_object *obj = json_object_new_object(); + + json_object_array_add(arr, json_object_new_int(1)); + json_object_object_add(file_obj, "array", arr); + json_object_object_add(obj, "array", json_object_get(arr)); + json_object_object_add(file_obj, "inner", obj); + + set_by_string("array[-1]", &modify_obj, "1", json_type_int); + set_by_string("inner.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_array_add(arr, json_object_get(obj)); + json_object_array_add(arr, json_object_get(obj)); + json_object_array_add(arr, json_object_get(obj)); + json_object_object_add(file_obj, "array", arr); + + set_by_string(NULL, &modify_obj, "{\"array\": [{\"nested\": {\"nested1\": {\"integer\": 1}}}]}", json_type_object); + set_by_string("array[5].nested.nested1.integer", &modify_obj, "1", json_type_int); + set_by_string("array[-1].nested.nested1", &modify_obj, "{\"integer\": 1}", json_type_object); + set_by_string("array[-1].nested", &modify_obj, "{\"nested1\": {\"integer\": 1}}", json_type_object); + set_by_string("array[-1]", &modify_obj, "{\"nested\": {\"nested1\": {\"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 void test_json_add_array_nested_array(void **state) +{ + (void) state; + + struct json_object *arr = json_object_new_array(); + struct json_object *nested_arr = json_object_new_array(); + struct json_object *nested1_arr = json_object_new_array(); + + json_object_array_add(nested_arr, json_object_new_int(1)); + json_object_array_add(nested_arr, json_object_new_int(2)); + json_object_array_add(nested_arr, json_object_new_int(3)); + json_object_array_add(nested1_arr, json_object_new_int(5)); + json_object_array_add(nested1_arr, json_object_new_int(6)); + json_object_array_add(nested1_arr, json_object_new_int(7)); + + json_object_array_add(arr, nested_arr); + json_object_array_add(arr, nested1_arr); + + json_object_object_add(file_obj, "array", arr); + + //set_by_string("array[0][0].test", &modify_obj, "1", json_type_int); + set_by_string("array[0][0]", &modify_obj, "1", json_type_int); + set_by_string("array[0][1]", &modify_obj, "2", json_type_int); + set_by_string("array[0][2]", &modify_obj, "3", json_type_int); + + set_by_string("array[1][-1]", &modify_obj, "5", json_type_int); + set_by_string("array[1][-1]", &modify_obj, "6", json_type_int); + set_by_string("array[1][-1]", &modify_obj, "7", 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 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 +366,10 @@ 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), + cmocka_unit_test_setup_teardown(test_json_add_array_nested_array, setup, teardown), }; return cmocka_run_group_tests(tests, NULL, NULL);