summaryrefslogtreecommitdiffstats
path: root/src/tests
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2018-04-09 18:16:07 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2018-06-15 17:57:36 +0200
commit4521c1e7ae5371ab9d639adc617d17fb4e8ded0c (patch)
treea8a1416a2d58c16ab3993c7e4dc405fc71daab6a /src/tests
parent63682b4da9d3e892d1d0a671de860adc43068142 (diff)
api-v3: First draft
This commit introduces the bindings v3 API for bindings. The documentation has still to be improved and will come very soon. Change-Id: I8f9007370e29f671fdfd1da87fff7372a17db7af Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/CMakeLists.txt2
-rw-r--r--src/tests/apiset/CMakeLists.txt23
-rw-r--r--src/tests/apiset/test-apiset.c579
-rw-r--r--src/tests/apiv3/CMakeLists.txt24
-rw-r--r--src/tests/apiv3/test-apiv3.c198
-rw-r--r--src/tests/session/test-session.c2
6 files changed, 827 insertions, 1 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index f63f27ae..f0349a68 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -22,6 +22,8 @@ if(check_FOUND)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS} ${check_INCLUDE_DIRS})
SET(link_libraries ${link_libraries} ${check_LDFLAGS})
add_subdirectory(session)
+ add_subdirectory(apiset)
+ add_subdirectory(apiv3)
else(check_FOUND)
MESSAGE(WARNING "check not found! no test!")
endif(check_FOUND)
diff --git a/src/tests/apiset/CMakeLists.txt b/src/tests/apiset/CMakeLists.txt
new file mode 100644
index 00000000..180c80b8
--- /dev/null
+++ b/src/tests/apiset/CMakeLists.txt
@@ -0,0 +1,23 @@
+###########################################################################
+# Copyright (C) 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-apiset test-apiset.c)
+target_include_directories(test-apiset PRIVATE ../..)
+target_link_libraries(test-apiset afb-lib ${link_libraries})
+add_test(NAME apiset COMMAND test-apiset)
+
diff --git a/src/tests/apiset/test-apiset.c b/src/tests/apiset/test-apiset.c
new file mode 100644
index 00000000..bdc84137
--- /dev/null
+++ b/src/tests/apiset/test-apiset.c
@@ -0,0 +1,579 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include <check.h>
+#if !defined(ck_assert_ptr_null)
+# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL)
+# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL)
+#endif
+
+#include "afb-api.h"
+#include "afb-apiset.h"
+
+const char *names[] = {
+ "Sadie",
+ "Milford",
+ "Yvette",
+ "Carma",
+ "Cory",
+ "Clarence",
+ "Jeffery",
+ "Molly",
+ "Sheba",
+ "Tasha",
+ "Corey",
+ "Gerry",
+ NULL
+};
+
+const char *aliases[] = {
+ "Rich", "Molly",
+ "Alicia", "Carma",
+ "Drema", "YVETTE",
+ "Pablo", "Sheba",
+ "Wendell", "Sadie",
+ "Cathrine", "CarMa",
+ "Allen", "Corey",
+ "Tori", "Drema",
+ NULL
+};
+
+const char *extras[] = {
+ "Meta",
+ "Delia",
+ "Pearlie",
+ "Hank",
+ "Vena",
+ "Terrance",
+ "Gloria",
+ "Tobi",
+ "Mack",
+ "Rosalee",
+ NULL
+};
+
+struct afb_api_itf api_itf_null = {
+ .call = NULL,
+ .service_start = NULL,
+ .update_hooks = NULL,
+ .get_logmask = NULL,
+ .set_logmask = NULL,
+ .describe = NULL,
+ .unref = NULL
+};
+
+
+/*********************************************************************/
+/* check the initialisation */
+START_TEST (check_initialisation)
+{
+ const char name[] = "name";
+ const char noname[] = "";
+ int to = 3600;
+ int noto = -1;
+ struct afb_apiset *a, *b;
+
+ a = afb_apiset_create(NULL, noto);
+ ck_assert_ptr_nonnull(a);
+ ck_assert_str_eq(noname, afb_apiset_name(a));
+ ck_assert_int_eq(noto, afb_apiset_timeout_get(a));
+ afb_apiset_timeout_set(a, to);
+ ck_assert_int_eq(to, afb_apiset_timeout_get(a));
+ b = afb_apiset_addref(a);
+ ck_assert_ptr_eq(a, b);
+ afb_apiset_unref(b);
+ afb_apiset_unref(a);
+
+ a = afb_apiset_create(name, to);
+ ck_assert_ptr_nonnull(a);
+ ck_assert_str_eq(name, afb_apiset_name(a));
+ ck_assert_int_eq(to, afb_apiset_timeout_get(a));
+ afb_apiset_timeout_set(a, noto);
+ ck_assert_int_eq(noto, afb_apiset_timeout_get(a));
+ b = afb_apiset_addref(a);
+ ck_assert_ptr_eq(a, b);
+ afb_apiset_unref(b);
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+/* check that NULL is a valid value for addref/unref */
+START_TEST (check_sanity)
+{
+ struct afb_apiset *a;
+
+ a = afb_apiset_addref(NULL);
+ ck_assert_ptr_null(a);
+ afb_apiset_unref(NULL);
+ ck_assert(1);
+}
+END_TEST
+
+/*********************************************************************/
+/* check creation and retrieval of apis */
+
+START_TEST (check_creation)
+{
+ int i, j, nn, na;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+ const char *x, *y, **set;
+ const struct afb_api_item *pa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; names[i] != NULL ; i++) {
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)names[i];
+ sa.group = names[i];
+ ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa));
+ pa = afb_apiset_lookup(a, names[i], 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(sa.itf, pa->itf);
+ ck_assert_ptr_eq(sa.closure, pa->closure);
+ ck_assert_ptr_eq(sa.group, pa->group);
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i]));
+ ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i]));
+ ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+ nn = i;
+
+ /* add aliases */
+ for (i = 0 ; aliases[i] != NULL ; i += 2) {
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i]));
+ ck_assert_int_eq(errno, ENOENT);
+ ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i]));
+ x = afb_apiset_unalias(a, aliases[i]);
+ y = afb_apiset_unalias(a, aliases[i + 1]);
+ ck_assert_int_eq(0, strcasecmp(x, y));
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+ na = i / 2;
+
+ /* check extras */
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_ptr_null(pa);
+ ck_assert_int_eq(errno, ENOENT);
+ }
+
+ /* get the names */
+ set = afb_apiset_get_names(a, 0, 1);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, set[i]));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, nn);
+ free(set);
+ set = afb_apiset_get_names(a, 0, 2);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, set[i]));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, na);
+ free(set);
+ set = afb_apiset_get_names(a, 0, 3);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, nn + na);
+
+ /* removes the apis to check deletion */
+ for (i = 0 ; i < nn + na ; i++) {
+ if (!set[i])
+ continue;
+
+ /* should be present */
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+
+ /* deleting a non aliased api removes the aliases! */
+ if (!afb_apiset_is_alias(a, set[i])) {
+ for (j = i + 1 ; j < nn + na ; j++) {
+ if (!set[j])
+ continue;
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0));
+ if (afb_apiset_is_alias(a, set[j])
+ && afb_apiset_lookup(a, set[i], 0) == afb_apiset_lookup(a, set[j], 0)) {
+ ck_assert(set[j][0] > 0);
+ ((char*)set[j])[0] = (char)-set[j][0];
+ }
+ }
+ }
+
+ /* delete now */
+ ck_assert_int_eq(0, afb_apiset_del(a, set[i]));
+ ck_assert_ptr_null(afb_apiset_lookup(a, set[i], 0));
+
+ /* check other not removed except aliases */
+ for (j = i + 1 ; j < nn + na ; j++) {
+ if (!set[j])
+ continue;
+ if (set[j][0] > 0)
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0));
+ else {
+ ((char*)set[j])[0] = (char)-set[j][0];
+ ck_assert_ptr_null(afb_apiset_lookup(a, set[j], 0));
+ set[j] = NULL;
+ }
+ }
+ }
+ free(set);
+
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+/* check onlack behaviour */
+
+int onlackcount;
+
+static void onlackcleanup(void *closure)
+{
+ int *count = closure;
+ ck_assert_ptr_eq(count, &onlackcount);
+ *count = 0;
+}
+static int onlack(void *closure, struct afb_apiset *a, const char *name)
+{
+ int *count = closure;
+ struct afb_api_item sa;
+
+ ck_assert_ptr_eq(count, &onlackcount);
+ (*count)++;
+
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)name;
+ sa.group = name;
+
+ ck_assert_int_eq(0, afb_apiset_add(a, name, sa));
+ return 1;
+}
+
+START_TEST (check_onlack)
+{
+ int i;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+ const char *x, *y;
+ const struct afb_api_item *pa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; names[i] != NULL ; i++) {
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)names[i];
+ sa.group = names[i];
+ ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa));
+ pa = afb_apiset_lookup(a, names[i], 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(sa.itf, pa->itf);
+ ck_assert_ptr_eq(sa.closure, pa->closure);
+ ck_assert_ptr_eq(sa.group, pa->group);
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i]));
+ ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i]));
+ ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+
+ /* add aliases */
+ for (i = 0 ; aliases[i] != NULL ; i += 2) {
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i]));
+ ck_assert_int_eq(errno, ENOENT);
+ ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i]));
+ x = afb_apiset_unalias(a, aliases[i]);
+ y = afb_apiset_unalias(a, aliases[i + 1]);
+ ck_assert_int_eq(0, strcasecmp(x, y));
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+
+ /* check extras */
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_ptr_null(pa);
+ ck_assert_int_eq(errno, ENOENT);
+ }
+
+ /* put the onlack feature */
+ afb_apiset_onlack_set(a, onlack, &onlackcount, onlackcleanup);
+
+ /* check extras */
+ onlackcount = 0;
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ ck_assert_int_eq(onlackcount, i);
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_int_eq(onlackcount, i + 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(&api_itf_null, pa->itf);
+ ck_assert_ptr_eq(extras[i], pa->closure);
+ ck_assert_ptr_eq(extras[i], pa->group);
+ }
+
+ ck_assert_int_eq(onlackcount, i);
+ afb_apiset_unref(a);
+ ck_assert_int_eq(onlackcount, 0);
+}
+END_TEST
+
+/*********************************************************************/
+
+struct set_api {
+ const char *name;
+ int init;
+ int mask;
+} set_apis[] = {
+ { "Sadie", 0, 0 },
+ { "Milford", 0, 0 },
+ { "Yvette", 0, 0 },
+ { "Carma", 0, 0 },
+ { "Cory", 0, 0 },
+ { "Clarence", 0, 0 },
+ { "Jeffery", 0, 0 },
+ { "Molly", 0, 0 },
+ { "Sheba", 0, 0 },
+ { "Tasha", 0, 0 },
+ { "Corey", 0, 0 },
+ { "Gerry", 0, 0 },
+ { NULL, 0, 0 }
+};
+
+int set_count;
+struct set_api *set_last_api;
+
+void set_cb0(void *closure)
+{
+ set_last_api = closure;
+ set_count++;
+}
+
+void set_cb_setmask(void *closure, int mask)
+{
+ set_cb0(closure);
+ set_last_api->mask = mask;
+}
+
+int set_cb_getmask(void *closure)
+{
+ set_cb0(closure);
+ return set_last_api->mask;
+}
+
+int set_cb_start(void *closure, int share_session, int onneed)
+{
+ set_cb0(closure);
+ ck_assert_int_eq(0, set_last_api->init);
+ set_last_api->init = 1;
+ return 0;
+}
+
+struct afb_api_itf set_api_itf = {
+ .call = NULL,
+ .service_start = set_cb_start,
+ .update_hooks = set_cb0,
+ .get_logmask = set_cb_getmask,
+ .set_logmask = set_cb_setmask,
+ .describe = NULL,
+ .unref = set_cb0
+};
+
+START_TEST (check_settings)
+{
+ int i, nn, mask;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; set_apis[i].name != NULL ; i++) {
+ sa.itf = &set_api_itf;
+ sa.closure = &set_apis[i];
+ sa.group = NULL;
+ ck_assert_int_eq(0, afb_apiset_add(a, set_apis[i].name, sa));
+ }
+ nn = i;
+
+ set_count = 0;
+ afb_apiset_start_all_services(a, 1);
+ ck_assert_int_eq(nn, set_count);
+
+ set_count = 0;
+ afb_apiset_update_hooks(a, NULL);
+ ck_assert_int_eq(nn, set_count);
+
+ for (mask = 1 ; !(mask >> 10) ; mask <<= 1) {
+ set_count = 0;
+ afb_apiset_set_logmask(a, NULL, mask);
+ ck_assert_int_eq(nn, set_count);
+ set_count = 0;
+ for (i = 0 ; set_apis[i].name != NULL ; i++) {
+ ck_assert_int_eq(mask, afb_apiset_get_logmask(a, set_apis[i].name));
+ ck_assert_ptr_eq(set_last_api, &set_apis[i]);
+ ck_assert_int_eq(i + 1, set_count);
+ }
+ }
+
+ set_count = 0;
+ afb_apiset_unref(a);
+ ck_assert_int_eq(nn, set_count);
+}
+END_TEST
+
+/*********************************************************************/
+
+struct clacl {
+ const char *name;
+ int count;
+} clacl[] = {
+ { "Sadie", 0 },
+ { "Milford", 0 },
+ { "Yvette", 0 },
+};
+
+struct clapi {
+ const char *name;
+ const char *provides;
+ const char *requires;
+ const char *apireq;
+ int init;
+ int expect;
+} clapi[] = {
+ { "Carma", "", "Sadie", "", 0, 9 },
+ { "Cory", "Milford", "", "Clarence", 0, 3 },
+ { "Clarence", "Milford", "", "Jeffery", 0, 2 },
+ { "Jeffery", "Milford", "", "", 0, 1 },
+ { "Molly", "Yvette", "", "Corey", 0, 6 },
+ { "Sheba", "Yvette", "Milford", "Molly", 0, 7 },
+ { "Tasha", "Sadie", "Yvette", "", 0, 8 },
+ { "Corey", "Sadie", "Milford", "Gerry", 0, 5 },
+ { "Gerry", "Sadie", "Milford", "", 0, 4 },
+ { NULL, NULL, NULL, NULL, 0, 0 }
+};
+
+int clorder;
+
+int clacb_start(void *closure, int share_session, int onneed)
+{
+ struct clapi *a = closure;
+ int i;
+
+ ck_assert_int_eq(0, a->init);
+
+ for (i = 0 ; clapi[i].name ; i++) {
+ if (a->requires && a->requires[0]
+ && clapi[i].provides && clapi[i].provides[0]
+ && !strcmp(a->requires, clapi[i].provides))
+ ck_assert_int_ne(0, clapi[i].init);
+ if (a->apireq && a->apireq[0]
+ && !strcmp(a->apireq, clapi[i].name))
+ ck_assert_int_ne(0, clapi[i].init);
+ }
+ a->init = ++clorder;
+ ck_assert_int_eq(a->init, a->expect);
+
+ return 0;
+}
+
+struct afb_api_itf clitf = {
+ .call = NULL,
+ .service_start = clacb_start,
+ .update_hooks = NULL,
+ .get_logmask = NULL,
+ .set_logmask = NULL,
+ .describe = NULL,
+ .unref = NULL
+};
+
+START_TEST (check_classes)
+{
+ int i;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; clapi[i].name != NULL ; i++) {
+ sa.itf = &clitf;
+ sa.closure = &clapi[i];
+ sa.group = NULL;
+ ck_assert_int_eq(0, afb_apiset_add(a, clapi[i].name, sa));
+ }
+
+ /* add constraints */
+ for (i = 0 ; clapi[i].name != NULL ; i++) {
+ if (clapi[i].provides && clapi[i].provides[0])
+ ck_assert_int_eq(0, afb_apiset_provide_class(a, clapi[i].name, clapi[i].provides));
+ if (clapi[i].requires && clapi[i].requires[0])
+ ck_assert_int_eq(0, afb_apiset_require_class(a, clapi[i].name, clapi[i].requires));
+ if (clapi[i].apireq && clapi[i].apireq[0])
+ ck_assert_int_eq(0, afb_apiset_require(a, clapi[i].name, clapi[i].apireq));
+ }
+
+ /* start all */
+ ck_assert_int_eq(0, afb_apiset_start_all_services(a, 0));
+
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+
+static Suite *suite;
+static TCase *tcase;
+
+void mksuite(const char *name) { suite = suite_create(name); }
+void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); }
+void addtest(TFun fun) { tcase_add_test(tcase, fun); }
+int srun()
+{
+ int nerr;
+ SRunner *srunner = srunner_create(suite);
+ srunner_run_all(srunner, CK_NORMAL);
+ nerr = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+ return nerr;
+}
+
+int main(int ac, char **av)
+{
+ mksuite("apiset");
+ addtcase("apiset");
+ addtest(check_initialisation);
+ addtest(check_sanity);
+ addtest(check_creation);
+ addtest(check_onlack);
+ addtest(check_settings);
+ addtest(check_classes);
+ return !!srun();
+}
diff --git a/src/tests/apiv3/CMakeLists.txt b/src/tests/apiv3/CMakeLists.txt
new file mode 100644
index 00000000..dfc44619
--- /dev/null
+++ b/src/tests/apiv3/CMakeLists.txt
@@ -0,0 +1,24 @@
+###########################################################################
+# Copyright (C) 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-apiv3 test-apiv3.c)
+target_include_directories(test-apiv3 PRIVATE ../..)
+target_link_libraries(test-apiv3 afb-lib ${link_libraries})
+add_test(NAME apiv3 COMMAND test-apiv3)
+
+
diff --git a/src/tests/apiv3/test-apiv3.c b/src/tests/apiv3/test-apiv3.c
new file mode 100644
index 00000000..dec1af97
--- /dev/null
+++ b/src/tests/apiv3/test-apiv3.c
@@ -0,0 +1,198 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include <check.h>
+
+#if !defined(ck_assert_ptr_null)
+# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL)
+# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL)
+#endif
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-api-v3.h"
+
+struct inapis {
+ struct afb_binding_v3 desc;
+ struct afb_api_x3 *api;
+ int init;
+};
+
+struct inapis inapis[] = {
+ { .desc = {
+ .api = "ezra",
+ .provide_class = "e",
+ .require_class = "c",
+ .require_api = "armel"
+ }},
+ { .desc = {
+ .api = "clara",
+ .provide_class = "c",
+ .require_class = "a"
+ }},
+ { .desc = {
+ .api = "amelie",
+ .provide_class = "a",
+ .require_api = "albert armel"
+ }},
+ { .desc = {
+ .api = "chloe",
+ .provide_class = "c a"
+ }},
+ { .desc = {
+ .api = "albert",
+ .provide_class = "a"
+ }},
+ { .desc = {
+ .api = "armel",
+ .provide_class = "a",
+ .require_api = "albert"
+ }},
+ { .desc = { .api = NULL }}
+};
+
+int last_in_init;
+
+int in_init(struct afb_api_x3 *api)
+{
+ struct inapis *desc = api->userdata;
+
+ ck_assert_str_eq(api->apiname, desc->desc.api);
+ ck_assert_int_eq(desc->init, 0);
+
+ desc->init = ++last_in_init;
+ printf("init %d of %s\n", desc->init, api->apiname);
+ return 0;
+}
+
+int in_preinit(void *closure, struct afb_api_x3 *api)
+{
+ int rc;
+ struct inapis *desc = closure;
+
+ printf("default preinit of %s\n", api->apiname);
+
+ ck_assert_ptr_nonnull(api);
+ ck_assert_ptr_nonnull(desc);
+ ck_assert_ptr_nonnull(api->apiname);
+ ck_assert_ptr_null(api->userdata);
+ ck_assert_str_eq(api->apiname, desc->desc.api);
+ ck_assert_ptr_null(desc->api);
+ ck_assert_int_eq(desc->init, 0);
+
+ rc = afb_api_v3_set_binding_fields(&desc->desc, api);
+ ck_assert_int_eq(rc, 0);
+
+ api->userdata = desc;
+ desc->api = api;
+
+ if (desc->desc.preinit)
+ desc->desc.preinit(api);
+
+ if (!desc->desc.init) {
+ rc = afb_api_x3_on_init(api, in_init);
+ ck_assert_int_eq(rc, 0);
+ }
+
+ return 0;
+}
+
+int out_init(struct afb_api_x3 *api)
+{
+ return 0;
+}
+
+struct afb_apiset *apiset;
+char out_apiname[] = "out";
+struct afb_api_v3 *out_v3;
+struct afb_api_x3 *out_api;
+
+int out_preinit(void *closure, struct afb_api_x3 *api)
+{
+ int i;
+ int rc;
+ struct afb_api_x3 *napi;
+
+ ck_assert_ptr_nonnull(api);
+ ck_assert_ptr_eq(closure, out_apiname);
+ ck_assert_ptr_null(api->userdata);
+ ck_assert_str_eq(api->apiname, out_apiname);
+ out_api = api;
+
+ for (i = 0 ; inapis[i].desc.api ; i++) {
+ ck_assert_ptr_null(inapis[i].api);
+ napi = afb_api_x3_new_api(
+ api,
+ inapis[i].desc.api,
+ NULL,
+ 0,
+ in_preinit,
+ &inapis[i]);
+ ck_assert_ptr_nonnull(napi);
+ ck_assert_ptr_nonnull(inapis[i].api);
+ ck_assert_ptr_eq(inapis[i].api, napi);
+ }
+
+ rc = afb_api_x3_on_init(api, out_init);
+ ck_assert_int_eq(rc, 0);
+
+ return 0;
+}
+
+START_TEST (test)
+{
+ int rc;
+
+ apiset = afb_apiset_create("test-apiv3", 1);
+ ck_assert_ptr_nonnull(apiset);
+
+ out_v3 = afb_api_v3_create(
+ apiset,
+ apiset,
+ out_apiname,
+ NULL,
+ 0,
+ out_preinit,
+ out_apiname,
+ 0
+ );
+ ck_assert_ptr_nonnull(out_v3);
+ ck_assert_ptr_nonnull(out_api);
+
+ /* start all services */
+ rc = afb_apiset_start_all_services(apiset, 1);
+ ck_assert_int_eq(rc, 0);
+}
+END_TEST
+
+
+/*********************************************************************/
+
+static Suite *suite;
+static TCase *tcase;
+
+void mksuite(const char *name) { suite = suite_create(name); }
+void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); }
+void addtest(TFun fun) { tcase_add_test(tcase, fun); }
+int srun()
+{
+ int nerr;
+ SRunner *srunner = srunner_create(suite);
+ srunner_run_all(srunner, CK_NORMAL);
+ nerr = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+ return nerr;
+}
+
+int main(int ac, char **av)
+{
+ mksuite("apiv3");
+ addtcase("apiv3");
+ addtest(test);
+ return !!srun();
+}
diff --git a/src/tests/session/test-session.c b/src/tests/session/test-session.c
index 58e57536..637b0a16 100644
--- a/src/tests/session/test-session.c
+++ b/src/tests/session/test-session.c
@@ -55,7 +55,7 @@ START_TEST (check_creation)
ck_assert(afb_session_uuid(s) != NULL);
ck_assert(afb_session_token(s) != NULL);
ck_assert(!afb_session_is_closed(s));
-
+
/* token is the initial one */
ck_assert_str_eq(afb_session_token(s), GOOD_UUID);
ck_assert(afb_session_check_token(s, GOOD_UUID));