summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Bollo <jose.bollo@iot.bzh>2018-07-12 10:59:48 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2018-07-24 16:28:32 +0200
commite17ae412245ba9afb33ff6a0f1f665b4d66d4da4 (patch)
tree698628c58b541007033ede6b4343dae921214da6
parent4c0f6ce66c66d39dc61ec661d88277c51d2fd9ae (diff)
coverage and test: Add tests
coverage values: - lines: 70.5 % - functions: 76.3 % Change-Id: Iaf802e84bbfa57502bbbac8c3b567b14c01608b6 Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
-rw-r--r--bindings/samples/hello3.c312
-rw-r--r--coverage/.gitignore11
-rw-r--r--coverage/Makefile7
-rw-r--r--coverage/bin/Makefile122
-rw-r--r--coverage/bin/bug.c270
l---------coverage/bin/fake/monitoring1
-rw-r--r--coverage/bin/loc.txt0
-rw-r--r--coverage/bin/locales/en/loc.txt0
-rw-r--r--coverage/bin/locales/fr-FR/loc.txt0
-rw-r--r--coverage/bin/locales/fr/loc.txt0
-rw-r--r--coverage/bin/locales/jp/loc.txt0
l---------coverage/ldpath/weak/bug.so1
l---------coverage/ldpath/weak/bugs1
-rwxr-xr-xcoverage/scripts/00-trace.sh7
-rwxr-xr-xcoverage/scripts/01-http.sh28
-rwxr-xr-xcoverage/scripts/02-hello.sh44
-rwxr-xr-xcoverage/scripts/03-auto-ws.sh (renamed from coverage/scripts/03-x-hello.sh)0
-rwxr-xr-xcoverage/scripts/06-auto-so.sh35
-rwxr-xr-xcoverage/scripts/run-test.sh65
-rw-r--r--src/tests/wrap-json/CMakeLists.txt23
-rw-r--r--src/tests/wrap-json/test-wrap-json.c331
21 files changed, 1211 insertions, 47 deletions
diff --git a/bindings/samples/hello3.c b/bindings/samples/hello3.c
index f49b3365..477e47bd 100644
--- a/bindings/samples/hello3.c
+++ b/bindings/samples/hello3.c
@@ -18,14 +18,24 @@
#include <stdio.h>
#include <string.h>
#include <pthread.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <json-c/json.h>
#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
+#if !defined(APINAME)
+#define APINAME "hello3"
+#endif
+
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+/**************************************************************************/
+
struct event
{
struct event *next;
@@ -116,6 +126,30 @@ static int event_broadcast(struct json_object *args, const char *tag)
return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
}
+/**************************************************************************/
+
+struct api
+{
+ struct api *next;
+ afb_api_t api;
+ char name[1];
+};
+
+static struct api *apis = 0;
+
+/* search the api of name */
+static struct api *searchapi(const char *name, struct api ***previous)
+{
+ struct api *a, **p = &apis;
+ while((a = *p) && strcmp(a->name, name))
+ p = &a->next;
+ if (previous)
+ *previous = p;
+ return a;
+}
+
+/**************************************************************************/
+
// Sample Generic Ping Debug API
static void ping(afb_req_t request, json_object *jresp, const char *tag)
{
@@ -451,23 +485,107 @@ static void info (afb_req_t request)
afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
}
-static int preinit(afb_api_t api)
+static void eventloop (afb_req_t request)
{
- AFB_NOTICE("hello binding comes to live");
- return 0;
+ afb_api_t api = afb_req_get_api(request);
+ struct sd_event *ev = afb_api_get_event_loop(api);
+ afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
}
-static int init(afb_api_t api)
+static void dbus (afb_req_t request)
{
- AFB_NOTICE("hello binding starting");
- return 0;
+ afb_api_t api = afb_req_get_api(request);
+ json_object *json = afb_req_json(request);
+ struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
+ afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
}
-static void onevent(afb_api_t api, const char *event, struct json_object *object)
+static void replycount (afb_req_t request)
{
- AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+ json_object *json = afb_req_json(request);
+ int count = json_object_get_int(json);
+ while (count-- > 0)
+ afb_req_reply(request, NULL, NULL, NULL);
}
+static void get(afb_req_t request)
+{
+ struct afb_arg arg = afb_req_get(request, "name");
+ const char *name, *value, *path;
+
+ if (!arg.name || !arg.value)
+ afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
+ else {
+ name = arg.name;
+ value = afb_req_value(request, name);
+ path = afb_req_path(request, name);
+ afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
+ }
+}
+
+static void ref(afb_req_t request)
+{
+ afb_req_addref(request);
+ afb_req_reply(request, NULL, NULL, NULL);
+ afb_req_unref(request);
+}
+
+static void rootdir (afb_req_t request)
+{
+ ssize_t s;
+ afb_api_t api = afb_req_get_api(request);
+ int fd = afb_api_rootdir_get_fd(api);
+ char buffer[150], root[1025];
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+}
+
+static void locale (afb_req_t request)
+{
+ char buffer[150], root[1025];
+ const char *lang, *file;
+ ssize_t s;
+ json_object *json = afb_req_json(request), *x;
+ afb_api_t api = afb_req_get_api(request);
+ int fd;
+
+ lang = NULL;
+ if (json_object_is_type(json, json_type_string))
+ file = json_object_get_string(json);
+ else {
+ if (!json_object_object_get_ex(json, "file", &x)) {
+ afb_req_reply(request, NULL, "invalid", "no file");
+ return;
+ }
+ file = json_object_get_string(x);
+ if (json_object_object_get_ex(json, "lang", &x))
+ lang = json_object_get_string(x);
+ }
+
+ fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
+ if (fd < 0)
+ afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
+ else {
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+ close(fd);
+ }
+}
+
+static void api (afb_req_t request);
+
// NOTE: this sample does not use session to keep test a basic as possible
// in real application most APIs should be protected with AFB_SESSION_CHECK
static const struct afb_verb_v3 verbs[]= {
@@ -499,12 +617,186 @@ static const struct afb_verb_v3 verbs[]= {
{ .verb="setctxif", .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
{ .verb="getctx", .callback=getctx },
{ .verb="info", .callback=info },
+ { .verb="eventloop", .callback=eventloop },
+ { .verb="dbus", .callback=dbus },
+ { .verb="reply-count", .callback=replycount },
+ { .verb="get", .callback=get},
+ { .verb="ref", .callback=ref},
+ { .verb="rootdir", .callback=rootdir},
+ { .verb="locale", .callback=locale},
+ { .verb="api", .callback=api},
{ .verb=NULL}
};
-#if !defined(APINAME)
-#define APINAME "hello3"
+static void pingSample2 (struct afb_req_x1 req)
+{
+ pingSample(req.closure);
+}
+
+static const struct afb_verb_v2 apiverbs2[]= {
+ { .verb="ping", .callback=pingSample2 },
+ { .verb="ping2", .callback=pingSample2 },
+ { .verb=NULL }
+};
+
+static int apipreinit(void *closure, afb_api_t api)
+{
+ afb_api_set_verbs_v2(api, apiverbs2);
+ afb_api_set_verbs_v3(api, verbs);
+ return 0;
+}
+
+static void apiverb (afb_req_t request)
+{
+ afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
+ afb_req_get_called_api(request), afb_req_get_called_verb(request));
+}
+
+static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
+{
+ struct json_object *obj = closure;
+ afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
+ json_object_get_string(obj), event, json_object_get_string(args));
+}
+
+static void api (afb_req_t request)
+{
+ struct api *sapi, **psapi;
+ const char *action, *apiname, *verbname, *pattern;
+ json_object *json = afb_req_json(request), *x, *closure;
+ afb_api_t api = afb_req_get_api(request), oapi;
+
+ /* get the action */
+ if (!json_object_object_get_ex(json, "action", &x)) {
+ afb_req_reply(request, NULL, "invalid", "no action");
+ goto end;
+ }
+ action = json_object_get_string(x);
+
+ /* get the verb */
+ verbname = json_object_object_get_ex(json, "verb", &x) ?
+ json_object_get_string(x) : NULL;
+
+ /* get the pattern */
+ pattern = json_object_object_get_ex(json, "pattern", &x) ?
+ json_object_get_string(x) : NULL;
+
+ /* get the closure */
+ closure = NULL;
+ json_object_object_get_ex(json, "closure", &closure);
+
+ /* get the api */
+ if (json_object_object_get_ex(json, "api", &x)) {
+ apiname = json_object_get_string(x);
+ sapi = searchapi(apiname, &psapi);
+ oapi = sapi ? sapi->api : NULL;
+ } else {
+ oapi = api;
+ apiname = afb_api_name(api);
+ sapi = searchapi(apiname, &psapi);
+ }
+
+ /* search the sapi */
+ if (!strcasecmp(action, "create")) {
+ if (!apiname) {
+ afb_req_reply(request, NULL, "invalid", "no api");
+ goto end;
+ }
+ if (sapi) {
+ afb_req_reply(request, NULL, "already-exist", NULL);
+ goto end;
+ }
+ sapi = malloc (sizeof * sapi + strlen(apiname));
+ if (!sapi) {
+ afb_req_reply(request, NULL, "out-of-memory", NULL);
+ goto end;
+ }
+ sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
+ if (!sapi->api) {
+ afb_req_reply_f(request, NULL, "cant-create", "%m");
+ goto end;
+ }
+ strcpy(sapi->name, apiname);
+ sapi->next = NULL;
+ *psapi = sapi;
+ } else {
+ if (!oapi) {
+ afb_req_reply(request, NULL, "cant-find-api", NULL);
+ goto end;
+ }
+ if (!strcasecmp(action, "destroy")) {
+ if (!sapi) {
+ afb_req_reply(request, NULL, "cant-destroy", NULL);
+ goto end;
+ }
+ afb_api_delete_api(oapi);
+ *psapi = sapi->next;
+ free(sapi);
+ } else if (!strcasecmp(action, "addverb")) {
+ if (!verbname){
+ afb_req_reply(request, NULL, "invalid", "no verb");
+ goto end;
+ }
+ afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
+ } else if (!strcasecmp(action, "delverb")) {
+ if (!verbname){
+ afb_req_reply(request, NULL, "invalid", "no verb");
+ goto end;
+ }
+ afb_api_del_verb(oapi, verbname, NULL);
+ } else if (!strcasecmp(action, "addhandler")) {
+ if (!pattern){
+ afb_req_reply(request, NULL, "invalid", "no pattern");
+ goto end;
+ }
+ afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
+ } else if (!strcasecmp(action, "delhandler")) {
+ if (!pattern){
+ afb_req_reply(request, NULL, "invalid", "no pattern");
+ goto end;
+ }
+ closure = NULL;
+ afb_api_event_handler_del(oapi, pattern, (void**)&closure);
+ json_object_put(closure);
+ } else if (!strcasecmp(action, "seal")) {
+ afb_api_seal(oapi);
+ } else {
+ afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
+ goto end;
+ }
+ }
+ afb_req_reply(request, NULL, NULL, NULL);
+end: return;
+}
+
+/*************************************************************/
+
+static int preinit(afb_api_t api)
+{
+ AFB_NOTICE("hello binding comes to live");
+#if defined(PREINIT_PROVIDE_CLASS)
+ afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
+#endif
+#if defined(PREINIT_REQUIRE_CLASS)
+ afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
+#endif
+ return 0;
+}
+
+static int init(afb_api_t api)
+{
+ AFB_NOTICE("hello binding starting");
+#if defined(INIT_REQUIRE_API)
+ afb_api_require_api(api, INIT_REQUIRE_API, 1);
#endif
+ afb_api_add_alias(api, api->apiname, "fakename");
+ return 0;
+}
+
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
+{
+ AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+}
const struct afb_binding_v3 afbBindingV3 = {
.api = APINAME,
diff --git a/coverage/.gitignore b/coverage/.gitignore
index 43d04cb6..69f6ea4f 100644
--- a/coverage/.gitignore
+++ b/coverage/.gitignore
@@ -1,3 +1,14 @@
lcov-out.info
report/
valgrind.out
+bin/bugs
+run-test.output
+bin/afb-client
+bin/afb-daemon-cov
+bin/test-apiset
+bin/test-session
+bin/test-wrap-json
+*.o
+*.so
+*.gcda
+*.gcno
diff --git a/coverage/Makefile b/coverage/Makefile
index 3f5f3ce3..30477a70 100644
--- a/coverage/Makefile
+++ b/coverage/Makefile
@@ -14,7 +14,8 @@ clean:
make -C bin -w clean
cleanall: clean
- rm -rf lcov-out.info report valgrind.out
+ @echo remove all outputs and reports
+ @rm -rf lcov-out.info report valgrind.out 2>/dev/null || true
.PHONY: test
@@ -22,14 +23,12 @@ test: binaries
@echo -----------------------------------------
@echo -- BEGIN TEST
@echo -----------------------------------------
- @scripts/run-test.sh
+ @scripts/run-test.sh 2>&1 | tee run-test.output
@echo -----------------------------------------
@echo -- END TEST
@echo -----------------------------------------
report: test
- @echo generating LCOV report
- @lcov -c -d bin -o lcov-out.info
@echo generating report
@genhtml -s -o report lcov-out.info
@echo ready: xdg-open report/index.html
diff --git a/coverage/bin/Makefile b/coverage/bin/Makefile
index 19bf254a..f9d561ed 100644
--- a/coverage/bin/Makefile
+++ b/coverage/bin/Makefile
@@ -4,41 +4,102 @@
heredir = .
basedir = ../..
-targets = afb-daemon-cov afb-client hi3.so hello.so salut.so salam.so shalom.so demat.so bug.so hellov2.so
+bindings = \
+ hi3.so \
+ hello.so \
+ salut.so \
+ salam.so \
+ shalom.so \
+ demat.so \
+ hellov2.so
+
+bugs = $(foreach i,\
+ 1 2 3 4 5 6 7 8 9 \
+ 10 11 12 13 14 15 16 17 18 19 \
+ 20 21, \
+ bugs/bug$i.so)
+
+tests = \
+ test-apiset \
+ test-session \
+ test-wrap-json
+
+targets = \
+ afb-daemon-cov \
+ afb-client \
+ $(tests) \
+ $(bindings) \
+ $(bugs)
binaries: $(targets)
clean:
- @rm $(targets) *.gcno *.gcda
+ @echo remove all binaries
+ @rm $(targets) *.gcno *.gcda *.o 2>/dev/null || true
#======================================================================================
-# creates the targets
+# definitions
#======================================================================================
incdir = $(basedir)/include
srcdir = $(basedir)/src
+tstdir = $(basedir)/src/tests
samdir = $(basedir)/bindings/samples
bindir = $(heredir)/bin
-cflags = -I$(incdir) \
- $(shell pkg-config --cflags --libs openssl libmicrohttpd json-c libsystemd uuid) \
- -ldl -lrt -lpthread
+deps = openssl libmicrohttpd json-c libsystemd uuid
+
+ccflags = \
+ -g \
+ -I$(incdir) \
+ $(shell pkg-config --cflags $(deps))
+
+ldflags = -ldl -lrt -lpthread \
+ $(shell pkg-config --libs $(deps))
+
+cflags = $(ccflags) $(ldflags)
+
+defs = -DAGL_DEVEL \
+ -DWITH_MONITORING_OPTION \
+ -DWITH_SUPERVISION \
+ -DAFB_VERSION=\"cov\" \
+ -DBINDING_INSTALL_DIR=\"$(shell pwd)/fake\"
afb_lib_src = $(shell ls $(srcdir)/*.c | egrep -v '/afs-|/main-' )
-afb_clib_src = $(shell ls $(srcdir)/*.c | egrep -v '/afs-|/main-' )
+afb_lib_obj = $(patsubst $(srcdir)/%.c,%.o,$(afb_lib_src))
+afb_lib = afb-lib.a
+afb_lib_defs = $(defs)
+
+afb_daemon_srcs = $(srcdir)/main-afb-daemon.c $(afb_lib_obj)
+afb_daemon_defs = $(afb_lib_defs)
-afb_daemon_srcs = $(srcdir)/main-afb-daemon.c $(afb_lib_src)
-afb_daemon_defs = '-DAFB_VERSION="cov"' -DAGL_DEVEL -DWITH_MONITORING_OPTION '-DBINDING_INSTALL_DIR="fake"'
+afb_client_srcs = $(srcdir)/main-afb-client-demo.c $(afb_lib_src)
+afb_client_defs = $(defs)
-afb_client_srcs = $(srcdir)/main-afb-client-demo.c $(afb_clib_src)
-afb_client_defs = '-DAFB_VERSION="cov"' '-DBINDING_INSTALL_DIR="fake"'
+tst_defs = $(defs)
+tst_flags = $(cflags) \
+ -I$(srcdir) \
+ $(shell pkg-config --cflags --libs check)
+
+tst_defs = '-DAFB_VERSION="cov"' '-DBINDING_INSTALL_DIR="fake"'
+tst_flags = $(cflags) \
+ -I$(srcdir) \
+ $(shell pkg-config --cflags --libs check)
hello2_src = $(samdir)/hello2.c
hello3_src = $(samdir)/hello3.c
hi_src = $(samdir)/hi3.c
binding_flags = -shared -fPIC -Wl,--version-script=$(samdir)/export.map
+#======================================================================================
+# creates the targets
+#======================================================================================
+
+%.o: $(srcdir)/%.c
+ @echo creation of $@
+ @gcc -c -o $@ $< --coverage $(afb_lib_defs) $(ccflags)
+
afb-daemon-cov: $(afb_daemon_srcs)
@echo creation of $@
@gcc -o $@ $(afb_daemon_srcs) --coverage $(afb_daemon_defs) $(cflags)
@@ -47,21 +108,41 @@ afb-client: $(afb_client_srcs)
@echo creation of $@
@gcc -o $@ $(afb_client_srcs) $(afb_client_defs) $(cflags)
+#======================================================================================
+# create test
+#======================================================================================
+
+test-apiset: $(tstdir)/apiset/test-apiset.c $(afb_lib_obj)
+ @echo creation of $@
+ @gcc -o $@ $(tstdir)/apiset/test-apiset.c $(afb_lib_obj) --coverage $(tst_defs) $(tst_flags)
+
+test-session: $(tstdir)/session/test-session.c $(afb_lib_obj)
+ @echo creation of $@
+ @gcc -o $@ $(tstdir)/session/test-session.c $(afb_lib_obj) --coverage $(tst_defs) $(tst_flags)
+
+test-wrap-json: $(tstdir)/session/test-session.c $(afb_lib_obj)
+ @echo creation of $@
+ @gcc -o $@ $(tstdir)/wrap-json/test-wrap-json.c $(afb_lib_obj) --coverage $(tst_defs) $(tst_flags)
+
+#======================================================================================
+# create bindings
+#======================================================================================
+
hi3.so: $(hi3_src)
@echo creation of $@
@gcc -o $@ $(hi3_src) $(binding_flags) $(cflags)
hello.so: $(hello3_src)
@echo creation of $@
- @gcc -o $@ $(hello3_src) '-DAPINAME="hello"' $(binding_flags) $(cflags)
+ @gcc -o $@ $(hello3_src) '-DAPINAME="hello"' '-DPREINIT_PROVIDE_CLASS="class1 class2"' $(binding_flags) $(cflags)
salut.so: $(hello3_src)
@echo creation of $@
- @gcc -o $@ $(hello3_src) '-DAPINAME="salut"' $(binding_flags) $(cflags)
+ @gcc -o $@ $(hello3_src) '-DAPINAME="salut"' '-DPREINIT_REQUIRE_CLASS="class2"' $(binding_flags) $(cflags)
salam.so: $(hello3_src)
@echo creation of $@
- @gcc -o $@ $(hello3_src) '-DAPINAME="salam"' $(binding_flags) $(cflags)
+ @gcc -o $@ $(hello3_src) '-DAPINAME="salam"' '-DINIT_REQUIRE_API="hello salut"' $(binding_flags) $(cflags)
shalom.so: $(hello3_src)
@echo creation of $@
@@ -75,7 +156,14 @@ hellov2.so: $(hello2_src)
@echo creation of $@
@gcc -o $@ $(hello2_src) '-DAPINAME="hello-v2"' $(binding_flags) $(cflags)
-bug.so: bug.c
- @echo creation of $@
- @gcc -o $@ bug.c $(binding_flags) $(cflags)
+#======================================================================================
+# create bugs
+#======================================================================================
+
+bugs:
+ @echo creation of directory bugs
+ @mkdir bugs
+bugs/bug%.so: bug.c bugs
+ @echo creation of $@
+ @gcc -o $@ bug.c $(binding_flags) $(cflags) -D$(patsubst bugs/bug%.so,BUG%,$@)
diff --git a/coverage/bin/bug.c b/coverage/bin/bug.c
index ddebdef7..62646cec 100644
--- a/coverage/bin/bug.c
+++ b/coverage/bin/bug.c
@@ -1,6 +1,276 @@
+#include <errno.h>
+#include <stdint.h>
+static int ok()
+{
+ return 0;
+}
+static int bug()
+{
+ errno = 0;
+ return ((int(*)())(intptr_t)0)();
+}
+static int err()
+{
+ errno = EAGAIN;
+ return -1;
+}
+/**************************************************************************/
+/**************************************************************************/
+/*** BINDINGS V2 ***/
+/**************************************************************************/
+/**************************************************************************/
+#if defined(BUG1) /* incomplete exports: afbBindingV2data miss */
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+const struct afb_binding_v2 afbBindingV2;
+
+#endif
+/**************************************************************************/
+#if defined(BUG2) /* incomplete exports: afbBindingV2 miss */
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+struct afb_binding_data_v2 afbBindingV2data;
+
+#endif
+/**************************************************************************/
+#if defined(BUG3) /* zero filled structure */
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+const struct afb_binding_v2 afbBindingV2;
+struct afb_binding_data_v2 afbBindingV2data;
+
+#endif
+/**************************************************************************/
+#if defined(BUG4) /* no verb definition */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug4",
+ .preinit = (void*)ok,
+ .init = (void*)ok
+};
+#endif
+/**************************************************************************/
+#if defined(BUG5) /* preinit buggy */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug5",
+ .verbs = verbs,
+ .preinit = (void*)bug,
+ .init = (void*)ok
+};
+#endif
+/**************************************************************************/
+#if defined(BUG6) /* buggy init */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug6",
+ .verbs = verbs,
+ .preinit = (void*)ok,
+ .init = (void*)bug
+};
+#endif
+/**************************************************************************/
+#if defined(BUG7) /* error in preinit */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug7",
+ .verbs = verbs,
+ .preinit = (void*)err,
+ .init = (void*)ok
+};
+#endif
+/**************************************************************************/
+#if defined(BUG8) /* error in init */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug8",
+ .verbs = verbs,
+ .preinit = (void*)ok,
+ .init = (void*)err
+};
+#endif
+/**************************************************************************/
+#if defined(BUG9) /* no api name */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .verbs = verbs,
+ .preinit = (void*)ok,
+ .init = (void*)ok
+};
+#endif
+/**************************************************************************/
+#if defined(BUG10) /* bad api name */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct afb_verb_v2 verbs[] = {
+ { NULL }
+};
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "bug 10",
+ .verbs = verbs,
+ .preinit = (void*)ok,
+ .init = (void*)err
+};
+#endif
+/**************************************************************************/
+/**************************************************************************/
+/*** BINDINGS V3 ***/
+/**************************************************************************/
+/**************************************************************************/
+#if defined(BUG11) /* make a SEGV */
+
#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
int afbBindingEntry(afb_api_t api)
{
return ((int(*)())(intptr_t)0)();
}
+#endif
+/**************************************************************************/
+#if defined(BUG12) /* no afbBindingV3 nor afbBindingV3entry */
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+struct afb_api_x3 *afbBindingV3root;
+
+#endif
+/**************************************************************************/
+#if defined(BUG13) /* no afbBindingV3root nor afbBindingV3entry */
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+const struct afb_binding_v3 afbBindingV3;
+int afbBindingV3entry(struct afb_api_x3 *rootapi) { return 0; }
+
+#endif
+/**************************************************************************/
+#if defined(BUG14) /* no api name */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3;
+
+#endif
+/**************************************************************************/
+#if defined(BUG15) /* bad api name */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug 15"
+};
+
+#endif
+/**************************************************************************/
+#if defined(BUG16) /* both entry and preinit */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+int afbBindingV3entry(struct afb_api_x3 *rootapi) { return 0; }
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug16",
+ .preinit = afbBindingV3entry
+};
+
+#endif
+/**************************************************************************/
+#if defined(BUG17) /* entry fails */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+int afbBindingV3entry(struct afb_api_x3 *rootapi) { errno = EAGAIN; return -1; }
+#endif
+/**************************************************************************/
+#if defined(BUG18) /* preinit fails */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug18",
+ .preinit = (void*)err
+};
+
+#endif
+/**************************************************************************/
+#if defined(BUG19) /* preinit SEGV */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug19",
+ .preinit = (void*)bug
+};
+
+#endif
+/**************************************************************************/
+#if defined(BUG20) /* init fails */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug20",
+ .init = (void*)err
+};
+
+#endif
+/**************************************************************************/
+#if defined(BUG21) /* init SEGV */
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "bug21",
+ .init = (void*)bug,
+ .provide_class = "a b c",
+ .require_class = "x y z",
+ .require_api = "bug4 bug5",
+};
+
+#endif
+/**************************************************************************/
diff --git a/coverage/bin/fake/monitoring b/coverage/bin/fake/monitoring
new file mode 120000
index 00000000..8cdac10f
--- /dev/null
+++ b/coverage/bin/fake/monitoring
@@ -0,0 +1 @@
+../../../test/monitoring \ No newline at end of file
diff --git a/coverage/bin/loc.txt b/coverage/bin/loc.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/coverage/bin/loc.txt
diff --git a/coverage/bin/locales/en/loc.txt b/coverage/bin/locales/en/loc.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/coverage/bin/locales/en/loc.txt
diff --git a/coverage/bin/locales/fr-FR/loc.txt b/coverage/bin/locales/fr-FR/loc.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/coverage/bin/locales/fr-FR/loc.txt
diff --git a/coverage/bin/locales/fr/loc.txt b/coverage/bin/locales/fr/loc.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/coverage/bin/locales/fr/loc.txt
diff --git a/coverage/bin/locales/jp/loc.txt b/coverage/bin/locales/jp/loc.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/coverage/bin/locales/jp/loc.txt
diff --git a/coverage/ldpath/weak/bug.so b/coverage/ldpath/weak/bug.so
deleted file mode 120000
index 01e7c27a..00000000
--- a/coverage/ldpath/weak/bug.so
+++ /dev/null
@@ -1 +0,0 @@
-sub/bug.so \ No newline at end of file
diff --git a/coverage/ldpath/weak/bugs b/coverage/ldpath/weak/bugs
new file mode 120000
index 00000000..6ed8e22c
--- /dev/null
+++ b/coverage/ldpath/weak/bugs
@@ -0,0 +1 @@
+../../bin/bugs \ No newline at end of file
diff --git a/coverage/scripts/00-trace.sh b/coverage/scripts/00-trace.sh
index 34a19bb0..27edc5b1 100755
--- a/coverage/scripts/00-trace.sh
+++ b/coverage/scripts/00-trace.sh
@@ -1,4 +1,7 @@
#!/bin/sh
-$R/bin/afb-client -k $WSURL monitor trace '{"add":{"api":"*","request":"*","event":"*","session":"*","global":"*"}}' &
-
+$R/bin/afb-client -k $WSURL <<EOC &
+monitor trace {"add":{"tag":"fun","api":"*","request":"*","event":"*","session":"*","global":"*"}}
+monitor trace {"add":{"tag":"T","api":"*","request":"*","event":"*","session":"*","global":"*"}}
+monitor trace {"drop":{"tag":"fun"}}
+EOC
diff --git a/coverage/scripts/01-http.sh b/coverage/scripts/01-http.sh
index 191318c0..9ffd640f 100755
--- a/coverage/scripts/01-http.sh
+++ b/coverage/scripts/01-http.sh
@@ -1,17 +1,29 @@
#!/bin/sh
-curl $URL/index.html
-curl $URL/marrus-orthocanna.jpg
-curl $URL/test.js
-curl $URL/icons/marrus-orthocanna.jpg
+curl -s -o /dev/null $URL/index.html
+curl -s -o /dev/null $URL/marrus-orthocanna.jpg
+curl -s -o /dev/null $URL/test.js
+curl -s -o /dev/null $URL/icons/marrus-orthocanna.jpg
-curl $URL/fake-file.html
+curl -s -o /dev/null $URL/fake-file.html
-curl "$URL/api/salut/ping?arg1=null&arg1=%22a+string%22"
-curl "$URL/api/hello/ping" \
+curl -s "$URL/api/salut/ping?arg1=null&arg1=%22a+string%22"
+curl -s "$URL/api/hello/ping" \
-F image=@$R/www/marrus-orthocanna.jpg \
-F name=test
-curl -X POST "$URL/api/hello/ping" \
+curl -s -X POST "$URL/api/hello/ping" \
--header 'content-type: application/json' \
--data-binary '[null,3,{"hello":false,"salut":4.5},true]'
+
+curl -s "$URL/api/hello/get?name=something&something=nothing"
+
+curl -s -F name=file -F file=@$R/www/marrus-orthocanna.jpg "$URL/api/hello/get"
+
+curl -s -X HEAD -o /dev/null $URL/index.html
+#curl -s -X CONNECT -o /dev/null $URL/index.html
+curl -s -X DELETE -o /dev/null $URL/index.html
+curl -s -X OPTIONS -o /dev/null $URL/index.html
+curl -s -X PATCH -o /dev/null $URL/index.html
+curl -s -X PUT -o /dev/null $URL/index.html
+curl -s -X TRACE -o /dev/null $URL/index.html
diff --git a/coverage/scripts/02-hello.sh b/coverage/scripts/02-hello.sh
index fe9040c2..9e3a9b08 100755
--- a/coverage/scripts/02-hello.sh
+++ b/coverage/scripts/02-hello.sh
@@ -48,5 +48,49 @@ hello setctx "some-text-2"
hello getctx
hello info
hello verbose {"level":2,"message":"hello"}
+hello eventloop
+hello dbus false
+hello dbus true
+hello reply-count 0
+hello reply-count 2
+hello get null
+hello get {"name":"toto"}
+hello get {"name":"toto","toto":5}
+hello ref null
+hello rootdir null
+hello eventadd {"tag":"EVENT","name":"EVENT"}
+hello locale {"file":"loc.txt","lang":"ru,de,jp-JP,fr"}
+hello locale "loc.txt"
+hello locale "i don't exist"
+hello api {"action":"create","api":"_extra_"}
+hello api {"action":"addverb","api":"_extra_","verb":"ping"}
+hello api {"action":"seal","api":"_extra_"}
+hello api {"action":"addverb","api":"_extra_","verb":"ping"}
+hello api {"action":"destroy","api":"_extra_"}
+_extra_ ping2 {"a":true}
+_extra_ ping3 {"b":false}
+_extra_ ping {"c":[1,2,3]}
+hello api {"action":"create","api":"extra"}
+extra api {"action":"addverb","verb":"blablabla"}
+extra api {"action":"addverb","verb":"ping"}
+extra api {"action":"addverb","verb":"ping2"}
+extra api {"action":"addverb","verb":"ping3"}
+extra api {"action":"addverb","verb":"q*"}
+extra api {"action":"delverb","verb":"blablabla"}
+extra api {"action":"addhandler","pattern":"*","closure":"*"}
+extra api {"action":"addhandler","pattern":"hello/*","closure":"hello/*"}
+extra call {"api":"hello","verb":"eventsub","args":{"tag":"EVENT"}}
+hello eventpush {"tag":"EVENT","data":[1,2,"hello"]}
+hello api {"action":"delhandler","api":"extra","pattern":"hello/*"}
+hello eventpush {"tag":"EVENT","data":[1,2,"hello"]}
+extra ping2 {"a":true}
+extra ping3 {"b":false}
+extra ping {"c":[1,2,3]}
+extra query {"c":[1,2,3]}
+extra blablabla {"c":[1,2,3]}
+extra api {"action":"addverb","verb":"ping"}
+extra ping {"c":[1,2,3]}
+hello api {"action":"destroy","api":"extra"}
+extra ping {"c":[1,2,3]}
EOC
diff --git a/coverage/scripts/03-x-hello.sh b/coverage/scripts/03-auto-ws.sh
index 9d3726e4..9d3726e4 100755
--- a/coverage/scripts/03-x-hello.sh
+++ b/coverage/scripts/03-auto-ws.sh
diff --git a/coverage/scripts/06-auto-so.sh b/coverage/scripts/06-auto-so.sh
new file mode 100755
index 00000000..36214ee0
--- /dev/null
+++ b/coverage/scripts/06-auto-so.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+$R/bin/afb-client -s -e $WSURL <<EOC
+salam ping true
+x-HELLO PING false
+salam pIngNull true
+salam PingBug true
+salam PiNgJsOn {"well":"formed","json":[1,2,3,4.5,true,false,null,"oups"]}
+salam subcall {"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}
+salam subcall {"api":"salam","verb":"subcall","args":{"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}}
+salam subcallsync {"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}
+salam subcallsync {"api":"salam","verb":"subcall","args":{"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}}
+salam subcall {"api":"salam","verb":"subcallsync","args":{"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}}
+salam subcallsync {"api":"salam","verb":"subcallsync","args":{"api":"salam","verb":"pingjson","args":[{"key1":"value1"}]}}
+salam eventadd {"tag":"ev1","name":"event-A"}
+salam eventadd {"tag":"ev2","name":"event-B"}
+salam eventpush {"tag":"ev1","data":[1,2,"salam"]}
+salam eventpush {"tag":"ev2","data":{"item":0}}
+salam eventsub {"tag":"ev2"}
+salam eventpush {"tag":"ev1","data":[1,2,"salam"]}
+salam eventpush {"tag":"ev2","data":{"item":0}}
+salam eventsub {"tag":"ev1"}
+salam subcall {"api":"salam","verb":"eventpush","args":{"tag":"ev1","data":[1,2,"salam"]}}
+salam subcall {"api":"salam","verb":"eventpush","args":{"tag":"ev2","data":{"item":0}}}
+salam subcallsync {"api":"salam","verb":"eventpush","args":{"tag":"ev1","data":[1,2,"salam"]}}
+salam subcallsync {"api":"salam","verb":"eventpush","args":{"tag":"ev2","data":{"item":0}}}
+salam eventunsub {"tag":"ev2"}
+salam eventpush {"tag":"ev1","data":[1,2,"salam"]}
+salam eventpush {"tag":"ev2","data":{"item":0}}
+salam eventdel {"tag":"ev1"}
+salam eventpush {"tag":"ev1","data":[1,2,"salam"]}
+salam eventpush {"tag":"ev2","data":{"item":0}}
+salam eventdel {"tag":"ev2"}
+EOC
+
diff --git a/coverage/scripts/run-test.sh b/coverage/scripts/run-test.sh
index 34c2d303..bac4da5e 100755
--- a/coverage/scripts/run-test.sh
+++ b/coverage/scripts/run-test.sh
@@ -3,18 +3,72 @@
export R=$(realpath $(dirname $0)/..)
export PATH="$R/bin:$R/scripts:$PATH"
-$R/bin/afb-daemon-cov --help > /dev/null
+cd $R/bin
-$R/bin/afb-daemon-cov --version > /dev/null
+lcov -c -i -d $R/bin -o $R/lcov-out.info
-$R/bin/afb-daemon-cov --fake-option > /dev/null
+mk() {
+ echo
+ echo "*******************************************************************"
+ echo "** $*"
+ echo "*******************************************************************"
+ lcov -c -i -d $R/bin -o $R/fake.info
+ "$@"
+ lcov -c -d $R/bin -o $R/tmp.info
+ mv $R/lcov-out.info $R/previous.info
+ lcov -a $R/tmp.info -a $R/previous.info -o $R/lcov-out.info
+ rm $R/previous.info $R/fake.info $R/tmp.info
+}
+mkdir /tmp/ldpaths
+export AFB_LDPATHS=/tmp/ldpaths
+export AFB_TRACEAPI=no
+
+##########################################################
+# test to check options
+##########################################################
+mk $R/bin/afb-daemon-cov --help
+
+mk $R/bin/afb-daemon-cov --version
+
+mk $R/bin/afb-daemon-cov --no-httpd --fake-option
+
+mk $R/bin/afb-daemon-cov --daemon --session-max
+
+mk $R/bin/afb-daemon-cov --ws-client fake --session-max toto
+
+mk $R/bin/afb-daemon-cov --foreground --port -55
+
+mk $R/bin/afb-daemon-cov --foreground --port 9999999
+
+mk $R/bin/afb-daemon-cov --no-ldpath --traceapi fake
+
+mk $R/bin/afb-daemon-cov --traceditf all --tracesvc all --log error,alarm
+
+LISTEN_FDNAMES=toto,demat LISTEN_FDS=5 mk $R/bin/afb-daemon-cov --no-ldpath --binding $R/bin/demat.so --ws-server sd:demat --call "demat/exit:0"
+
+mk $R/bin/afb-daemon-cov --weak-ldpaths $R/ldpath/weak --binding $R/bin/demat.so --ws-server sd:demat --call "demat/exit:0"
+
+##########################################################
+# test of the bench
+##########################################################
+mk $R/bin/test-apiset
+
+mk $R/bin/test-session
+
+mk $R/bin/test-wrap-json
+
+##########################################################
+# true life test
+##########################################################
+mk \
valgrind \
--log-file=$R/valgrind.out \
--trace-children=no \
--track-fds=yes \
--leak-check=full \
- --show-leak-kinds=all \
+ --show-leak-kinds=all \
+ --num-callers=50 \
$R/bin/afb-daemon-cov \
--verbose \
--verbose \
@@ -29,6 +83,7 @@ $R/bin/afb-daemon-cov \
--log error,warning,notice,info,debug,critical,alert-error,warning,notice,info,debug,critical,alert+error,warning,notice,info,debug,critical,alert \
--foreground \
--name binder-cov \
+ --port 8888 \
--roothttp $R/www \
--rootbase /opx \
--rootapi /api \
@@ -41,7 +96,6 @@ $R/bin/afb-daemon-cov \
--rootdir . \
--ldpaths $R/ldpath/strong \
--binding $R/bin/demat.so \
- --weak-ldpaths $R/ldpath/weak \
--auto-api $R/apis/auto \
--token HELLO \
--random-token \
@@ -50,6 +104,7 @@ $R/bin/afb-daemon-cov \
--traceapi all \
--traceses all \
--traceevt all \
+ --monitoring \
--call demat/ping:true \
--ws-server unix:$R/apis/ws/hello \
--ws-server unix:$R/apis/ws/salut \
diff --git a/src/tests/wrap-json/CMakeLists.txt b/src/tests/wrap-json/CMakeLists.txt
new file mode 100644
index 00000000..7e69f742
--- /dev/null
+++ b/src/tests/wrap-json/CMakeLists.txt
@@ -0,0 +1,23 @@
+###########################################################################
+# Copyright (C) 2017, 2018 "IoT.bzh"
+#
+# author: José Bollo <jose.bollo@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+add_executable(test-wrap-json test-wrap-json.c)
+target_include_directories(test-wrap-json PRIVATE ../..)
+target_link_libraries(test-wrap-json afb-lib ${link_libraries})
+add_test(NAME wrap-json COMMAND test-wrap-json)
+
diff --git a/src/tests/wrap-json/test-wrap-json.c b/src/tests/wrap-json/test-wrap-json.c
new file mode 100644
index 00000000..83ed3156
--- /dev/null
+++ b/src/tests/wrap-json/test-wrap-json.c
@@ -0,0 +1,331 @@
+/*
+ Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+
+ author: José Bollo <jose.bollo@iot.bzh>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "wrap-json.h"
+
+
+void tclone(struct json_object *object)
+{
+ struct json_object *o;
+
+ o = wrap_json_clone(object);
+ if (!wrap_json_equal(object, o))
+ printf("ERROR in clone or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
+ json_object_put(o);
+
+ o = wrap_json_clone_deep(object);
+ if (!wrap_json_equal(object, o))
+ printf("ERROR in clone_deep or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
+ json_object_put(o);
+}
+
+void p(const char *desc, ...)
+{
+ int rc;
+ va_list args;
+ struct json_object *result;
+
+ va_start(args, desc);
+ rc = wrap_json_vpack(&result, desc, args);
+ va_end(args);
+ if (!rc)
+ printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
+ else
+ printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
+ tclone(result);
+ json_object_put(result);
+}
+
+const char *xs[10];
+int *xi[10];
+int64_t *xI[10];
+double *xf[10];
+struct json_object *xo[10];
+size_t xz[10];
+uint8_t *xy[10];
+
+void u(const char *value, const char *desc, ...)
+{
+ unsigned m, k;
+ int rc;
+ va_list args;
+ struct json_object *object, *o;
+
+ memset(xs, 0, sizeof xs);
+ memset(xi, 0, sizeof xi);
+ memset(xI, 0, sizeof xI);
+ memset(xf, 0, sizeof xf);
+ memset(xo, 0, sizeof xo);
+ memset(xy, 0, sizeof xy);
+ memset(xz, 0, sizeof xz);
+ object = json_tokener_parse(value);
+ va_start(args, desc);
+ rc = wrap_json_vunpack(object, desc, args);
+ va_end(args);
+ if (rc)
+ printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
+ else {
+ value = NULL;
+ printf(" SUCCESS");
+ va_start(args, desc);
+ k = m = 0;
+ while(*desc) {
+ switch(*desc) {
+ case '{': m = (m << 1) | 1; k = 1; break;
+ case '}': m = m >> 1; k = m&1; break;
+ case '[': m = m << 1; k = 0; break;
+ case ']': m = m >> 1; k = m&1; break;
+ case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
+ case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
+ case 'n': printf(" n"); k = m&1; break;
+ case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
+ case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
+ case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
+ case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
+ case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
+ case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
+ case 'O': o = *va_arg(args, struct json_object**); printf(" O:%s", json_object_to_json_string(o)); json_object_put(o); k = m&1; break;
+ case 'y':
+ case 'Y': {
+ uint8_t *p = *va_arg(args, uint8_t**);
+ size_t s = *va_arg(args, size_t*);
+ printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
+ k ^= m&1;
+ break;
+ }
+ default: break;
+ }
+ desc++;
+ }
+ va_end(args);
+ printf("\n\n");
+ }
+ tclone(object);
+ json_object_put(object);
+}
+
+void c(const char *sx, const char *sy, int e, int c)
+{
+ int re, rc;
+ struct json_object *jx, *jy;
+
+ jx = json_tokener_parse(sx);
+ jy = json_tokener_parse(sy);
+
+ re = wrap_json_cmp(jx, jy);
+ rc = wrap_json_contains(jx, jy);
+
+ printf("compare(%s)(%s)\n", sx, sy);
+ printf(" -> %d / %d\n", re, rc);
+
+ if (!re != !!e)
+ printf(" ERROR should be %s\n", e ? "equal" : "different");
+ if (!rc != !c)
+ printf(" ERROR should %scontain\n", c ? "" : "not ");
+
+ printf("\n");
+}
+
+#define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
+#define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
+
+int main()
+{
+ char buffer[4] = {'t', 'e', 's', 't'};
+
+ P("n");
+ P("b", 1);
+ P("b", 0);
+ P("i", 1);
+ P("I", (uint64_t)0x123456789abcdef);
+ P("f", 3.14);
+ P("s", "test");
+ P("s?", "test");
+ P("s?", NULL);
+ P("s#", "test asdf", 4);
+ P("s%", "test asdf", (size_t)4);
+ P("s#", buffer, 4);
+ P("s%", buffer, (size_t)4);
+ P("s++", "te", "st", "ing");
+ P("s#+#+", "test", 1, "test", 2, "test");
+ P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
+ P("{}", 1.0);
+ P("[]", 1.0);
+ P("o", json_object_new_int(1));
+ P("o?", json_object_new_int(1));
+ P("o?", NULL);
+ P("O", json_object_new_int(1));
+ P("O?", json_object_new_int(1));
+ P("O?", NULL);
+ P("{s:[]}", "foo");
+ P("{s+#+: []}", "foo", "barbar", 3, "baz");
+ P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
+ P("{s:**}", "a", NULL);
+ P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
+ P("[i,i,i]", 0, 1, 2);
+ P("[s,o,O]", NULL, NULL, NULL);
+ P("[**]", NULL);
+ P("[s*,o*,O*]", NULL, NULL, NULL);
+ P(" s ", "test");
+ P("[ ]");
+ P("[ i , i, i ] ", 1, 2, 3);
+ P("{\n\n1");
+ P("[}");
+ P("{]");
+ P("[");
+ P("{");
+ P("[i]a", 42);
+ P("ia", 42);
+ P("s", NULL);
+ P("+", NULL);
+ P(NULL);
+ P("{s:i}", NULL, 1);
+ P("{ {}: s }", "foo");
+ P("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
+ P("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");
+ P("y", "???????hello>>>>>>>", (size_t)19);
+ P("Y", "???????hello>>>>>>>", (size_t)19);
+ P("{sy?}", "foo", "hi", (size_t)2);
+ P("{sy?}", "foo", NULL, 0);
+ P("{sy*}", "foo", "hi", (size_t)2);
+ P("{sy*}", "foo", NULL, 0);
+
+ U("true", "b", &xi[0]);
+ U("false", "b", &xi[0]);
+ U("null", "n");
+ U("42", "i", &xi[0]);
+ U("123456789", "I", &xI[0]);
+ U("3.14", "f", &xf[0]);
+ U("12345", "F", &xf[0]);
+ U("3.14", "F", &xf[0]);
+ U("\"foo\"", "s", &xs[0]);
+ U("\"foo\"", "s%", &xs[0], &xz[0]);
+ U("{}", "{}");
+ U("[]", "[]");
+ U("{}", "o", &xo[0]);
+ U("{}", "O", &xo[0]);
+ U("{\"foo\":42}", "{si}", "foo", &xi[0]);
+ U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
+ U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
+ U("42", "z");
+ U("null", "[i]");
+ U("[]", "[}");
+ U("{}", "{]");
+ U("[]", "[");
+ U("{}", "{");
+ U("[42]", "[i]a", &xi[0]);
+ U("42", "ia", &xi[0]);
+ U("[]", NULL);
+ U("\"foo\"", "s", NULL);
+ U("42", "s", NULL);
+ U("42", "n");
+ U("42", "b", NULL);
+ U("42", "f", NULL);
+ U("42", "[i]", NULL);
+ U("42", "{si}", "foo", NULL);
+ U("\"foo\"", "n");
+ U("\"foo\"", "b", NULL);
+ U("\"foo\"", "i", NULL);
+ U("\"foo\"", "I", NULL);
+ U("\"foo\"", "f", NULL);
+ U("\"foo\"", "F", NULL);
+ U("true", "s", NULL);
+ U("true", "n");
+ U("true", "i", NULL);
+ U("true", "I", NULL);
+ U("true", "f", NULL);
+ U("true", "F", NULL);
+ U("[42]", "[ii]", &xi[0], &xi[1]);
+ U("{\"foo\":42}", "{si}", NULL, &xi[0]);
+ U("{\"foo\":42}", "{si}", "baz", &xi[0]);
+ U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
+ U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
+ U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
+ U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
+ U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
+ U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
+ U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
+ U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
+ U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
+ U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
+ U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
+ U("{}", "{s?i}", "foo", &xi[0]);
+ U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
+ U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
+ U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
+ U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
+ U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
+ U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
+ U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
+ U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
+ U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
+
+ U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
+ U("\"\"", "y", &xy[0], &xz[0]);
+ U("null", "y", &xy[0], &xz[0]);
+ U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
+ U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
+ U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
+
+ c("null", "null", 1, 1);
+ c("true", "true", 1, 1);
+ c("false", "false", 1, 1);
+ c("1", "1", 1, 1);
+ c("1.0", "1.0", 1, 1);
+ c("\"\"", "\"\"", 1, 1);
+ c("\"hi\"", "\"hi\"", 1, 1);
+ c("{}", "{}", 1, 1);
+ c("{\"a\":true,\"b\":false}", "{\"b\":false,\"a\":true}", 1, 1);
+ c("[]", "[]", 1, 1);
+ c("[1,true,null]", "[1,true,null]", 1, 1);
+
+ c("null", "true", 0, 0);
+ c("null", "false", 0, 0);
+ c("0", "1", 0, 0);
+ c("1", "0", 0, 0);
+ c("0", "true", 0, 0);
+ c("0", "false", 0, 0);
+ c("0", "null", 0, 0);
+
+ c("\"hi\"", "\"hello\"", 0, 0);
+ c("\"hello\"", "\"hi\"", 0, 0);
+
+ c("{}", "null", 0, 0);
+ c("{}", "true", 0, 0);
+ c("{}", "1", 0, 0);
+ c("{}", "1.0", 0, 0);
+ c("{}", "[]", 0, 0);
+ c("{}", "\"x\"", 0, 0);
+
+ c("[1,true,null]", "[1,true]", 0, 1);
+ c("{\"a\":true,\"b\":false}", "{\"a\":true}", 0, 1);
+ c("{\"a\":true,\"b\":false}", "{\"a\":true,\"c\":false}", 0, 0);
+ c("{\"a\":true,\"c\":false}", "{\"a\":true,\"b\":false}", 0, 0);
+ return 0;
+}
+