changeset 743:473ce856c161

Tests: add irccdctl server-* tests #785
author David Demelier <markand@malikania.fr>
date Thu, 26 Jul 2018 12:29:00 +0200
parents d3660cbf2f3c
children 484e8b8afb6d
files libirccd-test/CMakeLists.txt libirccd-test/irccd/test/server_cli_test.cpp libirccd-test/irccd/test/server_cli_test.hpp tests/src/irccdctl/CMakeLists.txt tests/src/irccdctl/cli-server-disconnect/CMakeLists.txt tests/src/irccdctl/cli-server-disconnect/main.cpp tests/src/irccdctl/cli-server-info/CMakeLists.txt tests/src/irccdctl/cli-server-info/main.cpp tests/src/irccdctl/cli-server-invite/CMakeLists.txt tests/src/irccdctl/cli-server-invite/main.cpp tests/src/irccdctl/cli-server-join/CMakeLists.txt tests/src/irccdctl/cli-server-join/main.cpp tests/src/irccdctl/cli-server-kick/CMakeLists.txt tests/src/irccdctl/cli-server-kick/main.cpp tests/src/irccdctl/cli-server-list/CMakeLists.txt tests/src/irccdctl/cli-server-list/main.cpp tests/src/irccdctl/cli-server-me/CMakeLists.txt tests/src/irccdctl/cli-server-me/main.cpp tests/src/irccdctl/cli-server-message/CMakeLists.txt tests/src/irccdctl/cli-server-message/main.cpp tests/src/irccdctl/cli-server-mode/CMakeLists.txt tests/src/irccdctl/cli-server-mode/main.cpp tests/src/irccdctl/cli-server-nick/CMakeLists.txt tests/src/irccdctl/cli-server-nick/main.cpp tests/src/irccdctl/cli-server-notice/CMakeLists.txt tests/src/irccdctl/cli-server-notice/main.cpp tests/src/irccdctl/cli-server-part/CMakeLists.txt tests/src/irccdctl/cli-server-part/main.cpp tests/src/irccdctl/cli-server-reconnect/CMakeLists.txt tests/src/irccdctl/cli-server-reconnect/main.cpp tests/src/irccdctl/cli-server-topic/CMakeLists.txt tests/src/irccdctl/cli-server-topic/main.cpp
diffstat 32 files changed, 1312 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd-test/CMakeLists.txt	Wed Jul 25 22:15:00 2018 +0200
+++ b/libirccd-test/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -28,6 +28,7 @@
     ${libirccd-test_SOURCE_DIR}/irccd/test/mock_server.hpp
     ${libirccd-test_SOURCE_DIR}/irccd/test/plugin_cli_test.hpp
     ${libirccd-test_SOURCE_DIR}/irccd/test/rule_cli_test.hpp
+    ${libirccd-test_SOURCE_DIR}/irccd/test/server_cli_test.hpp
     $<$<BOOL:${IRCCD_HAVE_JS}>:${libirccd-test_SOURCE_DIR}/irccd/test/plugin_test.hpp>
     $<$<BOOL:${IRCCD_HAVE_JS}>:${libirccd-test_SOURCE_DIR}/irccd/test/js_test.hpp>
 )
@@ -41,6 +42,7 @@
     ${libirccd-test_SOURCE_DIR}/irccd/test/mock_server.cpp
     ${libirccd-test_SOURCE_DIR}/irccd/test/plugin_cli_test.cpp
     ${libirccd-test_SOURCE_DIR}/irccd/test/rule_cli_test.cpp
+    ${libirccd-test_SOURCE_DIR}/irccd/test/server_cli_test.cpp
     $<$<BOOL:${IRCCD_HAVE_JS}>:${libirccd-test_SOURCE_DIR}/irccd/test/plugin_test.cpp>
 )
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-test/irccd/test/server_cli_test.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * server_cli_test.cpp -- test fixture for irccdctl frontend (server support)
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <irccd/daemon/command/server_connect_command.hpp>
+#include <irccd/daemon/command/server_disconnect_command.hpp>
+#include <irccd/daemon/command/server_info_command.hpp>
+#include <irccd/daemon/command/server_invite_command.hpp>
+#include <irccd/daemon/command/server_join_command.hpp>
+#include <irccd/daemon/command/server_kick_command.hpp>
+#include <irccd/daemon/command/server_list_command.hpp>
+#include <irccd/daemon/command/server_me_command.hpp>
+#include <irccd/daemon/command/server_message_command.hpp>
+#include <irccd/daemon/command/server_mode_command.hpp>
+#include <irccd/daemon/command/server_nick_command.hpp>
+#include <irccd/daemon/command/server_notice_command.hpp>
+#include <irccd/daemon/command/server_part_command.hpp>
+#include <irccd/daemon/command/server_reconnect_command.hpp>
+#include <irccd/daemon/command/server_topic_command.hpp>
+
+#include <irccd/daemon/service/transport_service.hpp>
+
+#include "server_cli_test.hpp"
+
+namespace irccd {
+
+server_cli_test::server_cli_test()
+    : server_(new mock_server(irccd_.get_service(), "test", "localhost"))
+{
+    irccd_.servers().add(server_);
+    server_->clear();
+
+    irccd_.transports().get_commands().push_back(std::make_unique<server_connect_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_disconnect_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_info_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_invite_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_join_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_kick_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_list_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_me_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_message_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_mode_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_nick_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_notice_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_part_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_reconnect_command>());
+    irccd_.transports().get_commands().push_back(std::make_unique<server_topic_command>());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-test/irccd/test/server_cli_test.hpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * server_cli_test.hpp -- test fixture for irccdctl frontend (server support)
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IRCCD_TEST_SERVER_CLI_TEST_HPP
+#define IRCCD_TEST_SERVER_CLI_TEST_HPP
+
+/**
+ * \file server_cli_test.hpp
+ * \brief Test fixture for irccdctl frontend (server support).
+ */
+
+#include <irccd/daemon/service/server_service.hpp>
+
+#include <irccd/test/mock_server.hpp>
+
+#include "cli_test.hpp"
+
+namespace irccd {
+
+/**
+ * This class adds all server related transport commands to irccd and a unique
+ * mock server with id "test".
+ */
+class server_cli_test : public cli_test {
+protected:
+    /**
+     * Server automatically added as "test".
+     */
+    std::shared_ptr<mock_server> server_;
+
+public:
+    /**
+     * Default constructor.
+     */
+    server_cli_test();
+};
+
+} // !irccd
+
+#endif // !IRCCD_TEST_SERVER_CLI_TEST_HPP
--- a/tests/src/irccdctl/CMakeLists.txt	Wed Jul 25 22:15:00 2018 +0200
+++ b/tests/src/irccdctl/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -31,3 +31,18 @@
 add_subdirectory(cli-rule-list)
 add_subdirectory(cli-rule-move)
 add_subdirectory(cli-rule-remove)
+
+add_subdirectory(cli-server-disconnect)
+add_subdirectory(cli-server-info)
+add_subdirectory(cli-server-invite)
+add_subdirectory(cli-server-join)
+add_subdirectory(cli-server-kick)
+add_subdirectory(cli-server-list)
+add_subdirectory(cli-server-me)
+add_subdirectory(cli-server-message)
+add_subdirectory(cli-server-mode)
+#add_subdirectory(cli-server-nick)
+add_subdirectory(cli-server-notice)
+add_subdirectory(cli-server-part)
+add_subdirectory(cli-server-reconnect)
+add_subdirectory(cli-server-topic)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-disconnect/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-disconnect
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-disconnect/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * main.cpp -- test irccdctl server-disconnect
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-disconnect"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_disconnect_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(one)
+{
+    const auto s1 = std::make_shared<mock_server>(irccd_.get_service(), "s1", "localhost");
+    const auto s2 = std::make_shared<mock_server>(irccd_.get_service(), "s2", "localhost");
+
+    irccd_.servers().add(s1);
+    irccd_.servers().add(s2);
+    s1->clear();
+    s2->clear();
+    start();
+
+    const auto [code, out, err] = exec({ "server-disconnect", "test" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(server_->find("disconnect").size() == 1U);
+    BOOST_TEST(s1->find("disconnect").size() == 0U);
+    BOOST_TEST(s2->find("disconnect").size() == 0U);
+}
+
+BOOST_AUTO_TEST_CASE(all)
+{
+    const auto s1 = std::make_shared<mock_server>(irccd_.get_service(), "s1", "localhost");
+    const auto s2 = std::make_shared<mock_server>(irccd_.get_service(), "s2", "localhost");
+
+    irccd_.servers().add(s1);
+    irccd_.servers().add(s2);
+    s1->clear();
+    s2->clear();
+    start();
+
+    const auto [code, out, err] = exec({ "server-disconnect" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(server_->find("disconnect").size() == 1U);
+    BOOST_TEST(s1->find("disconnect").size() == 1U);
+    BOOST_TEST(s2->find("disconnect").size() == 1U);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-info/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-info
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-info/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * main.cpp -- test irccdctl server-info
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-info"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_info_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(output)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-info", "test" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 10U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(out[0] == "Name           : test");
+    BOOST_TEST(out[1] == "Host           : localhost");
+    BOOST_TEST(out[2] == "Port           : 6667");
+    BOOST_TEST(out[3] == "Ipv6           : null");
+    BOOST_TEST(out[4] == "SSL            : null");
+    BOOST_TEST(out[5] == "SSL verified   : null");
+    BOOST_TEST(out[6] == "Channels       : ");
+    BOOST_TEST(out[7] == "Nickname       : irccd");
+    BOOST_TEST(out[8] == "User name      : irccd");
+    BOOST_TEST(out[9] == "Real name      : IRC Client Daemon");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-invite/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-invite
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-invite/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * main.cpp -- test irccdctl server-invite
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-invite"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_invite_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(output)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-invite", "test", "francis", "#staff" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("invite");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "francis");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "#staff");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-join/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-join
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-join/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * main.cpp -- test irccdctl server-join
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-join"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_join_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-join", "test", "#staff" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("join");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "");
+}
+
+BOOST_AUTO_TEST_CASE(with_password)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-join", "test", "#staff", "secret" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("join");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "secret");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-kick/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-kick
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd irccdctl
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-kick/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,70 @@
+/*
+ * main.cpp -- test irccdctl server-kick
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-kick"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_kick_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-kick", "test", "francis", "#staff" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("kick");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "francis");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][2]) == "");
+}
+
+BOOST_AUTO_TEST_CASE(with_reason)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-kick", "test", "francis", "#staff", "shhh" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("kick");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "francis");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][2]) == "shhh");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-list/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-list
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-list/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * main.cpp -- test irccdctl server-list
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-list"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_list_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(output)
+{
+    irccd_.servers().add(std::make_unique<mock_server>(irccd_.get_service(), "s1", "localhost"));
+    irccd_.servers().add(std::make_unique<mock_server>(irccd_.get_service(), "s2", "localhost"));
+    start();
+
+    const auto [code, out, err] = exec({ "server-list" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 3U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(out[0] == "test");
+    BOOST_TEST(out[1] == "s1");
+    BOOST_TEST(out[2] == "s2");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-me/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-me
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-me/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * main.cpp -- test irccdctl server-me
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-me"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_me_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-me", "test", "#staff", "hi" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("me");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "hi");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-message/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-message
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-message/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * main.cpp -- test irccdctl server-message
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-message"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_message_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-message", "test", "#staff", "hi" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("message");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "hi");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-mode/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-mode
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-mode/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * main.cpp -- test irccdctl server-mode
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-mode"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_mode_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(user)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-mode", "test", "irccd", "+i" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("mode");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "irccd");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "+i");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][2]) == "");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][3]) == "");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][4]) == "");
+}
+
+BOOST_AUTO_TEST_CASE(channel)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-mode", "test", "#staff", "+b", "francis" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("mode");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "+b");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][2]) == "francis");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][3]) == "");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][4]) == "");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-nick/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-nick
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-nick/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * main.cpp -- test irccdctl server-nick
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-nick"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_nick_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    /*
+     * TODO: we will make server::set_nickname call raw() instead of being
+     * virtual.
+     */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-notice/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-notice
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-notice/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * main.cpp -- test irccdctl server-notice
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-notice"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_notice_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-notice", "test", "francis", "hi" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("notice");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "francis");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "hi");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-part/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-part
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-part/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * main.cpp -- test irccdctl server-part
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-part"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_part_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-part", "test", "#staff" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("part");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "");
+}
+
+BOOST_AUTO_TEST_CASE(with_reason)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-part", "test", "#staff", "sick" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("part");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "sick");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-reconnect/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-reconnect
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-reconnect/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * main.cpp -- test irccdctl server-reconnect
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-reconnect"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_reconnect_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(one)
+{
+    const auto s1 = std::make_shared<mock_server>(irccd_.get_service(), "s1", "localhost");
+    const auto s2 = std::make_shared<mock_server>(irccd_.get_service(), "s2", "localhost");
+
+    irccd_.servers().add(s1);
+    irccd_.servers().add(s2);
+    s1->clear();
+    s2->clear();
+    start();
+
+    const auto [code, out, err] = exec({ "server-reconnect", "test" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(server_->find("disconnect").size() == 1U);
+    BOOST_TEST(server_->find("connect").size() == 1U);
+    BOOST_TEST(s1->find("disconnect").size() == 0U);
+    BOOST_TEST(s2->find("disconnect").size() == 0U);
+    BOOST_TEST(s1->find("connect").size() == 0U);
+    BOOST_TEST(s2->find("connect").size() == 0U);
+}
+
+BOOST_AUTO_TEST_CASE(all)
+{
+    const auto s1 = std::make_shared<mock_server>(irccd_.get_service(), "s1", "localhost");
+    const auto s2 = std::make_shared<mock_server>(irccd_.get_service(), "s2", "localhost");
+
+    irccd_.servers().add(s1);
+    irccd_.servers().add(s2);
+    s1->clear();
+    s2->clear();
+    start();
+
+    const auto [code, out, err] = exec({ "server-reconnect" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+    BOOST_TEST(server_->find("disconnect").size() == 1U);
+    BOOST_TEST(server_->find("connect").size() == 1U);
+    BOOST_TEST(s1->find("disconnect").size() == 1U);
+    BOOST_TEST(s2->find("disconnect").size() == 1U);
+    BOOST_TEST(s1->find("connect").size() == 1U);
+    BOOST_TEST(s2->find("connect").size() == 1U);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-topic/CMakeLists.txt	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,24 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+    NAME cli-server-topic
+    SOURCES main.cpp
+    LIBRARIES libirccd-core
+    DEPENDS irccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/irccdctl/cli-server-topic/main.cpp	Thu Jul 26 12:29:00 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * main.cpp -- test irccdctl server-topic
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "irccdctl server-topic"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/test/server_cli_test.hpp>
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(server_topic_suite, server_cli_test)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+    start();
+
+    const auto [code, out, err] = exec({ "server-topic", "test", "#staff", "welcome" });
+
+    BOOST_TEST(!code);
+    BOOST_TEST(out.size() == 0U);
+    BOOST_TEST(err.size() == 0U);
+
+    const auto cmd = server_->find("topic");
+
+    BOOST_TEST(cmd.size() == 1U);
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][0]) == "#staff");
+    BOOST_TEST(std::any_cast<std::string>(cmd[0][1]) == "welcome");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd