changeset 487:beb6c638b841

Tests: create plugin_test fixture, closes #677 Improve plugin tests by using a dedicated fixture which automatically loads the plugin and enable some modules on it.
author David Demelier <markand@malikania.fr>
date Fri, 11 Aug 2017 13:45:42 +0200
parents 0b156b82b8c1
children 7e273b7f4f92
files cmake/function/IrccdDefineTest.cmake libirccd-test/CMakeLists.txt libirccd-test/irccd/plugin_test.cpp libirccd-test/irccd/plugin_test.hpp tests/plugin-ask/CMakeLists.txt tests/plugin-ask/main.cpp tests/plugin-auth/CMakeLists.txt tests/plugin-auth/main.cpp tests/plugin-history/CMakeLists.txt tests/plugin-history/main.cpp tests/plugin-logger/CMakeLists.txt tests/plugin-logger/main.cpp tests/plugin-plugin/CMakeLists.txt tests/plugin-plugin/main.cpp
diffstat 14 files changed, 296 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/cmake/function/IrccdDefineTest.cmake	Thu Jul 20 15:12:41 2017 +0200
+++ b/cmake/function/IrccdDefineTest.cmake	Fri Aug 11 13:45:42 2017 +0200
@@ -62,6 +62,8 @@
         test-${TEST_NAME}
         PRIVATE
             ${TEST_FLAGS}
+            CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
+            CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
             SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}"
             BINARYDIR="${CMAKE_CURRENT_BINARY_DIR}"
             IRCCD_TESTS_DIRECTORY="${CMAKE_BINARY_DIR}/tests"
--- a/libirccd-test/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/libirccd-test/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -25,6 +25,8 @@
         ${libirccd-test_SOURCE_DIR}/irccd/command-tester.hpp
         $<$<BOOL:${WITH_JS}>:${libirccd-test_SOURCE_DIR}/irccd/plugin-tester.cpp>
         $<$<BOOL:${WITH_JS}>:${libirccd-test_SOURCE_DIR}/irccd/plugin-tester.hpp>
