Skip to content
Snippets Groups Projects
Commit 09b28bee authored by Jakob Olsson's avatar Jakob Olsson
Browse files

add object, string and integer manipulation via string format

parent fd93c21b
No related branches found
No related tags found
No related merge requests found
Pipeline #117 failed
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
PROJECT(json-editor)
#set version
SET(MAJOR_VERSION 1)
SET(MINOR_VERSION 0)
SET(PATCH_VERSION 0)
#EXEC_PROGRAM("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "log HEAD --format=format:%H -1" OUTPUT_VARIABLE GIT_SHA1)
#ADD_DEFINITIONS(-D_PROJECT_NAME="${PROJECT_NAME}")
#ADD_DEFINITIONS(-D_PROJECT_VERSION="${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")
#ADD_DEFINITIONS(-D_GIT_SHA1="${GIT_SHA1}")
#set compile flags
SET(DEFAULT_FLAGS "--std=gnu99")
SET(RELEASE_FLAGS "-Wno-long-long -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Werror-implicit-function-declaration -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common -Wsign-compare -Wunused-result")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEFAULT_FLAGS} -Wall")
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os ${DEFAULT_FLAGS} ${RELEASE_FLAGS}")
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${DEFAULT_FLAGS} ${RELEASE_FLAGS}")
SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${DEFAULT_FLAGS} ${RELEASE_FLAGS}")
#INCLUDE(LogOptions.cmake)
#create executable
FILE(GLOB SOURCES "*.c" "*.h")
ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES})
#link libraries
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
find_library(JSON_LIBRARIES NAMES json-c)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${JSON_LIBRARIES})
#testing
IF(CMAKE_BUILD_TYPE STREQUAL Debug)
OPTION(ENABLE_BUILD_TESTS "Build tests" ON)
# OPTION(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
ELSE()
OPTION(ENABLE_BUILD_TESTS "Build tests" OFF)
# OPTION(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
ENDIF()
IF(ENABLE_BUILD_TESTS)
FIND_PACKAGE(CMocka)
if(CMOCKA_FOUND)
ADD_LIBRARY(${PROJECT_NAME}-api SHARED ${SOURCES})
MESSAGE("-- Building tests")
ENABLE_TESTING()
ADD_SUBDIRECTORY(test)
ELSE(CMOCKA_FOUND)
MESSAGE("-- CMocka not found")
ENDIF(CMOCKA_FOUND)
ENDIF(ENABLE_BUILD_TESTS)
#install
#INSTALL(TARGETS imonitor RUNTIME DESTINATION bin)
api.c 0 → 100644
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <json-c/json.h>
#include "api.h"
/* will allocate memory! remember to free! */
char *get_file(const char *path)
{
FILE *f;
size_t len, nread;
char *buffer;
f = fopen(path, "r");
if (!f)
goto out;
if (fseek(f, 0, SEEK_END))
goto out_close;
len = ftell(f);
if (len < 0)
goto out_close;
if (fseek(f, 0, SEEK_SET))
goto out_close;
buffer = calloc(1, len);
if (!buffer)
goto out_close;
nread = fread(buffer, sizeof(char), len, f);
if (nread < len)
goto out_free;
fclose(f);
return buffer;
out_free:
free(buffer);
out_close:
fclose(f);
out:
return NULL;
}
struct json_object *path_to_obj(const char *path)
{
struct json_object *obj;
char *file_str;
file_str = get_file(path);
if (!file_str)
goto out;
obj = json_tokener_parse(file_str);
free(file_str);
return obj;
out:
return NULL;
}
int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type type)
{
struct json_object *ptr, *tmp, *tar;
const char *delimiter = ".";
char buffer[1024] = {0};
char *p, *prev = fmt;
if (!*src) {
printf("lets allocate new object\n");
*src = json_object_new_object();
}
ptr = tmp = *src;
strcpy(buffer, fmt);
p = strtok(buffer,delimiter);
while (p != NULL) {
prev = p;
p = strtok(NULL, delimiter);
/* if next key exists, parse prev 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);
if (ptr && json_object_get_type(ptr) == json_type_array) {
ptr = json_object_array_get_idx(ptr, idx);
} else {
ptr = json_object_new_array();
json_object_object_add(tmp, prev, ptr);
}
}
}
/* create prev object if it does not exist */
if (!ptr) {
ptr = json_object_new_object();
json_object_object_add(tmp, prev, ptr);
}
}
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;
json_object_object_add(ptr, prev, json_object_new_boolean(bool_val));
}
break;
default:
fprintf(stderr, "Not valid input type!\n");
break;
}
return 0;
}
int set(char *fmt, struct json_object *src, struct json_object *val)
{
const char *delimiter = ".";
char buffer[1024] = {0};
char *p;
if (json_object_get_type(val) != json_type_object) {
fprintf(stderr, "object must be of type object!\n");
return -1;
}
src = get(fmt, src);
strcpy(buffer, fmt);
/* TODO: put this in some separate function */
for (p = strtok(buffer,delimiter); p != NULL; p = strtok(NULL, delimiter)) {
struct json_object *ptr, *tmp = src;
json_object_object_get_ex(tmp, p, &ptr);
if (!ptr) {
ptr = json_object_new_object();
json_object_object_add(tmp, p, ptr);
}
tmp = ptr;
}
json_object_object_foreach(val, key, val1)
json_object_object_add(src, key, val1);
return 0;
}
struct json_object *get(char *fmt, struct json_object *src)
{
struct json_object *ptr, *tmp = src;
const char *delimiter = ".";
char buffer[1024] = {0};
strcpy(buffer, fmt);
for (char *p = strtok(buffer,delimiter); p != NULL; p = strtok(NULL, delimiter)) {
json_object_object_get_ex(tmp, p, &ptr);
tmp = ptr;
}
return ptr;
}
int main()
{
struct json_object *obj = path_to_obj("/home/jakob/git/json-editor-api/test.json");
struct json_object *ptr;
printf("%s %d obj=%s\n", __func__, __LINE__, 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);
printf("%s\n", json_object_get_string(obj));
json_object_put(obj);
return 0;
}
api.h 0 → 100644
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <json-c/json.h>
char *get_file(const char *path);
struct json_object *path_to_obj(const char *path);
int set_by_string(char *fmt, struct json_object **src, char *val, enum json_type type);
int set(char *fmt, struct json_object *src, struct json_object *val);
struct json_object *get(char *fmt, struct json_object *src);
# CMOCKA_FOUND - System has CMocka
# CMOCKA_INCLUDE_DIRS - The CMocka include directories
# CMOCKA_LIBRARIES - The libraries needed to use CMocka
# CMOCKA_DEFINITIONS - Compiler switches required for using CMocka
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_CMOCKA QUIET cmocka)
set(CMOCKA_DEFINITIONS ${PC_CMOCKA_CFLAGS_OTHER})
endif()
find_path(CMOCKA_INCLUDE_DIR cmocka.h
HINTS ${PC_CMOCKA_INCLUDEDIR} ${PC_CMOCKA_INCLUDE_DIRS}
PATH_SUFFIXES cmocka)
find_library(CMOCKA_LIBRARY NAMES cmocka
HINTS ${PC_CMOCKA_LIBDIR} ${PC_CMOCKA_LIBRARY_DIRS})
set(CMOCKA_LIBRARIES ${CMOCKA_LIBRARY})
set(CMOCKA_INCLUDE_DIRS ${CMOCKA_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cmocka DEFAULT_MSG
CMOCKA_LIBRARY CMOCKA_INCLUDE_DIR)
mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARY)
\ No newline at end of file
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
#INCLUDE_DIRECTORIES ("${PROJECT_SOURCE_DIR}/src")
INCLUDE_DIRECTORIES ("${PROJECT_SOURCE_DIR}")
#FILE(COPY files DESTINATION .)
find_library(JSON_LIBRARIES NAMES json-c)
SET(api_tests api_test)
FOREACH(test_name IN LISTS api_tests)
ADD_EXECUTABLE(${test_name} ${test_name}.c)
TARGET_LINK_LIBRARIES(
${test_name}
${CMOCKA_LIBRARIES}
json-editor-api
${JSON_LIBRARIES}
)
ADD_TEST(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
ENDFOREACH(test_name)
#SET(COVERAGE_EXCLUDES 'src/main.c' '/usr/include/*')
#SETUP_TARGET_FOR_COVERAGE(
# NAME test_coverage
# EXECUTABLE ctest
# DEPENDENCIES owsd-api
#)
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <json-c/json.h>
#include <libwebsockets.h>
#include "api.h"
struct json_object *file_obj, *modify_obj;
static void test_cfg_parse_success(void **state)
{
(void) state; /* unused */
struct json_object *file = path_to_obj("/home/jakob/git/json-editor-api/test.json");
struct json_object *obj = json_object_new_object();
struct json_object *tot = json_object_new_object();
json_object_object_add(obj, "api", json_object_new_string("test2"));
json_object_object_add(tot, "nested", obj);
json_object_object_add(tot, "test", json_object_new_string("success"));
assert_int_equal(1, json_object_equal(file, tot));
}
static void test_cfg_parse_fail(void **state)
{
(void) state; /* unused */
struct json_object *obj = path_to_obj("NON_EXISTENT_FILE");
assert_null(obj);
if (obj)
json_object_put(obj);
}
static void test_build_from_scratch(void **state)
{
(void) state; /* unused */
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);
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"));
//json_object_object_add(file_obj, "string", json_object_new_string("1"));
set_by_string("string", &modify_obj, "{\"test2\":\"success\"}", 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(void **state)
{
(void) state;
struct json_object *arr = json_object_new_array();
json_object_array_add(arr, json_object_new_int(1));
json_object_array_add(arr, json_object_new_int(2));
json_object_array_add(arr, json_object_new_int(3));
json_object_object_add(file_obj, "ints", arr);
//json_object_object_add(file_obj, "string", json_object_new_string("1"));
set_by_string("ints", &modify_obj, "[ 1, 2, 3 ]", json_type_array);
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_multi_types(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();
json_object_object_add(nested, "integer", json_object_new_int(1));
json_object_object_add(obj, "nested1", nested);
json_object_object_add(file_obj, "nested0", obj);
json_object_array_add(arr, json_object_new_int(1));
json_object_array_add(arr, json_object_new_int(2));
json_object_array_add(arr, json_object_new_int(3));
json_object_object_add(file_obj, "ints", arr);
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("nested0.nested1.integer", &modify_obj, "1", json_type_int);
set_by_string("ints", &modify_obj, "[ 1, 2, 3 ]", json_type_array);
set_by_string("string", &modify_obj, "1", json_type_string);
set_by_string("integer", &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_multi_obj(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();
json_object_object_add(nested, "integer", json_object_new_int(1));
json_object_object_add(obj, "nested1", nested);
json_object_object_add(file_obj, "nested0", obj);
json_object_array_add(arr, json_object_new_int(1));
json_object_array_add(arr, json_object_new_int(2));
json_object_array_add(arr, json_object_new_int(3));
json_object_object_add(file_obj, "ints", arr);
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);
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_string(void **state)
{
(void) state;
//struct json_object *obj = json_object_new_object();
json_object_object_add(file_obj, "string", json_object_new_string("1"));
set_by_string("string", &modify_obj, "1", json_type_string);
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_overwrite_string(void **state)
{
(void) state;
//struct json_object *obj = json_object_new_object();
json_object_object_add(file_obj, "test", json_object_new_string("1"));
set_by_string("test", &modify_obj, "1", json_type_string);
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));
//json_object_object_add(file_obj, "test", json_object_new_string("1"));
struct json_object *obj, *nested;
json_object_object_get_ex(file_obj, "nested", &nested);
json_object_object_get_ex(nested, "api", &obj);
json_object_set_string(obj, "2");
set_by_string("nested.api", &modify_obj, "2", json_type_string);
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_int(void **state)
{
(void) state;
//struct json_object *obj = json_object_new_object();
json_object_object_add(file_obj, "integer", json_object_new_int(1));
set_by_string("integer", &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_int_nested(void **state)
{
(void) state;
struct json_object *obj = json_object_new_object();
struct json_object *nested = json_object_new_object();
json_object_object_add(nested, "integer", json_object_new_int(1));
json_object_object_add(obj, "nested1", nested);
json_object_object_add(file_obj, "nested0", obj);
set_by_string("nested0.nested1.integer", &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 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");
return 0;
}
static int teardown (void** state) {
json_object_put(file_obj);
json_object_put(modify_obj);
return 0;
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_cfg_parse_success),
cmocka_unit_test(test_cfg_parse_fail),
cmocka_unit_test(test_build_from_scratch),
cmocka_unit_test_setup_teardown(test_json_add_int, setup, teardown),
cmocka_unit_test_setup_teardown(test_json_add_int_nested, setup, teardown),
cmocka_unit_test_setup_teardown(test_json_add_string, setup, teardown),
cmocka_unit_test_setup_teardown(test_json_add_object, setup, teardown),
cmocka_unit_test_setup_teardown(test_json_add_array, setup, teardown),
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),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment