--- /dev/null
+#include<iostream>
+#include <gtest/gtest.h>
+#include <gio/gio.h>
+#include <pthread.h>
+
+#include <tuple>
+#include <utility>
+#include <iostream>
+#include "sessiond.h"
+
+#include "test_hlp.hpp"
+
+template <typename... Args>
+bool all_true(Args... args)
+{
+ return (... && args);
+}
+
+int test_reply_callback (int result, void *cb_data) {
+
+
+ test_user_data_cb_t *user_data = (test_user_data_cb_t *)cb_data;
+
+ user_data->callback_result = result;
+ g_atomic_int_inc(&user_data->callback_reference);
+
+ return result;
+}
+
+int test_switch_callback(int result, void *cb_data) {
+
+ //std::cout << " test_switch_callback" << std::endl;
+ test_user_data_cb_t *user_data = (test_user_data_cb_t *)cb_data;
+
+ user_data->callback_result = result;
+ g_atomic_int_inc(&user_data->callback_reference);
+
+ //std::cout << " test_switch_callback end" << std::endl;
+ return result;
+}
+
+int tud_atomic_int_get(test_user_data_cb_t &arg) {
+ return g_atomic_int_get(&arg.callback_reference);
+}
+
+template<typename T>
+gboolean callback_pending_ud (gpointer data) {
+
+ T *ud = static_cast<T *>(data);
+
+ gboolean is_pending = g_main_context_pending(NULL);
+
+ if(is_pending == TRUE) {
+ return TRUE;
+ }
+
+ auto loop_quit_ready = std::apply([](auto &... args){
+ return ( ( tud_atomic_int_get(args)>=1 ) && ... );
+ }, ud->t);
+
+ if(loop_quit_ready) {
+ g_main_loop_quit((GMainLoop*)ud->loop);
+ }
+
+ return TRUE;
+}
+
+const int user_1 = 1;
+const int user_2 = 2;
+
+
+int test_subsession_switch_user_completion_callback(subsession_event_info info, void *cb_data) {
+
+ test_user_data_cb_t *user_data = (test_user_data_cb_t *)cb_data;
+ user_data->session_uid = info.switch_user.session_uid;
+ user_data->switch_id = info.switch_user.switch_id;
+ user_data->user_id = info.switch_user.next_user;
+ user_data->prev_user_id = info.switch_user.prev_user;
+ user_data->callback_result = -1;
+
+ if(user_data->user_id == user_2 ){
+ user_data->callback_result = 0;
+ g_atomic_int_inc(&user_data->callback_reference);
+ }
+
+ return 0;
+}
+
+
+enum {
+ add_user_1 = 0,
+ add_user_2,
+ remove_user_1,
+ remove_user_2,
+ switch_user_to_1,
+ switch_user_to_2,
+ switch_completion,
+};
+
+using tud_ = test_user_data_cb_t;
+using ud_ = struct ud_ctrl_t<tud_, tud_, tud_, tud_, tud_, tud_, tud_>;
+
+template<int N>
+int add_user_wrap(int user_id, subsession_reply_callback cb, ud_ &ud) {
+
+ std::get<N>(ud.t).user_id = user_id;
+ return subsession_add_user(test_subsession_uid, std::get<N>(ud.t).user_id,
+ cb, (void *)&std::get<N>(ud.t));
+}
+
+template<int N>
+int remove_user_wrap(int user_id, subsession_reply_callback cb, ud_ &ud) {
+
+ std::get<N>(ud.t).user_id = user_id;
+ return subsession_remove_user(test_subsession_uid, std::get<N>(ud.t).user_id,
+ cb, (void *)&std::get<N>(ud.t));
+}
+
+TEST(subsession_switch_user_completion, APISwitchUserCompletion) {
+
+ ud_ ud = { .loop = g_main_loop_new (NULL, FALSE),
+ .t = std::tuple<tud_, tud_, tud_, tud_, tud_, tud_, tud_>(),
+ };
+
+ std::apply([](auto &... args){( (init_user<tud_ &>(args) ), ...); }, ud.t );
+
+ std::get<switch_completion>(ud.t).session_uid = -1;
+ int switch_user_completion_res = subsession_register_event_callback(test_subsession_uid, SUBSESSION_SWITCH_USER_COMPLETION,
+ test_subsession_switch_user_completion_callback, (void *)&std::get<switch_completion>(ud.t) );
+
+ int add_user_res_1 = add_user_wrap<add_user_1>(user_1, test_reply_callback, ud);
+ int add_user_res_2 = add_user_wrap<add_user_2>(user_2, test_reply_callback, ud);
+
+ std::get<switch_user_to_1>(ud.t).prev_user_id = user_1;
+ std::get<switch_user_to_1>(ud.t).user_id = user_1;
+
+ int switch_user_res_to_1 = subsession_switch_user(test_subsession_uid, std::get<switch_user_to_1>(ud.t).user_id, test_switch_callback, (void *)&std::get<switch_user_to_1>(ud.t));
+
+
+ std::get<switch_user_to_2>(ud.t).prev_user_id = user_1;
+ std::get<switch_user_to_2>(ud.t).user_id = user_2;
+
+ int switch_user_res_to_2 = subsession_switch_user(test_subsession_uid, std::get<switch_user_to_2>(ud.t).user_id, test_switch_callback, (void *)&std::get<switch_user_to_2>(ud.t));
+
+ int remove_user_res_1 = remove_user_wrap<remove_user_1>(user_1, test_reply_callback, ud);
+ int remove_user_res_2 = remove_user_wrap<remove_user_2>(user_2, test_reply_callback, ud);
+
+
+ g_idle_add(callback_pending_ud<ud_>,(gpointer*)&ud);
+ g_main_loop_run(ud.loop);
+
+ EXPECT_EQ(switch_user_completion_res, 0);
+ EXPECT_EQ(add_user_res_1, 0);
+ EXPECT_EQ(remove_user_res_1, 0);
+ EXPECT_EQ(switch_user_res_to_1, 0);
+ EXPECT_EQ(switch_user_res_to_2, 0);
+ EXPECT_EQ(add_user_res_2, 0);
+ EXPECT_EQ(remove_user_res_2, 0);
+
+ EXPECT_EQ(0, std::get<add_user_1>(ud.t).callback_result);
+ EXPECT_EQ(0, std::get<add_user_2>(ud.t).callback_result);
+ EXPECT_EQ(0, std::get<switch_user_to_1>(ud.t).callback_result);
+ EXPECT_EQ(0, std::get<switch_user_to_2>(ud.t).callback_result);
+ EXPECT_EQ(0, std::get<remove_user_1>(ud.t).callback_result);
+ EXPECT_EQ(0, std::get<remove_user_2>(ud.t).callback_result);
+
+ auto &user_data_result = std::get<switch_completion>(ud.t);
+
+ EXPECT_EQ(0, user_data_result.callback_result);
+ EXPECT_EQ(user_data_result.session_uid, test_subsession_uid);
+ EXPECT_EQ(user_data_result.user_id, user_2);
+ EXPECT_EQ(user_data_result.prev_user_id, user_1);
+
+}