changeset 489:349fe29d86d5

Tests: switch to Boost, closes #680
author David Demelier <markand@malikania.fr>
date Sun, 20 Aug 2017 08:16:39 +0200
parents 7e273b7f4f92
children 711575f6f686
files MIGRATING.md cmake/function/IrccdDefineTest.cmake irccd/main.cpp irccdctl/CMakeLists.txt irccdctl/cli.cpp irccdctl/main.cpp libcommon/CMakeLists.txt libcommon/irccd/elapsed-timer.cpp libcommon/irccd/elapsed-timer.hpp libirccd-js/CMakeLists.txt libirccd-js/irccd/js_elapsed_timer_module.cpp libirccd-test/irccd/command-tester.hpp libirccd/irccd/server.cpp libirccd/irccd/server.hpp tests/CMakeLists.txt tests/elapsedtimer/CMakeLists.txt tests/elapsedtimer/main.cpp tests/js-elapsedtimer/main.cpp tests/js-timer/main.cpp tests/logger/main.cpp tests/plugin-ask/main.cpp tests/plugin-auth/main.cpp tests/plugin-history/main.cpp tests/plugin-logger/main.cpp tests/plugin-plugin/main.cpp tests/rules/main.cpp tests/timer/main.cpp
diffstat 27 files changed, 463 insertions(+), 660 deletions(-) [+]
line wrap: on
line diff
--- a/MIGRATING.md	Tue Sep 26 17:18:47 2017 +0200
+++ b/MIGRATING.md	Sun Aug 20 08:16:39 2017 +0200
@@ -25,3 +25,10 @@
 
 Note: these paths are no more automatically detected and set with the new
       `[paths]` and `[paths.<name>]` sections.
+
+### Javascript API
+
+#### Module ElapsedTimer
+
+  - The method ElapsedTimer.reset has been removed, just use `start` instead
+    when you want to accumulate time.
--- a/cmake/function/IrccdDefineTest.cmake	Tue Sep 26 17:18:47 2017 +0200
+++ b/cmake/function/IrccdDefineTest.cmake	Sun Aug 20 08:16:39 2017 +0200
@@ -32,6 +32,8 @@
 # Resources files are copied VERBATIM into the same directory.
 #
 
+find_package(Boost REQUIRED COMPONENTS unit_test_framework)
+
 function(irccd_define_test)
     set(oneValueArgs NAME)
     set(multiValueArgs SOURCES LIBRARIES FLAGS)
@@ -45,8 +47,12 @@
         message(FATAL_ERROR "Please set SOURCES")
     endif ()
 
-    # Always link to googletest
-    list(APPEND TEST_LIBRARIES libirccd-test)
+    list(
+        APPEND
+        TEST_LIBRARIES
+            libirccd-test
+            Boost::unit_test_framework
+    )
 
     # Executable
     add_executable(test-${TEST_NAME} ${TEST_SOURCES})
@@ -62,6 +68,7 @@
         test-${TEST_NAME}
         PRIVATE
             ${TEST_FLAGS}
+            BOOST_TEST_DYN_LINK
             CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
             CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
             SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}"
--- a/irccd/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/irccd/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -210,7 +210,7 @@
     try {
         if (!gid.empty())
 #if defined(HAVE_SETGID)
-            sys::setGid(gid);
+            sys::set_gid(gid);
 #else
             throw std::runtime_error(" gid option not supported on this platform");
 #endif
@@ -224,7 +224,7 @@
     try {
         if (!uid.empty())
 #if defined(HAVE_SETUID)
-            sys::setUid(uid);
+            sys::set_uid(uid);
 #else
             throw std::runtime_error("uid option not supported on this platform");
 #endif
--- a/irccdctl/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
+++ b/irccdctl/CMakeLists.txt	Sun Aug 20 08:16:39 2017 +0200
@@ -18,6 +18,8 @@
 
 project(irccdctl)
 
+find_package(Boost REQUIRED COMPONENTS timer)
+
 set(
     SOURCES
     ${irccdctl_SOURCE_DIR}/CMakeLists.txt
@@ -32,5 +34,5 @@
     TARGET irccdctl
     DESCRIPTION "Irccd controller."
     SOURCES ${SOURCES}
-    LIBRARIES libirccdctl
+    LIBRARIES Boost::timer libirccdctl
 )
--- a/irccdctl/cli.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/irccdctl/cli.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -20,10 +20,11 @@
 #include <iostream>
 #include <sstream>
 
+#include <boost/timer/timer.hpp>
+
 #include <json.hpp>
 
 #include "cli.hpp"
-#include "elapsed-timer.hpp"
 #include "irccdctl.hpp"
 #include "logger.hpp"
 #include "options.hpp"
@@ -65,10 +66,10 @@
     });
 
     try {
-        ElapsedTimer timer;
+        boost::timer::cpu_timer timer;
 
-        while (irccdctl.client().isConnected() && !msg.is_object() && timer.elapsed() < 3000)
-            util::poller::poll(3000 - timer.elapsed(), irccdctl);
+        while (irccdctl.client().isConnected() && !msg.is_object() && timer.elapsed().wall / 1000000LL < 3000)
+            util::poller::poll(3000 - timer.elapsed().wall / 1000000LL, irccdctl);
     } catch (const std::exception &) {
         irccdctl.client().onMessage.disconnect(id);
         throw;
--- a/irccdctl/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/irccdctl/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -19,13 +19,13 @@
 #include <unordered_map>
 
 #include <boost/filesystem.hpp>
+#include <boost/timer/timer.hpp>
 
 #include <format.h>
 
 #include "alias.hpp"
 #include "cli.hpp"
 #include "client.hpp"
-#include "elapsed-timer.hpp"
 #include "fs.hpp"
 #include "ini.hpp"
 #include "irccdctl.hpp"
--- a/libcommon/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
+++ b/libcommon/CMakeLists.txt	Sun Aug 20 08:16:39 2017 +0200
@@ -22,7 +22,6 @@
 
 set(
     HEADERS
-    ${libcommon_SOURCE_DIR}/irccd/elapsed-timer.hpp
     ${libcommon_SOURCE_DIR}/irccd/fs.hpp
     ${libcommon_SOURCE_DIR}/irccd/ini.hpp
     ${libcommon_SOURCE_DIR}/irccd/logger.hpp
@@ -36,7 +35,6 @@
 
 set(
     SOURCES
-    ${libcommon_SOURCE_DIR}/irccd/elapsed-timer.cpp
     ${libcommon_SOURCE_DIR}/irccd/fs.cpp
     ${libcommon_SOURCE_DIR}/irccd/ini.cpp
     ${libcommon_SOURCE_DIR}/irccd/logger.cpp
--- a/libcommon/irccd/elapsed-timer.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * elapsed-timer.cpp -- measure elapsed time
- *
- * Copyright (c) 2013-2017 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 "elapsed-timer.hpp"
-
-using std::chrono::duration_cast;
-using std::chrono::high_resolution_clock;
-using std::chrono::milliseconds;
-
-namespace irccd {
-
-ElapsedTimer::ElapsedTimer() noexcept
-{
-    m_last = high_resolution_clock::now();
-}
-
-void ElapsedTimer::pause() noexcept
-{
-    /*
-     * When we put the timer on pause, do not forget to set the already
-     * elapsed time.
-     */
-    (void)elapsed();
-    m_paused = true;
-}
-
-void ElapsedTimer::restart() noexcept
-{
-    m_paused = false;
-    m_last = high_resolution_clock::now();
-}
-
-void ElapsedTimer::reset() noexcept
-{
-    m_elapsed = 0;
-    m_last = high_resolution_clock::now();
-}
-
-unsigned ElapsedTimer::elapsed() noexcept
-{
-    if (!m_paused) {
-        m_elapsed += duration_cast<milliseconds>(high_resolution_clock::now() - m_last).count();
-        m_last = high_resolution_clock::now();
-    }
-
-    return m_elapsed;
-}
-
-} // !irccd
--- a/libcommon/irccd/elapsed-timer.hpp	Tue Sep 26 17:18:47 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * elapsed-timer.hpp -- measure elapsed time
- *
- * Copyright (c) 2013-2017 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_ELAPSED_TIMER_HPP
-#define IRCCD_ELAPSED_TIMER_HPP
-
-/**
- * \file elapsed-timer.hpp
- * \brief Measure elapsed time
- */
-
-#include <chrono>
-
-#include "sysconfig.hpp"
-
-namespace irccd {
-
-/**
- * \brief Measure elapsed time
- *
- * This class provides an abstraction to measure elapsed time since the
- * construction of the object.
- *
- * It uses std::chrono::high_resolution_clock for more precision and uses
- * milliseconds only.
- */
-class ElapsedTimer {
-private:
-    using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
-
-    TimePoint m_last;
-    bool m_paused{false};
-    unsigned m_elapsed{0};
-
-public:
-    /**
-     * Construct the elapsed timer, start counting.
-     */
-    IRCCD_EXPORT ElapsedTimer() noexcept;
-
-    /**
-     * Virtual destructor defaulted.
-     */
-    virtual ~ElapsedTimer() = default;
-
-    /**
-     * Put the timer on pause, the already elapsed time is stored.
-     */
-    IRCCD_EXPORT void pause() noexcept;
-
-    /**
-     * Restart the timer, does not reset it.
-     */
-    IRCCD_EXPORT void restart() noexcept;
-
-    /**
-     * Reset the timer to 0.
-     */
-    IRCCD_EXPORT void reset() noexcept;
-
-    /**
-     * Get the number of elapsed milliseconds.
-     *
-     * \return the milliseconds
-     */
-    IRCCD_EXPORT unsigned elapsed() noexcept;
-};
-
-} // !irccd
-
-#endif // !IRCCD_ELAPSED_TIMER_HPP
--- a/libirccd-js/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
+++ b/libirccd-js/CMakeLists.txt	Sun Aug 20 08:16:39 2017 +0200
@@ -18,6 +18,8 @@
 
 project(libirccd-js)
 
+find_package(Boost REQUIRED COMPONENTS timer)
+
 set(
     HEADERS
     ${libirccd-js_SOURCE_DIR}/irccd/duktape.hpp
@@ -63,6 +65,7 @@
         ${HEADERS}
         ${SOURCES}
     LIBRARIES
+        Boost::timer
         extern-duktape
         libirccd
     PUBLIC_INCLUDES
--- a/libirccd-js/irccd/js_elapsed_timer_module.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/libirccd-js/irccd/js_elapsed_timer_module.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * js_elapsed_timer_module.cpp -- irccd.ElapsedTimer API
+ * js_elapsed_timer_module.cpp -- Irccd.ElapsedTimer API
  *
  * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
  *
@@ -16,7 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <irccd/elapsed-timer.hpp>
+#include <boost/timer/timer.hpp>
+
 #include <irccd/js_plugin.hpp>
 
 #include "js_elapsed_timer_module.hpp"
@@ -27,13 +28,13 @@
 
 const char* signature("\xff""\xff""irccd-elapsed-timer-ptr");
 
-ElapsedTimer* self(duk_context* ctx)
+boost::timer::cpu_timer* self(duk_context* ctx)
 {
     StackAssert sa(ctx);
 
     duk_push_this(ctx);
     duk_get_prop_string(ctx, -1, signature);
-    auto ptr = static_cast<ElapsedTimer*>(duk_to_pointer(ctx, -1));
+    auto ptr = static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
     duk_pop_2(ctx);
 
     if (!ptr)
@@ -50,20 +51,7 @@
  */
 duk_ret_t pause(duk_context* ctx)
 {
-    self(ctx)->pause();
-
-    return 0;
-}
-
-/*
- * Method: ElapsedTimer.reset
- * ------------------------------------------------------------------
- *
- * Reset the elapsed time to 0, the status is not modified.
- */
-duk_ret_t reset(duk_context* ctx)
-{
-    self(ctx)->reset();
+    self(ctx)->stop();
 
     return 0;
 }
@@ -76,7 +64,7 @@
  */
 duk_ret_t restart(duk_context* ctx)
 {
-    self(ctx)->restart();
+    self(ctx)->resume();
 
     return 0;
 }
@@ -92,13 +80,13 @@
  */
 duk_ret_t elapsed(duk_context* ctx)
 {
-    duk_push_uint(ctx, self(ctx)->elapsed());
+    duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL);
 
     return 1;
 }
 
 /*
- * Function: Irccd.ElapsedTimer() [constructor]
+ * Function: Irccd.ElapsedTimer [constructor]
  * ------------------------------------------------------------------
  *
  * Construct a new ElapsedTimer object.
@@ -106,7 +94,7 @@
 duk_ret_t constructor(duk_context* ctx)
 {
     duk_push_this(ctx);
-    duk_push_pointer(ctx, new ElapsedTimer);
+    duk_push_pointer(ctx, new boost::timer::cpu_timer);
     duk_put_prop_string(ctx, -2, signature);
     duk_pop(ctx);
 
@@ -114,7 +102,7 @@
 }
 
 /*
- * Function: irccd.ElapsedTimer() [destructor]
+ * Function: Irccd.ElapsedTimer [destructor]
  * ------------------------------------------------------------------
  *
  * Delete the property.
@@ -122,7 +110,7 @@
 duk_ret_t destructor(duk_context* ctx)
 {
     duk_get_prop_string(ctx, 0, signature);
-    delete static_cast<ElapsedTimer*>(duk_to_pointer(ctx, -1));
+    delete static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
     duk_pop(ctx);
     duk_del_prop_string(ctx, 0, signature);
 
@@ -132,7 +120,6 @@
 const duk_function_list_entry methods[] = {
     { "elapsed",    elapsed,    0 },
     { "pause",      pause,      0 },
-    { "reset",      reset,      0 },
     { "restart",    restart,    0 },
     { nullptr,      nullptr,    0 }
 };
--- a/libirccd-test/irccd/command-tester.hpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/libirccd-test/irccd/command-tester.hpp	Sun Aug 20 08:16:39 2017 +0200
@@ -19,9 +19,10 @@
 #ifndef IRCCD_COMMAND_TESTER_HPP
 #define IRCCD_COMMAND_TESTER_HPP
 
+#include <boost/timer/timer.hpp>
+
 #include <gtest/gtest.h>
 
-#include "elapsed-timer.hpp"
 #include "irccd.hpp"
 #include "irccdctl.hpp"
 #include "util.hpp"
@@ -43,9 +44,9 @@
     template <typename Predicate>
     void poll(Predicate &&predicate)
     {
-        ElapsedTimer timer;
+        boost::timer::cpu_timer timer;
 
-        while (!predicate() && timer.elapsed() < 30000)
+        while (!predicate() && timer.elapsed().wall / 1000000LL < 30000)
             util::poller::poll(250, m_irccd, m_irccdctl);
     }
 };
--- a/libirccd/irccd/server.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/libirccd/irccd/server.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -88,7 +88,7 @@
 
 class server::disconnected_state : public server::state {
 private:
-    ElapsedTimer timer_;
+    boost::timer::cpu_timer timer_;
 
 public:
     void prepare(server&, fd_set&, fd_set&, net::Handle&) override;
@@ -107,7 +107,7 @@
         connecting
     } state_{disconnected};
 
-    ElapsedTimer timer_;
+    boost::timer::cpu_timer timer_;
 
     bool connect(server& server);
 
@@ -216,7 +216,7 @@
     recocur_ = 1;
 
     // Reset the timer.
-    timer_.reset();
+    timer_.start();
 
     // Reset joined channels.
     jchannels_.clear();
@@ -455,7 +455,7 @@
 void server::handle_ping(const char*, const char**) noexcept
 {
     // Reset the timer to detect disconnection.
-    timer_.reset();
+    timer_.start();
 }
 
 void server::handle_query(const char* orig, const char** params) noexcept
@@ -799,7 +799,7 @@
         log::warning() << "server " << server.name_ << ": giving up" << std::endl;
         server.on_die();
     } else {
-        if (timer_.elapsed() > static_cast<unsigned>(server.recodelay_ * 1000)) {
+        if (timer_.elapsed().wall / 1000000LL > static_cast<unsigned>(server.recodelay_ * 1000)) {
             irc_disconnect(*server.session_);
 
             server.recocur_ ++;
@@ -863,7 +863,7 @@
      * Otherwise, the libircclient event_connect will change the state.
      */
     if (state_ == connecting) {
-        if (timer_.elapsed() > static_cast<unsigned>(server.recodelay_ * 1000)) {
+        if (timer_.elapsed().wall / 1000000LL > static_cast<unsigned>(server.recodelay_ * 1000)) {
             log::warning() << "server " << server.name() << ": timeout while connecting" << std::endl;
             server.next(std::make_unique<disconnected_state>());
         } else if (!irc_is_connected(*server.session_)) {
@@ -918,9 +918,9 @@
             log::warning("server {}: retrying in {} seconds"_format(server.name_, server.recodelay_));
 
         server.next(std::make_unique<disconnected_state>());
-    } else if (server.timer_.elapsed() >= server.timeout_ * 1000) {
+    } else if (server.timer_.elapsed().wall / 1000000LL >= server.timeout_ * 1000) {
         log::warning() << "server " << server.name_ << ": ping timeout after "
-                       << (server.timer_.elapsed() / 1000) << " seconds" << std::endl;
+                       << (server.timer_.elapsed().wall / 1000000000LL) << " seconds" << std::endl;
         server.next(std::make_unique<disconnected_state>());
     } else
         irc_add_select_descriptors(*server.session_, &setinput, &setoutput, reinterpret_cast<int*>(&maxfd));
--- a/libirccd/irccd/server.hpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/libirccd/irccd/server.hpp	Sun Aug 20 08:16:39 2017 +0200
@@ -35,9 +35,10 @@
 #include <utility>
 #include <vector>
 
+#include <boost/timer/timer.hpp>
+
 #include <json.hpp>
 
-#include "elapsed-timer.hpp"
 #include "net.hpp"
 #include "signals.hpp"
 #include "sysconfig.hpp"
@@ -460,7 +461,7 @@
     std::unique_ptr<state> state_next_;
 
     // Misc.
-    ElapsedTimer timer_;
+    boost::timer::cpu_timer timer_;
     std::map<channel_mode, char> modes_;
     std::int8_t recocur_{0};
     std::map<std::string, std::set<std::string>> names_map_;
--- a/tests/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/CMakeLists.txt	Sun Aug 20 08:16:39 2017 +0200
@@ -51,7 +51,6 @@
     add_subdirectory(cmd-server-topic)
 
     # Misc
-    add_subdirectory(elapsedtimer)
     add_subdirectory(logger)
     add_subdirectory(rules)
     add_subdirectory(util)
--- a/tests/elapsedtimer/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2017 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 elapsedtimer
-    SOURCES main.cpp
-    LIBRARIES libirccd
-)
--- a/tests/elapsedtimer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * main.cpp -- test ElapsedTimer
- *
- * Copyright (c) 2013-2017 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 <thread>
-
-#include <gtest/gtest.h>
-
-#include <irccd/elapsed-timer.hpp>
-
-using namespace irccd;
-using namespace std::chrono_literals;
-
-TEST(TestElapsedTimer, standard)
-{
-    ElapsedTimer timer;
-
-    std::this_thread::sleep_for(300ms);
-
-    ASSERT_GE(timer.elapsed(), 250U);
-    ASSERT_LE(timer.elapsed(), 350U);
-}
-
-TEST(TestElapsedTimer, reset)
-{
-    ElapsedTimer timer;
-
-    std::this_thread::sleep_for(300ms);
-
-    timer.reset();
-
-    ASSERT_LE(timer.elapsed(), 100U);
-}
-
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
-
--- a/tests/js-elapsedtimer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/js-elapsedtimer/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -61,24 +61,6 @@
     }
 }
 
-TEST_F(TestElapsedTimer, reset)
-{
-    try {
-        if (duk_peval_string(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
-            throw dukx_exception(m_plugin->context(), -1);
-
-        std::this_thread::sleep_for(300ms);
-
-        if (duk_peval_string(m_plugin->context(), "timer.reset(); result = timer.elapsed();") != 0)
-            throw dukx_exception(m_plugin->context(), -1);
-
-        ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "result"));
-        ASSERT_LE(duk_get_int(m_plugin->context(), -1), 100);
-    } catch (const std::exception &ex) {
-        FAIL() << ex.what();
-    }
-}
-
 int main(int argc, char **argv)
 {
     testing::InitGoogleTest(&argc, argv);
--- a/tests/js-timer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/js-timer/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,50 +16,97 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define BOOST_TEST_MODULE "Timer Javascript API"
-#include <boost/test/unit_test.hpp>
 #include <boost/timer/timer.hpp>
 
+#include <gtest/gtest.h>
+
+#include <irccd/irccd.hpp>
+#include <irccd/logger.hpp>
+#include <irccd/js_irccd_module.hpp>
 #include <irccd/js_plugin_module.hpp>
 #include <irccd/js_timer_module.hpp>
+#include <irccd/js_plugin.hpp>
+#include <irccd/service.hpp>
+#include <irccd/system.hpp>
 
-#include <js_test.hpp>
+using namespace irccd;
+
+class TestJsTimer : public testing::Test {
+protected:
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
-namespace irccd {
+    void open(const std::string &file)
+    {
+        m_plugin = std::make_shared<js_plugin>("timer", file);
 
-class fixture : public js_test<js_plugin_module, js_timer_module> {
-public:
-    using js_test::js_test;
+        js_irccd_module().load(m_irccd, m_plugin);
+        PluginModule().load(m_irccd, m_plugin);
+        js_timer_module().load(m_irccd, m_plugin);
+
+        m_plugin->on_load(m_irccd);
+        m_irccd.plugins().add(m_plugin);
+    }
 };
 
-BOOST_AUTO_TEST_SUITE(js_timer_suite)
-
-BOOST_AUTO_TEST_CASE(single)
+TEST_F(TestJsTimer, single)
 {
-    fixture f(DIRECTORY "/timer-single.js");
+    open(DIRECTORY "/timer-single.js");
 
     boost::timer::cpu_timer timer;
 
     while (timer.elapsed().wall / 1000000LL < 3000)
-        util::poller::poll(512, f.irccd_);
+        util::poller::poll(512, m_irccd);
 
-    BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count"));
-    BOOST_TEST(duk_get_int(f.plugin_->context(), -1) == 1);
+    ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "count"));
+    ASSERT_EQ(1, duk_get_int(m_plugin->context(), -1));
 }
 
-BOOST_AUTO_TEST_CASE(repeat)
+TEST_F(TestJsTimer, repeat)
 {
-    fixture f(DIRECTORY "/timer-repeat.js");
+    open(DIRECTORY "/timer-repeat.js");
 
     boost::timer::cpu_timer timer;
 
     while (timer.elapsed().wall / 1000000LL < 3000)
-        util::poller::poll(512, f.irccd_);
+        util::poller::poll(512, m_irccd);
 
-    BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count"));
-    BOOST_TEST(duk_get_int(f.plugin_->context(), -1) >= 5);
+    ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "count"));
+    ASSERT_GE(duk_get_int(m_plugin->context(), -1), 5);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+#if 0
+
+/*
+ * XXX: currently disabled because it will break single-shot timers.
+ */
+
+TEST(Basic, pending)
+{
+    /*
+     * This test ensure that if pending actions on a stopped timer are never executed.
+     */
+    Irccd irccd;
+    boost::timer::cpu_timer timer;
+
+    auto plugin = std::make_shared<Plugin>("timer", DIRECTORY "/timer-pending.js");
 
-} // !irccd
+    irccd.addPlugin(plugin);
+    irccd.poll();
+    irccd.dispatch();
+
+    ASSERT_EQ(0, plugin->context().getGlobal<int>("count"));
+}
+
+#endif
+
+int main(int argc, char **argv)
+{
+    // Needed for some components.
+    sys::set_program_name("irccd");
+    log::set_logger(std::make_unique<log::silent_logger>());
+    log::set_verbose(true);
+    testing::InitGoogleTest(&argc, argv);
+
+    return RUN_ALL_TESTS();
+}
--- a/tests/logger/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/logger/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -18,88 +18,106 @@
 
 #include <algorithm>
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Logger"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/logger.hpp>
 
-using namespace irccd;
-
-namespace {
+namespace irccd {
 
-std::string lineDebug;
-std::string lineInfo;
-std::string lineWarning;
-
-} // !namespace
-
-class MyInterface : public log::logger {
+class logger_test {
 public:
-    void debug(const std::string &line) override
-    {
-        lineDebug = line;
-    }
+    std::string line_debug;
+    std::string line_info;
+    std::string line_warning;
+
+    class my_logger : public log::logger {
+    private:
+        logger_test& test_;
+
+    public:
+        inline my_logger(logger_test& test) noexcept
+            : test_(test)
+        {
+        }
+
+        void debug(const std::string& line) override
+        {
+            test_.line_debug = line;
+        }
+
+        void info(const std::string& line) override
+        {
+            test_.line_info = line;
+        }
 
-    void info(const std::string &line) override
+        void warning(const std::string& line) override
+        {
+            test_.line_warning = line;
+        }
+    };
+
+    class my_filter : public log::filter {
+    public:
+        std::string pre_debug(std::string input) const override
+        {
+            return std::reverse(input.begin(), input.end()), input;
+        }
+
+        std::string pre_info(std::string input) const override
+        {
+            return std::reverse(input.begin(), input.end()), input;
+        }
+
+        std::string pre_warning(std::string input) const override
+        {
+            return std::reverse(input.begin(), input.end()), input;
+        }
+    };
+
+    logger_test()
     {
-        lineInfo = line;
-    }
-
-    void warning(const std::string &line) override
-    {
-        lineWarning = line;
+        log::set_logger(std::make_unique<my_logger>(*this));
+        log::set_filter(std::make_unique<my_filter>());
+        log::set_verbose(true);
     }
 };
 
-class MyFilter : public log::filter {
-public:
-    std::string pre_debug(std::string input) const override
-    {
-        return std::reverse(input.begin(), input.end()), input;
-    }
-
-    std::string pre_info(std::string input) const override
-    {
-        return std::reverse(input.begin(), input.end()), input;
-    }
-
-    std::string pre_warning(std::string input) const override
-    {
-        return std::reverse(input.begin(), input.end()), input;
-    }
-};
+BOOST_FIXTURE_TEST_SUITE(logger_test_suite, logger_test)
 
 #if !defined(NDEBUG)
 
-TEST(Logger, debug)
+BOOST_AUTO_TEST_CASE(debug)
 {
     log::debug("debug");
 
-    ASSERT_EQ("gubed", lineDebug);
+    BOOST_REQUIRE_EQUAL("gubed", line_debug);
 }
 
 #endif
 
-TEST(Logger, info)
+BOOST_AUTO_TEST_CASE(info)
 {
     log::info("info");
 
-    ASSERT_EQ("ofni", lineInfo);
+    BOOST_REQUIRE_EQUAL("ofni", line_info);
 }
 
-TEST(Logger, warning)
+BOOST_AUTO_TEST_CASE(info_quiet)
+{
+    log::set_verbose(false);
+    log::info("info");
+
+    BOOST_REQUIRE(line_info.empty());
+}
+
+BOOST_AUTO_TEST_CASE(warning)
 {
     log::warning("warning");
 
-    ASSERT_EQ("gninraw", lineWarning);
+    BOOST_REQUIRE_EQUAL("gninraw", line_warning);
 }
 
-int main(int argc, char **argv)
-{
-    log::set_verbose(true);
-    log::set_logger(std::make_unique<MyInterface>());
-    log::set_filter(std::make_unique<MyFilter>());
+BOOST_AUTO_TEST_SUITE_END()
 
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/plugin-ask/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/plugin-ask/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,7 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Ask plugin"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/irccd.hpp>
 #include <irccd/server.hpp>
@@ -24,33 +25,9 @@
 
 #include "plugin_test.hpp"
 
-using namespace irccd;
-
-class server_test : public server {
-private:
-    std::string last_;
-
-public:
-    inline server_test()
-        : server("test")
-    {
-    }
-
-    inline const std::string& last() const noexcept
-    {
-        return last_;
-    }
-
-    void message(std::string target, std::string message) override
-    {
-        last_ = util::join({target, message});
-    }
-};
+namespace irccd {
 
 class ask_test : public plugin_test {
-protected:
-    std::shared_ptr<server_test> server_{new server_test};
-
 public:
     inline ask_test()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
@@ -62,7 +39,9 @@
     }
 };
 
-TEST_F(ask_test, basic)
+BOOST_FIXTURE_TEST_SUITE(ask_test_suite, ask_test)
+
+BOOST_AUTO_TEST_CASE(basic)
 {
     bool no = false;
     bool yes = false;
@@ -74,19 +53,25 @@
     for (int i = 0; i < 1000; ++i) {
         plugin_->on_command(irccd_, {server_, "tester", "#dummy", ""});
 
-        if (server_->last() == "#dummy:tester, YES")
+        auto cmd = server_->cqueue().front();
+
+        BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+        BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#dummy");
+
+        auto msg = cmd["message"].get<std::string>();
+
+        if (msg == "tester, YES")
             yes = true;
-        if (server_->last() == "#dummy:tester, NO")
+        if (msg == "tester, NO")
             no = true;
+
+        server_->cqueue().clear();
     }
 
-    ASSERT_TRUE(no);
-    ASSERT_TRUE(yes);
+    BOOST_REQUIRE(no);
+    BOOST_REQUIRE(yes);
 }
 
-int main(int argc, char** argv)
-{
-    testing::InitGoogleTest(&argc, argv);
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/plugin-auth/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/plugin-auth/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,7 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Auth plugin"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/irccd.hpp>
 #include <irccd/server.hpp>
@@ -24,41 +25,20 @@
 
 #include "plugin_test.hpp"
 
-using namespace irccd;
-
-class server_test : public server {
-private:
-    std::string last_;
-
-public:
-    inline server_test(std::string name)
-        : server(std::move(name))
-    {
-    }
-
-    inline const std::string& last() const noexcept
-    {
-        return last_;
-    }
-
-    void message(std::string target, std::string message) override
-    {
-        last_ = util::join({target, message});
-    }
-};
+namespace irccd {
 
 class auth_test : public plugin_test {
 protected:
-    std::shared_ptr<server_test> nickserv1_;
-    std::shared_ptr<server_test> nickserv2_;
-    std::shared_ptr<server_test> quakenet_;
+    std::shared_ptr<journal_server> nickserv1_;
+    std::shared_ptr<journal_server> nickserv2_;
+    std::shared_ptr<journal_server> quakenet_;
 
 public:
     auth_test()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
-        , nickserv1_(std::make_shared<server_test>("nickserv1"))
-        , nickserv2_(std::make_shared<server_test>("nickserv2"))
-        , quakenet_(std::make_shared<server_test>("quakenet"))
+        , nickserv1_(std::make_shared<journal_server>("nickserv1"))
+        , nickserv2_(std::make_shared<journal_server>("nickserv2"))
+        , quakenet_(std::make_shared<journal_server>("quakenet"))
     {
         plugin_->set_config({
             { "nickserv1.type", "nickserv" },
@@ -74,30 +54,41 @@
     }
 };
 
-TEST_F(auth_test, nickserv1)
+BOOST_FIXTURE_TEST_SUITE(auth_test_suite, auth_test)
+
+BOOST_AUTO_TEST_CASE(nickserv1)
 {
     plugin_->on_connect(irccd_, {nickserv1_});
 
-    ASSERT_EQ("NickServ:identify plopation", nickserv1_->last());
+    auto cmd = nickserv1_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "NickServ");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "identify plopation");
 }
 
-TEST_F(auth_test, nickserv2)
+BOOST_AUTO_TEST_CASE(nickserv2)
 {
     plugin_->on_connect(irccd_, {nickserv2_});
 
-    ASSERT_EQ("NickServ:identify jean something", nickserv2_->last());
+    auto cmd = nickserv2_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "NickServ");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "identify jean something");
 }
 
-TEST_F(auth_test, quakenet)
+BOOST_AUTO_TEST_CASE(quakenet)
 {
     plugin_->on_connect(irccd_, {quakenet_});
 
-    ASSERT_EQ("Q@CServe.quakenet.org:AUTH mario hello", quakenet_->last());
+    auto cmd = quakenet_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "Q@CServe.quakenet.org");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "AUTH mario hello");
 }
 
-int main(int argc, char** argv)
-{
-    testing::InitGoogleTest(&argc, argv);
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/plugin-history/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/plugin-history/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -18,7 +18,8 @@
 
 #include <regex>
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "History plugin"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/irccd.hpp>
 #include <irccd/server.hpp>
@@ -26,37 +27,12 @@
 
 #include "plugin_test.hpp"
 
-using namespace irccd;
-
-class server_test : public server {
-private:
-    std::string last_;
-
-public:
-    inline server_test()
-        : server("test")
-    {
-    }
-
-    inline const std::string& last() const noexcept
-    {
-        return last_;
-    }
-
-    void message(std::string target, std::string message) override
-    {
-        last_ = util::join({target, message});
-    }
-};
+namespace irccd {
 
 class history_test : public plugin_test {
-protected:
-    std::shared_ptr<server_test> server_;
-
 public:
     history_test()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
-        , server_(std::make_shared<server_test>())
     {
         plugin_->set_formats({
             { "error", "error=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}" },
@@ -77,17 +53,24 @@
     }
 };
 
-TEST_F(history_test, formatError)
+BOOST_FIXTURE_TEST_SUITE(history_test_suite, history_test)
+
+BOOST_AUTO_TEST_CASE(format_error)
 {
-    load({{ "file", SOURCEDIR "/broken-conf.json" }});
+    load({{"file", SOURCEDIR "/broken-conf.json"}});
 
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#history", "seen francis"});
-    ASSERT_EQ("#history:error=history:!history:test:#history:jean!jean@localhost:jean", server_->last());
+
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "error=history:!history:test:#history:jean!jean@localhost:jean");
 }
 
-TEST_F(history_test, formatSeen)
+BOOST_AUTO_TEST_CASE(format_seen)
 {
-    std::regex rule("#history:seen=history:!history:test:#history:destructor!dst@localhost:destructor:jean:\\d{2}:\\d{2}");
+    const std::regex rule("seen=history:!history:test:#history:destructor!dst@localhost:destructor:jean:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/seen.json");
     load({{ "file", BINARYDIR "/seen.json" }});
@@ -95,12 +78,16 @@
     plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
     plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "seen jean"});
 
-    ASSERT_TRUE(std::regex_match(server_->last(), rule));
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE(std::regex_match(cmd["message"].get<std::string>(), rule));
 }
 
-TEST_F(history_test, formatSaid)
+BOOST_AUTO_TEST_CASE(format_said)
 {
-    std::regex rule("#history:said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
+    std::regex rule("said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/said.json");
     load({{ "file", BINARYDIR "/said.json" }});
@@ -108,10 +95,14 @@
     plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
     plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "said jean"});
 
-    ASSERT_TRUE(std::regex_match(server_->last(), rule));
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE(std::regex_match(cmd["message"].get<std::string>(), rule));
 }
 
-TEST_F(history_test, formatUnknown)
+BOOST_AUTO_TEST_CASE(format_unknown)
 {
     remove(BINARYDIR "/unknown.json");
     load({{ "file", BINARYDIR "/unknown.json" }});
@@ -119,27 +110,41 @@
     plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
     plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "seen nobody"});
 
-    ASSERT_EQ("#history:unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody", server_->last());
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody");
 }
 
-TEST_F(history_test, case_fix_642)
+BOOST_AUTO_TEST_CASE(fix_642)
 {
-    std::regex rule("#history:said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
+    const std::regex rule("said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/case.json");
     load({{"file", BINARYDIR "/case.json"}});
 
     plugin_->on_message(irccd_, {server_, "JeaN!JeaN@localhost", "#history", "hello"});
 
+    // Full caps.
     plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#HISTORY", "said JEAN"});
-    ASSERT_TRUE(std::regex_match(server_->last(), rule));
+
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE(std::regex_match(cmd["message"].get<std::string>(), rule));
+
+    // Random caps.
     plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#HiSToRy", "said JeaN"});
-    ASSERT_TRUE(std::regex_match(server_->last(), rule));
+
+    cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#history");
+    BOOST_REQUIRE(std::regex_match(cmd["message"].get<std::string>(), rule));
 }
 
-int main(int argc, char** argv)
-{
-    testing::InitGoogleTest(&argc, argv);
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/plugin-logger/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/plugin-logger/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -19,7 +19,8 @@
 #include <fstream>
 #include <iterator>
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Logger plugin"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/irccd.hpp>
 #include <irccd/logger.hpp>
@@ -28,12 +29,10 @@
 
 #include "plugin_test.hpp"
 
-using namespace irccd;
+namespace irccd {
 
 class logger_test : public plugin_test {
 protected:
-    std::shared_ptr<server> server_;
-
     std::string last() const
     {
         std::ifstream file(BINARYDIR "/log.txt");
@@ -44,7 +43,6 @@
 public:
     logger_test()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
-        , server_(std::make_shared<server>("test"))
     {
         remove(BINARYDIR "/log.txt");
 
@@ -73,118 +71,116 @@
     }
 };
 
-TEST_F(logger_test, formatChannelMode)
+BOOST_FIXTURE_TEST_SUITE(logger_test_suite, logger_test)
+
+BOOST_AUTO_TEST_CASE(format_channel_mode)
 {
     load();
 
     plugin_->on_channel_mode(irccd_, {server_, "jean!jean@localhost", "#staff", "+o", "jean"});
 
-    ASSERT_EQ("cmode=test:#staff:jean!jean@localhost:jean:+o:jean\n", last());
+    BOOST_REQUIRE_EQUAL("cmode=test:#staff:jean!jean@localhost:jean:+o:jean\n", last());
 }
 
-TEST_F(logger_test, formatChannelNotice)
+BOOST_AUTO_TEST_CASE(format_channel_notice)
 {
     load();
 
     plugin_->on_channel_notice(irccd_, {server_, "jean!jean@localhost", "#staff", "bonjour!"});
 
-    ASSERT_EQ("cnotice=test:#staff:jean!jean@localhost:jean:bonjour!\n", last());
+    BOOST_REQUIRE_EQUAL("cnotice=test:#staff:jean!jean@localhost:jean:bonjour!\n", last());
 }
 
-TEST_F(logger_test, formatJoin)
+BOOST_AUTO_TEST_CASE(format_join)
 {
     load();
 
     plugin_->on_join(irccd_, {server_, "jean!jean@localhost", "#staff"});
 
-    ASSERT_EQ("join=test:#staff:jean!jean@localhost:jean\n", last());
+    BOOST_REQUIRE_EQUAL("join=test:#staff:jean!jean@localhost:jean\n", last());
 }
 
-TEST_F(logger_test, formatKick)
+BOOST_AUTO_TEST_CASE(format_kick)
 {
     load();
 
     plugin_->on_kick(irccd_, {server_, "jean!jean@localhost", "#staff", "badboy", "please do not flood"});
 
-    ASSERT_EQ("kick=test:#staff:jean!jean@localhost:jean:badboy:please do not flood\n", last());
+    BOOST_REQUIRE_EQUAL("kick=test:#staff:jean!jean@localhost:jean:badboy:please do not flood\n", last());
 }
 
-TEST_F(logger_test, formatMe)
+BOOST_AUTO_TEST_CASE(format_me)
 {
     load();
 
     plugin_->on_me(irccd_, {server_, "jean!jean@localhost", "#staff", "is drinking water"});
 
-    ASSERT_EQ("me=test:#staff:jean!jean@localhost:jean:is drinking water\n", last());
+    BOOST_REQUIRE_EQUAL("me=test:#staff:jean!jean@localhost:jean:is drinking water\n", last());
 }
 
-TEST_F(logger_test, formatMessage)
+BOOST_AUTO_TEST_CASE(format_message)
 {
     load();
 
     plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#staff", "hello guys"});
 
-    ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
+    BOOST_REQUIRE_EQUAL("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
 
-TEST_F(logger_test, formatMode)
+BOOST_AUTO_TEST_CASE(format_mode)
 {
     load();
 
     plugin_->on_mode(irccd_, {server_, "jean!jean@localhost", "+i"});
 
-    ASSERT_EQ("mode=test:jean!jean@localhost:jean:+i:\n", last());
+    BOOST_REQUIRE_EQUAL("mode=test:jean!jean@localhost:jean:+i:\n", last());
 }
 
-TEST_F(logger_test, formatNotice)
+BOOST_AUTO_TEST_CASE(format_notice)
 {
     load();
 
     plugin_->on_notice(irccd_, {server_, "jean!jean@localhost", "tu veux voir mon chat ?"});
 
-    ASSERT_EQ("notice=test:jean!jean@localhost:jean:tu veux voir mon chat ?\n", last());
+    BOOST_REQUIRE_EQUAL("notice=test:jean!jean@localhost:jean:tu veux voir mon chat ?\n", last());
 }
 
-TEST_F(logger_test, formatPart)
+BOOST_AUTO_TEST_CASE(format_part)
 {
     load();
 
     plugin_->on_part(irccd_, {server_, "jean!jean@localhost", "#staff", "too noisy here"});
 
-    ASSERT_EQ("part=test:#staff:jean!jean@localhost:jean:too noisy here\n", last());
+    BOOST_REQUIRE_EQUAL("part=test:#staff:jean!jean@localhost:jean:too noisy here\n", last());
 }
 
-TEST_F(logger_test, formatQuery)
+BOOST_AUTO_TEST_CASE(format_query)
 {
     load();
 
     plugin_->on_query(irccd_, {server_, "jean!jean@localhost", "much irccd, wow"});
 
-    ASSERT_EQ("query=test:jean!jean@localhost:jean:much irccd, wow\n", last());
+    BOOST_REQUIRE_EQUAL("query=test:jean!jean@localhost:jean:much irccd, wow\n", last());
 }
 
-TEST_F(logger_test, formatTopic)
+BOOST_AUTO_TEST_CASE(format_topic)
 {
     load();
 
     plugin_->on_topic(irccd_, {server_, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
 
-    ASSERT_EQ("topic=test:#staff:jean!jean@localhost:jean:oh yeah yeaaaaaaaah\n", last());
+    BOOST_REQUIRE_EQUAL("topic=test:#staff:jean!jean@localhost:jean:oh yeah yeaaaaaaaah\n", last());
 }
 
-TEST_F(logger_test, case_fix_642)
+BOOST_AUTO_TEST_CASE(fix_642)
 {
     load();
 
     plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#STAFF", "hello guys"});
 
-    ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
+    BOOST_REQUIRE_EQUAL("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
 
-int main(int argc, char** argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-    log::set_logger(std::make_unique<log::silent_logger>());
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/plugin-plugin/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/plugin-plugin/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,7 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Plugin plugin"
+#include <boost/test/unit_test.hpp>
 
 #include <format.h>
 
@@ -29,28 +30,7 @@
 
 using namespace fmt::literals;
 
-using namespace irccd;
-
-class server_test : public server {
-private:
-    std::string last_;
-
-public:
-    inline server_test()
-        : server("test")
-    {
-    }
-
-    inline const std::string& last() const noexcept
-    {
-        return last_;
-    }
-
-    void message(std::string target, std::string message) override
-    {
-        last_ = util::join({target, message});
-    }
-};
+namespace irccd {
 
 class fake_plugin : public plugin {
 public:
@@ -64,14 +44,10 @@
     }
 };
 
-class plugin_test_suite : public plugin_test {
-protected:
-    std::shared_ptr<server_test> server_;
-
+class test_fixture : public plugin_test {
 public:
-    plugin_test_suite()
+    test_fixture()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
-        , server_(std::make_shared<server_test>())
     {
         irccd_.plugins().add(std::make_shared<fake_plugin>());
 
@@ -85,46 +61,70 @@
     }
 };
 
-TEST_F(plugin_test_suite, formatUsage)
+BOOST_FIXTURE_TEST_SUITE(test_fixture_suite, test_fixture)
+
+BOOST_AUTO_TEST_CASE(format_usage)
 {
+    nlohmann::json cmd;
+
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", ""});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
+    cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean");
 
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "fail"});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
+    cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean");
 
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info"});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
+    cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean");
 }
 
-TEST_F(plugin_test_suite, formatInfo)
+BOOST_AUTO_TEST_CASE(format_info)
 {
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info fake"});
 
-    ASSERT_EQ("#staff:info=plugin:!plugin:test:#staff:jean!jean@localhost:jean:jean:BEER:fake:Fake White Beer 2000:0.0.0.0.0.1", server_->last());
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "info=plugin:!plugin:test:#staff:jean!jean@localhost:jean:jean:BEER:fake:Fake White Beer 2000:0.0.0.0.0.1");
 }
 
-TEST_F(plugin_test_suite, formatNotFound)
+BOOST_AUTO_TEST_CASE(format_not_found)
 {
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
 
-    ASSERT_EQ("#staff:not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope", server_->last());
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope");
 }
 
-TEST_F(plugin_test_suite, formatTooLong)
+BOOST_AUTO_TEST_CASE(format_too_long)
 {
     for (int i = 0; i < 100; ++i)
         irccd_.plugins().add(std::make_shared<plugin>("plugin-n-{}"_format(i), ""));
 
     plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "list"});
 
-    ASSERT_EQ("#staff:too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
+    auto cmd = server_->cqueue().front();
+
+    BOOST_REQUIRE_EQUAL(cmd["command"].get<std::string>(), "message");
+    BOOST_REQUIRE_EQUAL(cmd["target"].get<std::string>(), "#staff");
+    BOOST_REQUIRE_EQUAL(cmd["message"].get<std::string>(), "too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean");
 }
 
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-    log::set_logger(std::make_unique<log::silent_logger>());
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/rules/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/rules/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,7 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Rules"
+#include <boost/test/unit_test.hpp>
 
 #include <irccd/logger.hpp>
 #include <irccd/rule.hpp>
@@ -64,15 +65,17 @@
  * events       = "onMessage onCommand"
  * action       = accept
  */
-class RulesTest : public testing::Test {
+class rules_test {
 protected:
-    rule_service m_rules;
+    rule_service rules_;
 
-    RulesTest()
+    rules_test()
     {
+        log::set_logger(std::make_unique<log::silent_logger>());
+
         // #1
         {
-            m_rules.add({
+            rules_.add({
                 rule::set{                }, // Servers
                 rule::set{ "#staff"       }, // Channels
                 rule::set{                }, // Origins
@@ -84,7 +87,7 @@
 
         // #2
         {
-            m_rules.add({
+            rules_.add({
                 rule::set{ "unsafe"       },
                 rule::set{ "#staff"       },
                 rule::set{                },
@@ -96,7 +99,7 @@
 
         // #3-1
         {
-            m_rules.add({
+            rules_.add({
                 rule::set{},
                 rule::set{},
                 rule::set{},
@@ -108,7 +111,7 @@
 
         // #3-2
         {
-            m_rules.add({
+            rules_.add({
                 rule::set{ "malikania", "localhost"   },
                 rule::set{ "#games"                   },
                 rule::set{                            },
@@ -120,18 +123,20 @@
     }
 };
 
-TEST_F(RulesTest, basicMatch1)
+BOOST_FIXTURE_TEST_SUITE(rules_test_suite, rules_test)
+
+BOOST_AUTO_TEST_CASE(basic_match1)
 {
     rule m;
 
     /*
      * [rule]
      */
-    ASSERT_TRUE(m.match("freenode", "#test", "a", "", ""));
-    ASSERT_TRUE(m.match("", "", "", "", ""));
+    BOOST_REQUIRE(m.match("freenode", "#test", "a", "", ""));
+    BOOST_REQUIRE(m.match("", "", "", "", ""));
 }
 
-TEST_F(RulesTest, basicMatch2)
+BOOST_AUTO_TEST_CASE(basic_match2)
 {
     rule m(rule::set{"freenode"});
 
@@ -140,12 +145,12 @@
      * servers    = "freenode"
      */
 
-    ASSERT_TRUE(m.match("freenode", "#test", "a", "", ""));
-    ASSERT_FALSE(m.match("malikania", "#test", "a", "", ""));
-    ASSERT_TRUE(m.match("freenode", "", "jean", "", "onMessage"));
+    BOOST_REQUIRE(m.match("freenode", "#test", "a", "", ""));
+    BOOST_REQUIRE(!m.match("malikania", "#test", "a", "", ""));
+    BOOST_REQUIRE(m.match("freenode", "", "jean", "", "onMessage"));
 }
 
-TEST_F(RulesTest, basicMatch3)
+BOOST_AUTO_TEST_CASE(basic_match3)
 {
     rule m(rule::set{"freenode"}, rule::set{"#staff"});
 
@@ -155,12 +160,12 @@
      * channels    = "#staff"
      */
 
-    ASSERT_TRUE(m.match("freenode", "#staff", "a", "", ""));
-    ASSERT_FALSE(m.match("freenode", "#test", "a", "", ""));
-    ASSERT_FALSE(m.match("malikania", "#staff", "a", "", ""));
+    BOOST_REQUIRE(m.match("freenode", "#staff", "a", "", ""));
+    BOOST_REQUIRE(!m.match("freenode", "#test", "a", "", ""));
+    BOOST_REQUIRE(!m.match("malikania", "#staff", "a", "", ""));
 }
 
-TEST_F(RulesTest, basicMatch4)
+BOOST_AUTO_TEST_CASE(basic_match4)
 {
     rule m(rule::set{"malikania"}, rule::set{"#staff"}, rule::set{"a"});
 
@@ -171,12 +176,12 @@
      * plugins    = "a"
      */
 
-    ASSERT_TRUE(m.match("malikania", "#staff", "a", "",""));
-    ASSERT_FALSE(m.match("malikania", "#staff", "b", "", ""));
-    ASSERT_FALSE(m.match("freenode", "#staff", "a", "", ""));
+    BOOST_REQUIRE(m.match("malikania", "#staff", "a", "",""));
+    BOOST_REQUIRE(!m.match("malikania", "#staff", "b", "", ""));
+    BOOST_REQUIRE(!m.match("freenode", "#staff", "a", "", ""));
 }
 
-TEST_F(RulesTest, complexMatch1)
+BOOST_AUTO_TEST_CASE(complex_match1)
 {
     rule m(rule::set{"malikania", "freenode"});
 
@@ -185,61 +190,55 @@
      * servers    = "malikania freenode"
      */
 
-    ASSERT_TRUE(m.match("malikania", "", "", "", ""));
-    ASSERT_TRUE(m.match("freenode", "", "", "", ""));
-    ASSERT_FALSE(m.match("no", "", "", "", ""));
+    BOOST_REQUIRE(m.match("malikania", "", "", "", ""));
+    BOOST_REQUIRE(m.match("freenode", "", "", "", ""));
+    BOOST_REQUIRE(!m.match("no", "", "", "", ""));
 }
 
-TEST_F(RulesTest, basicSolve)
+BOOST_AUTO_TEST_CASE(basic_solve)
 {
     /* Allowed */
-    ASSERT_TRUE(m_rules.solve("malikania", "#staff", "", "a", "onMessage"));
+    BOOST_REQUIRE(rules_.solve("malikania", "#staff", "", "a", "onMessage"));
 
     /* Allowed */
-    ASSERT_TRUE(m_rules.solve("freenode", "#staff", "", "b", "onTopic"));
+    BOOST_REQUIRE(rules_.solve("freenode", "#staff", "", "b", "onTopic"));
 
     /* Not allowed */
-    ASSERT_FALSE(m_rules.solve("malikania", "#staff", "", "", "onCommand"));
+    BOOST_REQUIRE(!rules_.solve("malikania", "#staff", "", "", "onCommand"));
 
     /* Not allowed */
-    ASSERT_FALSE(m_rules.solve("freenode", "#staff", "", "c", "onCommand"));
-
-    /* Allowed */
-    ASSERT_TRUE(m_rules.solve("unsafe", "#staff", "", "c", "onCommand"));
-}
-
-TEST_F(RulesTest, gamesSolve)
-{
-    /* Allowed */
-    ASSERT_TRUE(m_rules.solve("malikania", "#games", "", "game", "onMessage"));
+    BOOST_REQUIRE(!rules_.solve("freenode", "#staff", "", "c", "onCommand"));
 
     /* Allowed */
-    ASSERT_TRUE(m_rules.solve("localhost", "#games", "", "game", "onMessage"));
-
-    /* Allowed */
-    ASSERT_TRUE(m_rules.solve("malikania", "#games", "", "game", "onCommand"));
-
-    /* Not allowed */
-    ASSERT_FALSE(m_rules.solve("malikania", "#games", "", "game", "onQuery"));
-
-    /* Not allowed */
-    ASSERT_FALSE(m_rules.solve("freenode", "#no", "", "game", "onMessage"));
-
-    /* Not allowed */
-    ASSERT_FALSE(m_rules.solve("malikania", "#test", "", "game", "onMessage"));
+    BOOST_REQUIRE(rules_.solve("unsafe", "#staff", "", "c", "onCommand"));
 }
 
-TEST_F(RulesTest, case_fix_645)
+BOOST_AUTO_TEST_CASE(games_solve)
 {
-    ASSERT_FALSE(m_rules.solve("MALIKANIA", "#STAFF", "", "SYSTEM", "onCommand"));
+    /* Allowed */
+    BOOST_REQUIRE(rules_.solve("malikania", "#games", "", "game", "onMessage"));
+
+    /* Allowed */
+    BOOST_REQUIRE(rules_.solve("localhost", "#games", "", "game", "onMessage"));
+
+    /* Allowed */
+    BOOST_REQUIRE(rules_.solve("malikania", "#games", "", "game", "onCommand"));
+
+    /* Not allowed */
+    BOOST_REQUIRE(!rules_.solve("malikania", "#games", "", "game", "onQuery"));
+
+    /* Not allowed */
+    BOOST_REQUIRE(!rules_.solve("freenode", "#no", "", "game", "onMessage"));
+
+    /* Not allowed */
+    BOOST_REQUIRE(!rules_.solve("malikania", "#test", "", "game", "onMessage"));
 }
 
+BOOST_AUTO_TEST_CASE(fix_645)
+{
+    BOOST_REQUIRE(!rules_.solve("MALIKANIA", "#STAFF", "", "SYSTEM", "onCommand"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
 } // !irccd
-
-int main(int argc, char **argv)
-{
-    irccd::log::set_logger(std::make_unique<irccd::log::silent_logger>());
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
--- a/tests/timer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
+++ b/tests/timer/main.cpp	Sun Aug 20 08:16:39 2017 +0200
@@ -16,38 +16,43 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Timer"
+#include <boost/test/unit_test.hpp>
+#include <boost/timer/timer.hpp>
 
-#include <irccd/elapsed-timer.hpp>
 #include <irccd/timer.hpp>
 
-using namespace irccd;
 using namespace std::chrono_literals;
 
-/* --------------------------------------------------------
+namespace irccd {
+
+/*
  * timer object itself
- * -------------------------------------------------------- */
+ * --------------------------------------------------------
+ */
 
-TEST(Basic, single)
+BOOST_AUTO_TEST_SUITE(timer_suite)
+
+BOOST_AUTO_TEST_CASE(single)
 {
     timer timer(timer::type::single, 1000);
-    ElapsedTimer elapsed;
+    boost::timer::cpu_timer elapsed;
     int count = 0;
 
     timer.on_signal.connect([&] () {
-        count = elapsed.elapsed();
+        count = elapsed.elapsed().wall / 1000000LL;
     });
 
-    elapsed.reset();
+    elapsed.start();
     timer.start();
 
     std::this_thread::sleep_for(3s);
 
-    ASSERT_GE(count, 900);
-    ASSERT_LE(count, 1100);
+    BOOST_REQUIRE_GE(count, 900);
+    BOOST_REQUIRE_LE(count, 1100);
 }
 
-TEST(Basic, repeat)
+BOOST_AUTO_TEST_CASE(repeat)
 {
     timer timer(timer::type::repeat, 500);
     int max = 0;
@@ -61,12 +66,12 @@
     // Should be at least 5
     std::this_thread::sleep_for(3s);
 
-    ASSERT_GE(max, 5);
+    BOOST_REQUIRE_GE(max, 5);
 
     timer.stop();
 }
 
-TEST(Basic, restart)
+BOOST_AUTO_TEST_CASE(restart)
 {
     timer timer(timer::type::repeat, 500);
     int max = 0;
@@ -82,15 +87,12 @@
     timer.start();
     std::this_thread::sleep_for(3s);
 
-    ASSERT_GE(max, 10);
-    ASSERT_LT(max, 15);
+    BOOST_REQUIRE_GE(max, 10);
+    BOOST_REQUIRE_LT(max, 15);
 
     timer.stop();
 }
 
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
+BOOST_AUTO_TEST_SUITE_END()
 
-    return RUN_ALL_TESTS();
-}
+} // !irccd