+        $<$<BOOL:${WITH_JS}>:${libirccd-test_SOURCE_DIR}/irccd/plugin_test.cpp>
+        $<$<BOOL:${WITH_JS}>:${libirccd-test_SOURCE_DIR}/irccd/plugin_test.hpp>
         ${libirccd-test_SOURCE_DIR}/irccd/server-tester.cpp
         ${libirccd-test_SOURCE_DIR}/irccd/server-tester.hpp
     LIBRARIES
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-test/irccd/plugin_test.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * plugin_test.cpp -- test fixture helper for Javascript plugins
+ *
+ * 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 <irccd/mod-directory.hpp>
+#include <irccd/mod-elapsed-timer.hpp>
+#include <irccd/mod-file.hpp>
+#include <irccd/mod-irccd.hpp>
+#include <irccd/mod-logger.hpp>
+#include <irccd/mod-plugin.hpp>
+#include <irccd/mod-server.hpp>
+#include <irccd/mod-system.hpp>
+#include <irccd/mod-timer.hpp>
+#include <irccd/mod-unicode.hpp>
+#include <irccd/mod-util.hpp>
+#include <irccd/plugin-js.hpp>
+#include <irccd/service.hpp>
+
+#include "plugin_test.hpp"
+
+namespace irccd {
+
+plugin_test::plugin_test(std::string name, std::string path)
+{
+    JsPluginLoader loader(irccd_);
+
+    loader.addModule(std::make_unique<IrccdModule>());
+    loader.addModule(std::make_unique<DirectoryModule>());
+    loader.addModule(std::make_unique<ElapsedTimerModule>());
+    loader.addModule(std::make_unique<FileModule>());
+    loader.addModule(std::make_unique<LoggerModule>());
+    loader.addModule(std::make_unique<PluginModule>());
+    loader.addModule(std::make_unique<ServerModule>());
+    loader.addModule(std::make_unique<SystemModule>());
+    loader.addModule(std::make_unique<TimerModule>());
+    loader.addModule(std::make_unique<UnicodeModule>());
+    loader.addModule(std::make_unique<UtilModule>());
+
+    plugin_ = loader.open(name, path);
+    irccd_.plugins().add(plugin_);
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-test/irccd/plugin_test.hpp	Fri Aug 11 13:45:42 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * plugin_test.hpp -- test fixture helper for Javascript plugins
+ *
+ * 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_PLUGIN_TEST_HPP
+#define IRCCD_PLUGIN_TEST_HPP
+
+/**
+ * \file plugin_test.hpp
+ * \brief test fixture helper for Javascript plugins.
+ */
+
+#include <gtest/gtest.h>
+
+#include "irccd.hpp"
+#include "plugin.hpp"
+
+namespace irccd {
+
+/**
+ * \brief test fixture helper for Javascript plugins.
+ *
+ * Holds a plugin that is opened (but not loaded).
+ */
+class plugin_test : public testing::Test {
+protected:
+    irccd irccd_;
+    std::shared_ptr<plugin> plugin_;
+
+public:
+    /**
+     * Construct the fixture test.
+     *
+     * \param name the plugin name (e.g. ask)
+     * \param path the full plugin path (e.g. /usr/libexec/irccd/plugins/ask.js)
+     */
+    plugin_test(std::string name, std::string path);
+};
+
+} // !irccd
+
+#endif // !IRCCD_PLUGIN_TESTER_HPP
--- a/tests/plugin-ask/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-ask/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -18,7 +18,11 @@
 
 irccd_define_test(
     NAME plugin-ask
-    SOURCES main.cpp answers.conf
+    SOURCES
+        ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/answers.conf
     LIBRARIES libirccd
-    FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
+    FLAGS
+        PLUGIN_NAME="ask"
+        PLUGIN_PATH="${CMAKE_SOURCE_DIR}/plugins/ask/ask.js"
 )
--- a/tests/plugin-ask/main.cpp	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-ask/main.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -22,47 +22,47 @@
 #include <irccd/server.hpp>
 #include <irccd/service.hpp>
 
-#include "plugin-tester.hpp"
+#include "plugin_test.hpp"
 
 using namespace irccd;
 
-class ServerTest : public Server {
+class server_test : public Server {
 private:
-    std::string m_last;
+    std::string last_;
 
 public:
-    inline ServerTest()
+    inline server_test()
         : Server("test")
     {
     }
 
-    inline const std::string &last() const noexcept
+    inline const std::string& last() const noexcept
     {
-        return m_last;
+        return last_;
     }
 
     void message(std::string target, std::string message) override
     {
-        m_last = util::join({target, message});
+        last_ = util::join({target, message});
     }
 };
 
-class AskTest : public PluginTester {
+class ask_test : public plugin_test {
 protected:
-    std::shared_ptr<ServerTest> m_server;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<server_test> server_{new server_test};
 
 public:
-    AskTest()
-        : m_server(std::make_shared<ServerTest>())
+    inline ask_test()
+        : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
     {
-        m_irccd.plugins().setConfig("ask", {{"file", SOURCEDIR "/answers.conf"}});
-        m_irccd.plugins().load("ask", PLUGINDIR "/ask.js");
-        m_plugin = m_irccd.plugins().require("ask");
+        plugin_->set_config({
+            { "file", CMAKE_CURRENT_SOURCE_DIR "/answers.conf" }
+        });
+        plugin_->on_load(irccd_);
     }
 };
 
-TEST_F(AskTest, basic)
+TEST_F(ask_test, basic)
 {
     bool no = false;
     bool yes = false;
@@ -72,11 +72,11 @@
      * answers in that amount of tries.
      */
     for (int i = 0; i < 1000; ++i) {
-        m_plugin->onCommand(m_irccd, MessageEvent{m_server, "tester", "#dummy", ""});
+        plugin_->on_command(irccd_, MessageEvent{server_, "tester", "#dummy", ""});
 
-        if (m_server->last() == "#dummy:tester, YES")
+        if (server_->last() == "#dummy:tester, YES")
             yes = true;
-        if (m_server->last() == "#dummy:tester, NO")
+        if (server_->last() == "#dummy:tester, NO")
             no = true;
     }
 
@@ -84,7 +84,7 @@
     ASSERT_TRUE(yes);
 }
 
-int main(int argc, char **argv)
+int main(int argc, char** argv)
 {
     testing::InitGoogleTest(&argc, argv);
 
--- a/tests/plugin-auth/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-auth/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -20,5 +20,7 @@
     NAME plugin-auth
     SOURCES main.cpp
     LIBRARIES libirccd
-    FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
+    FLAGS
+        PLUGIN_NAME="auth"
+        PLUGIN_PATH="${CMAKE_SOURCE_DIR}/plugins/auth/auth.js"
 )
--- a/tests/plugin-auth/main.cpp	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-auth/main.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -22,45 +22,45 @@
 #include <irccd/server.hpp>
 #include <irccd/service.hpp>
 
-#include "plugin-tester.hpp"
+#include "plugin_test.hpp"
 
 using namespace irccd;
 
-class ServerTest : public Server {
+class server_test : public Server {
 private:
-    std::string m_last;
+    std::string last_;
 
 public:
-    inline ServerTest(std::string name)
+    inline server_test(std::string name)
         : Server(std::move(name))
     {
     }
 
-    inline const std::string &last() const noexcept
+    inline const std::string& last() const noexcept
     {
-        return m_last;
+        return last_;
     }
 
     void message(std::string target, std::string message) override
     {
-        m_last = util::join({target, message});
+        last_ = util::join({target, message});
     }
 };
 
-class AuthTest : public PluginTester {
+class auth_test : public plugin_test {
 protected:
-    std::shared_ptr<ServerTest> m_nickserv1;
-    std::shared_ptr<ServerTest> m_nickserv2;
-    std::shared_ptr<ServerTest> m_quakenet;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<server_test> nickserv1_;
+    std::shared_ptr<server_test> nickserv2_;
+    std::shared_ptr<server_test> quakenet_;
 
 public:
-    AuthTest()
-        : m_nickserv1(std::make_shared<ServerTest>("nickserv1"))
-        , m_nickserv2(std::make_shared<ServerTest>("nickserv2"))
-        , m_quakenet(std::make_shared<ServerTest>("quakenet"))
+    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"))
     {
-        m_irccd.plugins().setConfig("auth", {
+        plugin_->set_config({
             { "nickserv1.type", "nickserv" },
             { "nickserv1.password", "plopation" },
             { "nickserv2.type", "nickserv" },
@@ -70,33 +70,32 @@
             { "quakenet.password", "hello" },
             { "quakenet.username", "mario" }
         });
-        m_irccd.plugins().load("auth", PLUGINDIR "/auth.js");
-        m_plugin = m_irccd.plugins().require("auth");
+        plugin_->on_load(irccd_);
     }
 };
 
-TEST_F(AuthTest, nickserv1)
+TEST_F(auth_test, nickserv1)
 {
-    m_plugin->onConnect(m_irccd, ConnectEvent{m_nickserv1});
+    plugin_->on_connect(irccd_, ConnectEvent{nickserv1_});
 
-    ASSERT_EQ("NickServ:identify plopation", m_nickserv1->last());
+    ASSERT_EQ("NickServ:identify plopation", nickserv1_->last());
 }
 
-TEST_F(AuthTest, nickserv2)
+TEST_F(auth_test, nickserv2)
 {
-    m_plugin->onConnect(m_irccd, ConnectEvent{m_nickserv2});
+    plugin_->on_connect(irccd_, ConnectEvent{nickserv2_});
 
-    ASSERT_EQ("NickServ:identify jean something", m_nickserv2->last());
+    ASSERT_EQ("NickServ:identify jean something", nickserv2_->last());
 }
 
-TEST_F(AuthTest, quakenet)
+TEST_F(auth_test, quakenet)
 {
-    m_plugin->onConnect(m_irccd, ConnectEvent{m_quakenet});
+    plugin_->on_connect(irccd_, ConnectEvent{quakenet_});
 
-    ASSERT_EQ("Q@CServe.quakenet.org:AUTH mario hello", m_quakenet->last());
+    ASSERT_EQ("Q@CServe.quakenet.org:AUTH mario hello", quakenet_->last());
 }
 
-int main(int argc, char **argv)
+int main(int argc, char** argv)
 {
     testing::InitGoogleTest(&argc, argv);
 
--- a/tests/plugin-history/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-history/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -20,5 +20,7 @@
     NAME plugin-history
     SOURCES main.cpp
     LIBRARIES libirccd
-    FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
+    FLAGS
+        PLUGIN_NAME="history"
+        PLUGIN_PATH="${CMAKE_SOURCE_DIR}/plugins/history/history.js"
 )
--- a/tests/plugin-history/main.cpp	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-history/main.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -24,41 +24,41 @@
 #include <irccd/server.hpp>
 #include <irccd/service.hpp>
 
-#include "plugin-tester.hpp"
+#include "plugin_test.hpp"
 
 using namespace irccd;
 
-class ServerTest : public Server {
+class server_test : public Server {
 private:
-    std::string m_last;
+    std::string last_;
 
 public:
-    inline ServerTest()
+    inline server_test()
         : Server("test")
     {
     }
 
-    inline const std::string &last() const noexcept
+    inline const std::string& last() const noexcept
     {
-        return m_last;
+        return last_;
     }
 
     void message(std::string target, std::string message) override
     {
-        m_last = util::join({target, message});
+        last_ = util::join({target, message});
     }
 };
 
-class HistoryTest : public PluginTester {
+class history_test : public plugin_test {
 protected:
-    std::shared_ptr<ServerTest> m_server;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<server_test> server_;
 
 public:
-    HistoryTest()
-        : m_server(std::make_shared<ServerTest>())
+    history_test()
+        : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
+        , server_(std::make_shared<server_test>())
     {
-        m_irccd.plugins().setFormats("history", {
+        plugin_->set_formats({
             { "error", "error=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}" },
             { "seen", "seen=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{target}:%H:%M" },
             { "said", "said=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{target}:#{message}:%H:%M" },
@@ -66,79 +66,78 @@
         });
     }
 
-    void load(PluginConfig config = PluginConfig())
+    void load(plugin_config config = {})
     {
         // Add file if not there.
         if (config.count("file") == 0)
             config.emplace("file", SOURCEDIR "/words.conf");
 
-        m_irccd.plugins().setConfig("history", config);
-        m_irccd.plugins().load("history", PLUGINDIR "/history.js");
-        m_plugin = m_irccd.plugins().require("history");
+        plugin_->set_config(config);
+        plugin_->on_load(irccd_);
     }
 };
 
-TEST_F(HistoryTest, formatError)
+TEST_F(history_test, formatError)
 {
     load({{ "file", SOURCEDIR "/broken-conf.json" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "seen francis"});
-    ASSERT_EQ("#history:error=history:!history:test:#history:jean!jean@localhost:jean", m_server->last());
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "seen francis"});
+    ASSERT_EQ("#history:error=history:!history:test:#history:jean!jean@localhost:jean", server_->last());
 }
 
-TEST_F(HistoryTest, formatSeen)
+TEST_F(history_test, formatSeen)
 {
     std::regex rule("#history:seen=history:!history:test:#history:destructor!dst@localhost:destructor:jean:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/seen.json");
     load({{ "file", BINARYDIR "/seen.json" }});
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "seen jean"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "seen jean"});
 
-    ASSERT_TRUE(std::regex_match(m_server->last(), rule));
+    ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
 
-TEST_F(HistoryTest, formatSaid)
+TEST_F(history_test, formatSaid)
 {
     std::regex rule("#history:said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/said.json");
     load({{ "file", BINARYDIR "/said.json" }});
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "said jean"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "said jean"});
 
-    ASSERT_TRUE(std::regex_match(m_server->last(), rule));
+    ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
 
-TEST_F(HistoryTest, formatUnknown)
+TEST_F(history_test, formatUnknown)
 {
     remove(BINARYDIR "/unknown.json");
     load({{ "file", BINARYDIR "/unknown.json" }});
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "seen nobody"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "seen nobody"});
 
-    ASSERT_EQ("#history:unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody", m_server->last());
+    ASSERT_EQ("#history:unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody", server_->last());
 }
 
-TEST_F(HistoryTest, case_fix_642)
+TEST_F(history_test, case_fix_642)
 {
     std::regex rule("#history:said=history:!history:test:#history:destructor!dst@localhost:destructor:jean:hello:\\d{2}:\\d{2}");
 
     remove(BINARYDIR "/case.json");
     load({{"file", BINARYDIR "/case.json"}});
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "JeaN!JeaN@localhost", "#history", "hello"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "JeaN!JeaN@localhost", "#history", "hello"});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#HISTORY", "said JEAN"});
-    ASSERT_TRUE(std::regex_match(m_server->last(), rule));
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#HiSToRy", "said JeaN"});
-    ASSERT_TRUE(std::regex_match(m_server->last(), rule));
+    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#HISTORY", "said JEAN"});
+    ASSERT_TRUE(std::regex_match(server_->last(), rule));
+    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#HiSToRy", "said JeaN"});
+    ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
 
-int main(int argc, char **argv)
+int main(int argc, char** argv)
 {
     testing::InitGoogleTest(&argc, argv);
 
--- a/tests/plugin-logger/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-logger/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -20,5 +20,7 @@
     NAME plugin-logger
     SOURCES main.cpp
     LIBRARIES libirccd
-    FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
+    FLAGS
+        PLUGIN_NAME="logger"
+        PLUGIN_PATH="${CMAKE_SOURCE_DIR}/plugins/logger/logger.js"
 )
--- a/tests/plugin-logger/main.cpp	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-logger/main.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -26,22 +26,13 @@
 #include <irccd/server.hpp>
 #include <irccd/service.hpp>
 
-#include "plugin-tester.hpp"
+#include "plugin_test.hpp"
 
 using namespace irccd;
 
-class ServerTest : public Server {
-public:
-    inline ServerTest()
-        : Server("test")
-    {
-    }
-};
-
-class LoggerTest : public PluginTester {
+class logger_test : public plugin_test {
 protected:
-    std::shared_ptr<ServerTest> m_server;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<Server> server_;
 
     std::string last() const
     {
@@ -51,12 +42,13 @@
     }
 
 public:
-    LoggerTest()
-        : m_server(std::make_shared<ServerTest>())
+    logger_test()
+        : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
+        , server_(std::make_shared<Server>("test"))
     {
         remove(BINARYDIR "/log.txt");
 
-        m_irccd.plugins().setFormats("logger", {
+        plugin_->set_formats({
             { "cmode", "cmode=#{server}:#{channel}:#{origin}:#{nickname}:#{mode}:#{arg}" },
             { "cnotice", "cnotice=#{server}:#{channel}:#{origin}:#{nickname}:#{message}" },
             { "join", "join=#{server}:#{channel}:#{origin}:#{nickname}" },
@@ -71,126 +63,125 @@
         });
     }
 
-    void load(PluginConfig config = PluginConfig())
+    void load(plugin_config config = plugin_config())
     {
         if (config.count("path") == 0)
             config.emplace("path", BINARYDIR "/log.txt");
 
-        m_irccd.plugins().setConfig("logger", config);
-        m_irccd.plugins().load("logger", PLUGINDIR "/logger.js");
-        m_plugin = m_irccd.plugins().require("logger");
+        plugin_->set_config(config);
+        plugin_->on_load(irccd_);
     }
 };
 
-TEST_F(LoggerTest, formatChannelMode)
+TEST_F(logger_test, formatChannelMode)
 {
     load();
 
-    m_plugin->onChannelMode(m_irccd, ChannelModeEvent{m_server, "jean!jean@localhost", "#staff", "+o", "jean"});
+    plugin_->on_channel_mode(irccd_, ChannelModeEvent{server_, "jean!jean@localhost", "#staff", "+o", "jean"});
 
     ASSERT_EQ("cmode=test:#staff:jean!jean@localhost:jean:+o:jean\n", last());
 }
 
-TEST_F(LoggerTest, formatChannelNotice)
+TEST_F(logger_test, formatChannelNotice)
 {
     load();
 
-    m_plugin->onChannelNotice(m_irccd, ChannelNoticeEvent{m_server, "jean!jean@localhost", "#staff", "bonjour!"});
+    plugin_->on_channel_notice(irccd_, ChannelNoticeEvent{server_, "jean!jean@localhost", "#staff", "bonjour!"});
 
     ASSERT_EQ("cnotice=test:#staff:jean!jean@localhost:jean:bonjour!\n", last());
 }
 
-TEST_F(LoggerTest, formatJoin)
+TEST_F(logger_test, formatJoin)
 {
     load();
 
-    m_plugin->onJoin(m_irccd, JoinEvent{m_server, "jean!jean@localhost", "#staff"});
+    plugin_->on_join(irccd_, JoinEvent{server_, "jean!jean@localhost", "#staff"});
 
     ASSERT_EQ("join=test:#staff:jean!jean@localhost:jean\n", last());
 }
 
-TEST_F(LoggerTest, formatKick)
+TEST_F(logger_test, formatKick)
 {
     load();
 
-    m_plugin->onKick(m_irccd, KickEvent{m_server, "jean!jean@localhost", "#staff", "badboy", "please do not flood"});
+    plugin_->on_kick(irccd_, KickEvent{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());
 }
 
-TEST_F(LoggerTest, formatMe)
+TEST_F(logger_test, formatMe)
 {
     load();
 
-    m_plugin->onMe(m_irccd, MeEvent{m_server, "jean!jean@localhost", "#staff", "is drinking water"});
+    plugin_->on_me(irccd_, MeEvent{server_, "jean!jean@localhost", "#staff", "is drinking water"});
 
     ASSERT_EQ("me=test:#staff:jean!jean@localhost:jean:is drinking water\n", last());
 }
 
-TEST_F(LoggerTest, formatMessage)
+TEST_F(logger_test, formatMessage)
 {
     load();
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "hello guys"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "hello guys"});
 
     ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
 
-TEST_F(LoggerTest, formatMode)
+TEST_F(logger_test, formatMode)
 {
     load();
 
-    m_plugin->onMode(m_irccd, ModeEvent{m_server, "jean!jean@localhost", "+i"});
+    plugin_->on_mode(irccd_, ModeEvent{server_, "jean!jean@localhost", "+i"});
 
     ASSERT_EQ("mode=test:jean!jean@localhost:jean:+i:\n", last());
 }
 
-TEST_F(LoggerTest, formatNotice)
+TEST_F(logger_test, formatNotice)
 {
     load();
 
-    m_plugin->onNotice(m_irccd, NoticeEvent{m_server, "jean!jean@localhost", "tu veux voir mon chat ?"});
+    plugin_->on_notice(irccd_, NoticeEvent{server_, "jean!jean@localhost", "tu veux voir mon chat ?"});
 
     ASSERT_EQ("notice=test:jean!jean@localhost:jean:tu veux voir mon chat ?\n", last());
 }
 
-TEST_F(LoggerTest, formatPart)
+TEST_F(logger_test, formatPart)
 {
     load();
 
-    m_plugin->onPart(m_irccd, PartEvent{m_server, "jean!jean@localhost", "#staff", "too noisy here"});
+    plugin_->on_part(irccd_, PartEvent{server_, "jean!jean@localhost", "#staff", "too noisy here"});
 
     ASSERT_EQ("part=test:#staff:jean!jean@localhost:jean:too noisy here\n", last());
 }
 
-TEST_F(LoggerTest, formatQuery)
+TEST_F(logger_test, formatQuery)
 {
     load();
 
-    m_plugin->onQuery(m_irccd, QueryEvent{m_server, "jean!jean@localhost", "much irccd, wow"});
+    plugin_->on_query(irccd_, QueryEvent{server_, "jean!jean@localhost", "much irccd, wow"});
 
     ASSERT_EQ("query=test:jean!jean@localhost:jean:much irccd, wow\n", last());
 }
 
-TEST_F(LoggerTest, formatTopic)
+TEST_F(logger_test, formatTopic)
 {
     load();
 
-    m_plugin->onTopic(m_irccd, TopicEvent{m_server, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
+    plugin_->on_topic(irccd_, TopicEvent{server_, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
 
     ASSERT_EQ("topic=test:#staff:jean!jean@localhost:jean:oh yeah yeaaaaaaaah\n", last());
 }
 
-TEST_F(LoggerTest, case_fix_642)
+TEST_F(logger_test, case_fix_642)
 {
     load();
 
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#STAFF", "hello guys"});
+    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#STAFF", "hello guys"});
 
     ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
 
-int main(int argc, char **argv)
+int main(int argc, char** argv)
 {
     testing::InitGoogleTest(&argc, argv);
     log::setLogger(std::make_unique<log::SilentLogger>());
--- a/tests/plugin-plugin/CMakeLists.txt	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-plugin/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
@@ -20,5 +20,7 @@
     NAME plugin-plugin
     SOURCES main.cpp
     LIBRARIES libirccd
-    FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
+    FLAGS
+        PLUGIN_NAME="plugin"
+        PLUGIN_PATH="${CMAKE_SOURCE_DIR}/plugins/plugin/plugin.js"
 )
--- a/tests/plugin-plugin/main.cpp	Thu Jul 20 15:12:41 2017 +0200
+++ b/tests/plugin-plugin/main.cpp	Fri Aug 11 13:45:42 2017 +0200
@@ -25,100 +25,100 @@
 #include <irccd/server.hpp>
 #include <irccd/service.hpp>
 
-#include "plugin-tester.hpp"
+#include "plugin_test.hpp"
 
 using namespace fmt::literals;
 
 using namespace irccd;
 
-class ServerTest : public Server {
+class server_test : public Server {
 private:
-    std::string m_last;
+    std::string last_;
 
 public:
-    inline ServerTest()
+    inline server_test()
         : Server("test")
     {
     }
 
-    inline const std::string &last() const noexcept
+    inline const std::string& last() const noexcept
     {
-        return m_last;
+        return last_;
     }
 
     void message(std::string target, std::string message) override
     {
-        m_last = util::join({target, message});
+        last_ = util::join({target, message});
     }
 };
 
-class FakePlugin : public Plugin {
+class fake_plugin : public plugin {
 public:
-    FakePlugin()
-        : Plugin("fake", "")
+    fake_plugin()
+        : plugin("fake", "")
     {
-        setAuthor("jean");
-        setVersion("0.0.0.0.0.1");
-        setLicense("BEER");
-        setSummary("Fake White Beer 2000");
+        set_author("jean");
+        set_version("0.0.0.0.0.1");
+        set_license("BEER");
+        set_summary("Fake White Beer 2000");
     }
 };
 
-class PluginTest : public PluginTester {
+class plugin_test_suite : public plugin_test {
 protected:
-    std::shared_ptr<ServerTest> m_server;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<server_test> server_;
 
 public:
-    PluginTest()
-        : m_server(std::make_shared<ServerTest>())
+    plugin_test_suite()
+        : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
+        , server_(std::make_shared<server_test>())
     {
-        m_irccd.plugins().add(std::make_shared<FakePlugin>());
-        m_irccd.plugins().setFormats("plugin", {
+        irccd_.plugins().add(std::make_shared<fake_plugin>());
+
+        plugin_->set_formats({
             { "usage", "usage=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}" },
             { "info", "info=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{author}:#{license}:#{name}:#{summary}:#{version}" },
             { "not-found", "not-found=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{name}" },
             { "too-long", "too-long=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}" }
         });
-        m_irccd.plugins().load("plugin", PLUGINDIR "/plugin.js");
-        m_plugin = m_irccd.plugins().require("plugin");
+        plugin_->on_load(irccd_);
     }
 };
 
-TEST_F(PluginTest, formatUsage)
+TEST_F(plugin_test_suite, formatUsage)
 {
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", ""});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", ""});
+    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "fail"});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "fail"});
+    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info"});
-    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "info"});
+    ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 }
 
-TEST_F(PluginTest, formatInfo)
+TEST_F(plugin_test_suite, formatInfo)
 {
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info fake"});
+    plugin_->on_command(irccd_, MessageEvent{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", m_server->last());
+    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());
 }
 
-TEST_F(PluginTest, formatNotFound)
+TEST_F(plugin_test_suite, formatNotFound)
 {
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
 
-    ASSERT_EQ("#staff:not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope", m_server->last());
+    ASSERT_EQ("#staff:not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope", server_->last());
 }
 
-TEST_F(PluginTest, formatTooLong)
+TEST_F(plugin_test_suite, formatTooLong)
 {
     for (int i = 0; i < 100; ++i)
-        m_irccd.plugins().add(std::make_shared<Plugin>("plugin-n-{}"_format(i), ""));
+        irccd_.plugins().add(std::make_shared<plugin>("plugin-n-{}"_format(i), ""));
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "list"});
+    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "list"});
 
-    ASSERT_EQ("#staff:too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
+    ASSERT_EQ("#staff:too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 }
 
 int main(int argc, char **argv)