coverage: Improve coverage test 13/15813/1
authorJosé Bollo <jose.bollo@iot.bzh>
Tue, 24 Jul 2018 10:53:15 +0000 (12:53 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Fri, 27 Jul 2018 15:44:07 +0000 (17:44 +0200)
The test now raise an overall coverage rate:

  lines......: 75.4% (8356 of 11080 lines)
  functions..: 80.4% (1094 of 1360 functions)

Also Improve the documentation and improve parts of code.

Change-Id: Ic2b8bc2f85d4181aa0b358a953f95cb105a0eed9
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
19 files changed:
.gitignore
bindings/samples/hello3.c
coverage/.gitignore
coverage/bin/Makefile
coverage/ldpath/strong/hellov2.so [new symlink]
coverage/scripts/00-trace.sh
coverage/scripts/01-http.sh
coverage/scripts/02-hello.sh
coverage/scripts/07-inet.sh [changed mode: 0644->0755]
coverage/scripts/run-test.sh
docs/reference-v3/types-and-globals.md
include/afb/afb-auth.h
src/afb-apiset.c
src/afb-apiset.h
src/main-afb-daemon.c
src/tests/CMakeLists.txt
src/tests/apiset/test-apiset.c
src/tests/wrap-json/test-wrap-json.c
src/wrap-json.c

index abc051f..d718309 100644 (file)
@@ -9,7 +9,6 @@ CMakeFiles/
 CMakeCache.txt
 nbproject/private/*
 cmake_install.cmake
-*.so
 .vscode
 stress-out*
 node_modules/
index 477e47b..7e54e3a 100644 (file)
@@ -467,6 +467,11 @@ static void setloa (afb_req_t request)
        afb_req_reply_f(request, NULL, NULL, "LOA set to %d", loa);
 }
 
+static void ok (afb_req_t request)
+{
+       afb_req_reply_f(request, NULL, NULL, NULL);
+}
+
 static void setctx (afb_req_t request)
 {
        struct json_object *x = afb_req_json(request);
@@ -530,6 +535,23 @@ static void ref(afb_req_t request)
        afb_req_unref(request);
 }
 
+static void mute(afb_req_t request)
+{
+}
+
+void queue_cb(int signum, void *arg)
+{
+       afb_req_t request = arg;
+       afb_req_reply(request, NULL, NULL, NULL);
+       afb_req_unref(request);
+}
+
+static void queue(afb_req_t request)
+{
+       afb_req_addref(request);
+       afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
+}
+
 static void rootdir (afb_req_t request)
 {
        ssize_t s;
@@ -586,6 +608,88 @@ static void locale (afb_req_t request)
 
 static void api (afb_req_t request);
 
+/**
+ * Definition of an authorization entry
+ */
+static struct afb_auth auths[] = {
+       {       /* 0 */
+               .type = afb_auth_Or,
+               .first = &auths[1],
+               .next = &auths[9],
+       },
+       {       /* 1 */
+               .type = afb_auth_And,
+               .first = &auths[2],
+               .next = &auths[3],
+       },
+       {       /* 2 */
+               .type = afb_auth_Yes
+       },
+       {       /* 3 */
+               .type = afb_auth_And,
+               .first = &auths[4],
+               .next = &auths[5],
+       },
+       {       /* 4 */
+               .type = afb_auth_LOA,
+               .loa = 0
+       },
+       {       /* 5 */
+               .type = afb_auth_Or,
+               .first = &auths[6],
+               .next = &auths[7],
+       },
+       {       /* 6 */
+               .type = afb_auth_No
+       },
+       {       /* 7 */
+               .type = afb_auth_Not,
+               .first = &auths[8]
+       },
+       {       /* 8 */
+               .type = afb_auth_Yes
+       },
+       {       /* 9 */
+               .type = afb_auth_And,
+               .first = &auths[10],
+               .next = &auths[13],
+       },
+       {       /* 10 */
+               .type = afb_auth_Or,
+               .first = &auths[12],
+               .next = &auths[11],
+       },
+       {       /* 11 */
+               .type = afb_auth_Not,
+               .first = &auths[13]
+       },
+       {       /* 12 */
+               .type = afb_auth_Token
+       },
+       {       /* 13 */
+               .type = afb_auth_And,
+               .first = &auths[14],
+               .next = &auths[17],
+       },
+       {       /* 14 */
+               .type = afb_auth_Or,
+               .first = &auths[16],
+               .next = &auths[15],
+       },
+       {       /* 15 */
+               .type = afb_auth_Not,
+               .first = &auths[16]
+       },
+       {       /* 16 */
+               .type = afb_auth_Permission,
+               .text = "permission"
+       },
+       {       /* 17 */
+               .type = afb_auth_Yes
+       }
+};
+
+
 // 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[]= {
@@ -611,11 +715,15 @@ static const struct afb_verb_v3 verbs[]= {
   { .verb="appid",       .callback=appid },
   { .verb="uid",         .callback=uid },
   { .verb="exit",        .callback=exitnow },
-  { .verb="close",       .callback=closess },
-  { .verb="set-loa",     .callback=setloa },
+  { .verb="close",       .callback=closess, .session=AFB_SESSION_CLOSE },
+  { .verb="set-loa",     .callback=setloa, .auth = &auths[0] },
+  { .verb="has-loa-1",   .callback=ok, .session=AFB_SESSION_LOA_1 },
+  { .verb="has-loa-2",   .callback=ok, .session=AFB_SESSION_LOA_2 },
+  { .verb="has-loa-3",   .callback=ok, .session=AFB_SESSION_LOA_3 },
   { .verb="setctx",      .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
   { .verb="setctxif",    .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
   { .verb="getctx",      .callback=getctx },
+  { .verb="reftok",      .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
   { .verb="info",        .callback=info },
   { .verb="eventloop",   .callback=eventloop },
   { .verb="dbus",        .callback=dbus },
@@ -625,6 +733,8 @@ static const struct afb_verb_v3 verbs[]= {
   { .verb="rootdir",     .callback=rootdir},
   { .verb="locale",      .callback=locale},
   { .verb="api",         .callback=api},
+  { .verb="mute",        .callback=mute},
+  { .verb="queue",       .callback=queue},
   { .verb=NULL}
 };
 
index 69f6ea4..531f1a9 100644 (file)
@@ -8,7 +8,7 @@ bin/afb-daemon-cov
 bin/test-apiset
 bin/test-session
 bin/test-wrap-json
-*.o
-*.so
-*.gcda
-*.gcno
+bin/*.o
+bin/*.so
+bin/*.gcda
+bin/*.gcno
index f9d561e..ef8b68e 100644 (file)
@@ -62,11 +62,10 @@ 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_lib_src = $(shell ls $(srcdir)/*.c | egrep -v '/afs-|/main-|/fdev-epoll.c|/afb-ws-client.c' )
 afb_lib_obj = $(patsubst $(srcdir)/%.c,%.o,$(afb_lib_src))
 afb_lib = afb-lib.a
 afb_lib_defs = $(defs)
@@ -74,7 +73,7 @@ afb_lib_defs = $(defs)
 afb_daemon_srcs = $(srcdir)/main-afb-daemon.c $(afb_lib_obj)
 afb_daemon_defs = $(afb_lib_defs)
 
-afb_client_srcs = $(srcdir)/main-afb-client-demo.c $(afb_lib_src)
+afb_client_srcs = $(srcdir)/main-afb-client-demo.c $(srcdir)/afb-ws-client.c $(afb_lib_src)
 afb_client_defs = $(defs)
 
 tst_defs = $(defs)
diff --git a/coverage/ldpath/strong/hellov2.so b/coverage/ldpath/strong/hellov2.so
new file mode 120000 (symlink)
index 0000000..f60e708
--- /dev/null
@@ -0,0 +1 @@
+../../bin/hellov2.so
\ No newline at end of file
index 27edc5b..247be61 100755 (executable)
@@ -2,6 +2,7 @@
 
 $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 {"add":{"tag":"T","api":"!(monitor)","request":"*","event":"*","session":"*","global":"*"}}
+monitor trace {"add":{"tag":"T","api":"monitor","request":"none"}}
 monitor trace {"drop":{"tag":"fun"}}
 EOC
index 9ffd640..cb69595 100755 (executable)
@@ -5,6 +5,7 @@ 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 -s -o /dev/null $URL/opa/item/extra/index.html
 
 curl -s -o /dev/null $URL/fake-file.html
 
index 9e3a9b0..de6e2de 100755 (executable)
@@ -38,9 +38,22 @@ hello eventdel {"tag":"ev2"}
 hello hasperm {"perm":"some-permissison"}
 hello appid true
 hello uid true
+hello reftok true
+hello has_loa-1
+hello has_loa-2
+hello has_loa-3
 hello set-loa 1
+hello has_loa-1
+hello has_loa-2
+hello has_loa-3
 hello set-loa 3
+hello has_loa-1
+hello has_loa-2
+hello has_loa-3
 hello close true
+hello has_loa-1
+hello has_loa-2
+hello has_loa-3
 hello setctx "some-text-0"
 hello setctxif "some-text-1"
 hello getctx 
@@ -89,6 +102,7 @@ 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 call {"api":"hello","verb":"eventunsub","args":{"tag":"EVENT"}}
 extra ping {"c":[1,2,3]}
 hello api {"action":"destroy","api":"extra"}
 extra ping {"c":[1,2,3]}
old mode 100644 (file)
new mode 100755 (executable)
index caaec79..5d1b9a9 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 export R=$(realpath $(dirname $0)/..)
 export PATH="$R/bin:$R/scripts:$PATH"
@@ -45,10 +45,26 @@ 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 --call noapi/noverb:false
+
+mk $R/bin/afb-daemon-cov --call not-a-call
+
+LISTEN_FDNAMES=toto,demat LISTEN_FDS=5
+typeset -x LISTEN_FDNAMES LISTEN_FDS
+mk $R/bin/afb-daemon-cov --no-ldpath --binding $R/bin/demat.so --ws-server sd:demat --call "demat/exit:0"
+typeset +x LISTEN_FDNAMES LISTEN_FDS
 
 mk $R/bin/afb-daemon-cov --weak-ldpaths $R/ldpath/weak --binding $R/bin/demat.so --ws-server sd:demat --call "demat/exit:0"
 
+AFB_DEBUG_BREAK=zero,one,two,main-start  AFB_DEBUG_WAIT="here I am"
+typeset -x AFB_DEBUG_BREAK AFB_DEBUG_WAIT
+mk $R/bin/afb-daemon-cov --rootdir $R/i-will-never-exist
+typeset +x AFB_DEBUG_BREAK AFB_DEBUG_WAIT
+
+mk $R/bin/afb-daemon-cov --workdir=/etc/you/should/not/be/able/to/create/me
+
+mk $R/bin/afb-daemon-cov --exec $R/it-doesn-t-exist
+
 ##########################################################
 # test of the bench
 ##########################################################
@@ -85,7 +101,7 @@ $R/bin/afb-daemon-cov \
        --name binder-cov \
        --port 8888 \
        --roothttp $R/www \
-       --rootbase /opx \
+       --rootbase /opa \
        --rootapi /api \
        --alias /icons:$R/www \
        --apitimeout 90 \
@@ -104,13 +120,48 @@ $R/bin/afb-daemon-cov \
        --traceapi all \
        --traceses all \
        --traceevt all \
+       --traceglob none \
        --monitoring \
        --call demat/ping:true \
+       --call hello/ping:false \
        --ws-server unix:$R/apis/ws/hello \
        --ws-server unix:$R/apis/ws/salut \
-       --ws-server localhost:9595/salut \
-       --ws-client localhost:9595/salut2 \
        --exec $R/scripts/run-parts.sh @p @t
 
+##########################################################
+# true life test
+##########################################################
+mk \
+valgrind \
+       --log-file=$R/valgrind.out \
+       --trace-children=no \
+       --track-fds=yes \
+       --leak-check=full \
+       --show-leak-kinds=all \
+       --num-callers=50 \
+$R/bin/afb-daemon-cov \
+       --quiet \
+       --quiet \
+       --foreground \
+       --roothttp $R/www \
+       --alias /icons:$R/www \
+       --workdir . \
+       --uploaddir . \
+       --rootdir . \
+       --ldpaths $R/ldpath/strong \
+       --binding $R/bin/demat.so \
+       --auto-api $R/apis/auto \
+       --random-token \
+       --ws-server unix:$R/apis/ws/hello \
+       --ws-server unix:$R/apis/ws/salut \
+       --ws-server localhost:9595/salut \
+       --exec \
+            afb-daemon \
+               --auto-api $R/apis/auto \
+               --auto-api $R/apis/ws \
+               --ws-client localhost:@p/salut2 \
+               $R/scripts/run-parts.sh @@p @@t
+
 exit 0
 
+
index 50abeec..5c10ba9 100644 (file)
@@ -198,7 +198,7 @@ enum afb_auth_type
        /** authorized if token valid, no data */
        afb_auth_Token,
 
-       /** authorized if LOA greater than data 'loa' */
+       /** authorized if LOA greater than or equal to data 'loa' */
        afb_auth_LOA,
 
        /** authorized if permission 'text' is granted */
index 31cbf6f..b9162cd 100644 (file)
@@ -34,7 +34,7 @@ enum afb_auth_type
        /** authorized if token valid, no data */
        afb_auth_Token,
 
-       /** authorized if LOA greater than data 'loa' */
+       /** authorized if LOA greater than or equal to data 'loa' */
        afb_auth_LOA,
 
        /** authorized if permission 'text' is granted */
@@ -60,18 +60,18 @@ struct afb_auth
 {
        /** type of entry @see afb_auth_type */
        enum afb_auth_type type;
-       
+
        union {
                /** text when @ref type == @ref afb_auth_Permission */
                const char *text;
-               
+
                /** level of assurancy when @ref type ==  @ref afb_auth_LOA */
                unsigned loa;
-               
+
                /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */
                const struct afb_auth *first;
        };
-       
+
        /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */
        const struct afb_auth *next;
 };
index f837fae..6229b37 100644 (file)
@@ -427,17 +427,23 @@ struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set)
  * Set the subset of the set
  * @param set the api set
  * @param subset the subset to set
+ *
+ * @return 0 in case of success or -1 if it had created a loop
  */
-void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
+int afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
 {
        struct afb_apiset *tmp;
-       if (subset == set) {
-               /* avoid infinite loop */
-               subset = NULL;
-       }
+
+       /* avoid infinite loop */
+       for (tmp = subset ; tmp ; tmp = tmp->subset)
+               if (tmp == set)
+                       return -1;
+
        tmp = set->subset;
        set->subset = afb_apiset_addref(subset);
        afb_apiset_unref(tmp);
+
+       return 0;
 }
 
 void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*))
index 5aacecc..1a115fb 100644 (file)
@@ -38,7 +38,7 @@ extern void afb_apiset_onlack_set(
                void *closure,
                void (*cleanup)(void*closure));
 
-extern void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset);
+extern int afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset);
 extern struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set);
 
 extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api);
index 3f32e87..f199681 100644 (file)
@@ -534,8 +534,7 @@ static void startup_call_unref(struct afb_xreq *xreq)
        free(sreq->api);
        free(sreq->verb);
        json_object_put(sreq->xreq.json);
-       sreq->index++;
-       if (sreq->index < sreq->count)
+       if (++sreq->index < sreq->count)
                startup_call_current(sreq);
        else {
                afb_session_close(sreq->session);
index f0349a6..b516a9d 100644 (file)
@@ -24,6 +24,7 @@ if(check_FOUND)
        add_subdirectory(session)
        add_subdirectory(apiset)
        add_subdirectory(apiv3)
+       add_subdirectory(wrap-json)
 else(check_FOUND)
        MESSAGE(WARNING "check not found! no test!")
 endif(check_FOUND)
index ccab463..b49ade9 100644 (file)
@@ -549,6 +549,49 @@ END_TEST
 
 /*********************************************************************/
 
+START_TEST (check_subset)
+{
+       int rc;
+       struct afb_apiset *a, *b, *c, *d;
+
+       a = afb_apiset_create_subset_first(NULL, "a", 0);
+       ck_assert_ptr_nonnull(a);
+       ck_assert_str_eq("a", afb_apiset_name(a));
+       ck_assert_ptr_null(afb_apiset_subset_get(a));
+
+       b = afb_apiset_create_subset_first(a, "b", 0);
+       ck_assert_ptr_nonnull(b);
+       ck_assert_str_eq("b", afb_apiset_name(b));
+       ck_assert_ptr_eq(b, afb_apiset_subset_get(a));
+       ck_assert_ptr_null(afb_apiset_subset_get(b));
+
+       c = afb_apiset_create_subset_first(a, "c", 0);
+       ck_assert_ptr_nonnull(c);
+       ck_assert_str_eq("c", afb_apiset_name(c));
+       ck_assert_ptr_eq(c, afb_apiset_subset_get(a));
+       ck_assert_ptr_eq(b, afb_apiset_subset_get(c));
+       ck_assert_ptr_null(afb_apiset_subset_get(b));
+
+       d = afb_apiset_create_subset_last(a, "d", 0);
+       ck_assert_ptr_nonnull(d);
+       ck_assert_str_eq("d", afb_apiset_name(d));
+       ck_assert_ptr_eq(c, afb_apiset_subset_get(a));
+       ck_assert_ptr_eq(b, afb_apiset_subset_get(c));
+       ck_assert_ptr_eq(d, afb_apiset_subset_get(b));
+       ck_assert_ptr_null(afb_apiset_subset_get(d));
+
+       rc = afb_apiset_subset_set(a, b);
+       ck_assert(rc == 0);
+       ck_assert_ptr_eq(b, afb_apiset_subset_get(a));
+       ck_assert_ptr_eq(d, afb_apiset_subset_get(b));
+       ck_assert_ptr_null(afb_apiset_subset_get(d));
+
+       afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+
 static Suite *suite;
 static TCase *tcase;
 
@@ -575,5 +618,6 @@ int main(int ac, char **av)
                        addtest(check_onlack);
                        addtest(check_settings);
                        addtest(check_classes);
+                       addtest(check_subset);
        return !!srun();
 }
index 8e22433..651320a 100644 (file)
@@ -41,6 +41,69 @@ void tclone(struct json_object *object)
        json_object_put(o);
 }
 
+
+void objcb(void *closure, struct json_object *obj, const char *key)
+{
+       const char *prefix = closure;
+       printf("  %s {%s} %s\n", prefix ?: "", key ?: "[]", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_NOSLASHESCAPE));
+}
+
+void arrcb(void *closure, struct json_object *obj)
+{
+       objcb(closure, obj, NULL);
+}
+
+void tforall(struct json_object *object)
+{
+       wrap_json_for_all(object, objcb, "wrap_json_for_all");
+       wrap_json_optobject_for_all(object, objcb, "wrap_json_optobject_for_all");
+       wrap_json_object_for_all(object, objcb, "wrap_json_object_for_all");
+       wrap_json_optarray_for_all(object, arrcb, "wrap_json_optarray_for_all");
+       wrap_json_array_for_all(object, arrcb, "wrap_json_array_for_all");
+}
+
+struct mix
+{
+       int n;
+       struct json_object *pair[2];
+};
+
+void mixcb(void *closure, struct json_object *obj, const char *key)
+{
+       struct mix *mix = closure;
+
+       if (!mix->n) {
+               mix->pair[0] = json_object_new_object();
+               mix->pair[1] = json_object_new_object();
+       }
+       json_object_object_add(mix->pair[mix->n & 1], key, json_object_get(obj));
+       mix->n++;
+}
+
+void tmix(struct json_object *object)
+{
+       struct json_object *z;
+       struct mix mix = { .n = 0 };
+
+       wrap_json_object_for_all(object, mixcb, &mix);
+       if (mix.n) {
+               z = wrap_json_object_add(wrap_json_clone(mix.pair[0]), mix.pair[1]);
+               if (!wrap_json_contains(z, mix.pair[0]))
+                       printf("  ERROR mix/1\n");
+               if (!wrap_json_contains(z, mix.pair[1]))
+                       printf("  ERROR mix/2\n");
+               if (!wrap_json_contains(z, object))
+                       printf("  ERROR mix/3\n");
+               if (!wrap_json_contains(object, z))
+                       printf("  ERROR mix/4\n");
+               if (!wrap_json_equal(object, z))
+                       printf("  ERROR mix/5\n");
+               json_object_put(z);
+               json_object_put(mix.pair[0]);
+               json_object_put(mix.pair[1]);
+       }
+}
+
 void p(const char *desc, ...)
 {
        int rc;
@@ -66,11 +129,74 @@ struct json_object *xo[10];
 size_t xz[10];
 uint8_t *xy[10];
 
+int extrchk(const char *desc, const char **array, int length, va_list args)
+{
+       unsigned m, k;
+       int n;
+
+       if (!desc)
+               return 0;
+
+       n = 0;
+       k = m = 0;
+       while(*desc) {
+               switch(*desc) {
+               case '{':
+               case '[': k = !(*desc - '{'); m = (m << 1) | k; break;
+               case '}':
+               case ']': m = m >> 1; k = m&1; break;
+               case 's':
+                       if (!k)
+                               (void)va_arg(args, char**);
+                       else {
+                               if (n > length)
+                                       return -1;
+                               array[n++] = va_arg(args, const char*);
+                       }
+                       break;
+               case '%': (void)va_arg(args, size_t*); k = m&1; break;
+               case 'n': k = m&1; break;
+               case 'b':
+               case 'i': (void)va_arg(args, int*); k = m&1; break;
+               case 'I': (void)va_arg(args, int64_t*); k = m&1; break;
+               case 'f':
+               case 'F': (void)va_arg(args, double*); k = m&1; break;
+               case 'o': (void)va_arg(args, struct json_object**), k = m&1; break;
+               case 'O': (void)va_arg(args, struct json_object**); k = m&1; break;
+               case 'y':
+               case 'Y':
+                       (void)va_arg(args, uint8_t**);
+                       (void)va_arg(args, size_t*);
+                       k = m&1;
+                       break;
+               default:
+                       break;
+               }
+               desc++;
+       }
+       return n;
+}
+
+const char *mkeys[5];
+
+void tchk(struct json_object *object, const char *desc, const char **keys, int length, int qrc)
+{
+       int rm, rc;
+
+       rm = wrap_json_match(object, desc, keys[0], keys[1], keys[2], keys[3], keys[4]);
+       rc = wrap_json_check(object, desc, keys[0], keys[1], keys[2], keys[3], keys[4]);
+       if (rc != qrc)
+               printf("  ERROR DIFFERS[char %d err %d] %s\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
+       if (rm != !rc)
+               printf("  ERROR OF MATCH\n");
+}
+
 void u(const char *value, const char *desc, ...)
 {
        unsigned m, k;
-       int rc;
+       int rc, n;
        va_list args;
+       const char *d;
        struct json_object *object, *o;
 
        memset(xs, 0, sizeof xs);
@@ -85,14 +211,15 @@ void u(const char *value, const char *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));
+               printf("  ERROR[char %d err %d] %s", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
        else {
                value = NULL;
                printf("  SUCCESS");
+               d = desc;
                va_start(args, desc);
                k = m = 0;
-               while(*desc) {
-                       switch(*desc) {
+               while(*d) {
+                       switch(*d) {
                        case '{': m = (m << 1) | 1; k = 1; break;
                        case '}': m = m >> 1; k = m&1; break;
                        case '[': m = m << 1; k = 0; break;
@@ -102,7 +229,7 @@ void u(const char *value, const char *desc, ...)
                        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 'I': printf(" I:%lld", (long long int)*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_ext(*va_arg(args, struct json_object**), JSON_C_TO_STRING_NOSLASHESCAPE)); k = m&1; break;
@@ -112,17 +239,27 @@ void u(const char *value, const char *desc, ...)
                                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;
+                               k = m&1;
                                break;
                                }
                        default: break;
                        }
-                       desc++;
+                       d++;
                }
                va_end(args);
-               printf("\n\n");
        }
+       printf("\n");
+       va_start(args, desc);
+       n = extrchk(desc, mkeys, (int)(sizeof mkeys / sizeof *mkeys), args);
+       va_end(args);
+       if (n < 0)
+               printf("  ERROR: too much keys in %s\n", desc);
+       else
+               tchk(object, desc, mkeys, n, rc);
        tclone(object);
+       tforall(object);
+       tmix(object);
+       printf("\n");
        json_object_put(object);
 }
 
@@ -329,6 +466,6 @@ int main()
        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;
 }
-
index a1fcb22..6bf6f4f 100644 (file)
@@ -815,7 +815,7 @@ int wrap_json_check(struct json_object *object, const char *desc, ...)
        va_list args;
 
        va_start(args, desc);
-       rc = vunpack(object, desc, args, 0);
+       rc = wrap_json_vcheck(object, desc, args);
        va_end(args);
        return rc;
 }
@@ -831,9 +831,9 @@ int wrap_json_match(struct json_object *object, const char *desc, ...)
        va_list args;
 
        va_start(args, desc);
-       rc = vunpack(object, desc, args, 0);
+       rc = wrap_json_vmatch(object, desc, args);
        va_end(args);
-       return !rc;
+       return rc;
 }
 
 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
@@ -992,9 +992,13 @@ struct json_object *wrap_json_clone_depth(struct json_object *item, int depth)
 }
 
 /**
- * Clones the 'object': returns a copy of it. But doen't clones
+ * Clones the 'object': returns a copy of it. But doesn't clones
  * the content. Synonym of wrap_json_clone_depth(object, 1).
  *
+ * Be aware that this implementation doesn't clones content that is deeper
+ * than 1 but it does link these contents to the original object and
+ * increments their use count. So, everything deeper that 1 is still available.
+ *
  * @param object the object to clone
  *
  * @return a copy of the object.