Mercurial > irccd
changeset 500:458e34f16c1f
Irccd: rework native plugins, closes #707
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 02 Oct 2017 13:05:30 +0200 |
parents | 1c96d1fee4b4 |
children | 111e89a0c541 |
files | cmake/function/IrccdDefineTest.cmake libirccd/CMakeLists.txt libirccd/irccd/dynlib.hpp libirccd/irccd/dynlib_plugin.cpp libirccd/irccd/dynlib_plugin.hpp libirccd/irccd/plugin-dynlib.cpp libirccd/irccd/plugin-dynlib.hpp tests/CMakeLists.txt tests/dynlib_plugin/CMakeLists.txt tests/dynlib_plugin/main.cpp tests/dynlib_plugin/test_plugin.cpp |
diffstat | 11 files changed, 781 insertions(+), 751 deletions(-) [+] |
line wrap: on
line diff
--- a/cmake/function/IrccdDefineTest.cmake Mon Oct 02 13:04:17 2017 +0200 +++ b/cmake/function/IrccdDefineTest.cmake Mon Oct 02 13:05:30 2017 +0200 @@ -70,6 +70,7 @@ ${TEST_FLAGS} BOOST_TEST_DYN_LINK CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}" + CMAKE_CURRENT_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}" BINARYDIR="${CMAKE_CURRENT_BINARY_DIR}"
--- a/libirccd/CMakeLists.txt Mon Oct 02 13:04:17 2017 +0200 +++ b/libirccd/CMakeLists.txt Mon Oct 02 13:05:30 2017 +0200 @@ -22,6 +22,7 @@ HEADERS ${libirccd_SOURCE_DIR}/irccd/command.hpp ${libirccd_SOURCE_DIR}/irccd/config.hpp + ${libirccd_SOURCE_DIR}/irccd/dynlib_plugin.hpp ${libirccd_SOURCE_DIR}/irccd/irccd.hpp ${libirccd_SOURCE_DIR}/irccd/plugin.hpp ${libirccd_SOURCE_DIR}/irccd/rule.hpp @@ -34,6 +35,7 @@ SOURCES ${libirccd_SOURCE_DIR}/irccd/command.cpp ${libirccd_SOURCE_DIR}/irccd/config.cpp + ${libirccd_SOURCE_DIR}/irccd/dynlib_plugin.cpp ${libirccd_SOURCE_DIR}/irccd/irccd.cpp ${libirccd_SOURCE_DIR}/irccd/plugin.cpp ${libirccd_SOURCE_DIR}/irccd/rule.cpp @@ -48,7 +50,10 @@ ${libirccd_SOURCE_DIR}/CMakeLists.txt ${HEADERS} ${SOURCES} - LIBRARIES extern-ircclient libcommon + LIBRARIES + $<$<BOOL:${IRCCD_SYSTEM_LINUX}>:dl> + extern-ircclient + libcommon PUBLIC_INCLUDES $<BUILD_INTERFACE:${libirccd_SOURCE_DIR}/irccd> $<BUILD_INTERFACE:${libirccd_SOURCE_DIR}>
--- a/libirccd/irccd/dynlib.hpp Mon Oct 02 13:04:17 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -/* - * dynlib.hpp -- portable shared library loader - * - * 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_DYNLIB_HPP -#define IRCCD_DYNLIB_HPP - -/** - * \file dynlib.hpp - * \brief Portable shared library loader. - * \author David Demelier <markand@malikania.fr> - */ - -/** - * \page Dynlib Dynlib - * \brief Portable shared library loader. - * - * The dynlib module let you open shared libraries dynamically at runtime. - * - * ## Operating system support - * - * | System | Support | Remarks | - * |---------|---------|--------------------| - * | Apple | Ok | | - * | FreeBSD | Ok | | - * | Linux | Ok | Needs -ldl library | - * | Windows | Ok | | - * - * ## How to export symbols - * - * When you want to dynamically load symbols from your shared library, make sure they are in a `extern "C"` block, if - * not they will be [mangled][name-mangling]. - * - * Note, this does not mean that you can't write C++ code, it just mean that you can't use namespaces and function - * overloading. - * - * Example of **plugin.cpp**: - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * extern "C" { - * - * DYNLIB_EXPORT void plugin_load() - * { - * std::cout << "Loading plugin" << std::endl; - * } - * - * DYNLIB_EXPORT void plugin_unload() - * { - * std::cout << "Unloading plugin" << std::endl; - * } - * - * } - * ```` - * - * The \ref DYNLIB_EXPORT macro is necessary on some platforms to be sure that symbol will be visible. Make sure you always - * add it before any function. - * - * To compile, see your compiler documentation or build system. For gcc you can use the following: - * - * ```` - * gcc -std=c++14 -shared plugin.cpp -o plugin.so - * ```` - * - * ## How to load the library - * - * The dynlib module will search for the library in various places, thus you can use relative paths names but be sure - * that the library can be found. Otherwise, just use an absolute path to the file. - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * int main() - * { - * try { - * Dynlib dso("./plugin" DYNLIB_SUFFIX); - * } catch (const std::exception &ex) { - * std::cerr << ex.what() << std::endl; - * } - * - * return 0; - * } - * ```` - * - * ## How to load symbol - * - * The last part is symbol loading, you muse use raw C function pointer and the Dynlib::sym function. - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * using PluginLoad = void (*)(); - * using PluginUnload = void (*)(); - * - * int main() - * { - * try { - * Dynlib dso("./plugin" DYNLIB_SUFFIX); - * - * dso.sym<PluginLoad>("plugin_load")(); - * dso.sym<PluginUnload>("plugin_unload")(); - * } catch (const std::exception &ex) { - * std::cerr << ex.what() << std::endl; - * } - * - * return 0; - * } - * ```` - * - * [name-mangling]: https://en.wikipedia.org/wiki/Name_mangling - */ - -#include <stdexcept> -#include <string> - -#if defined(_WIN32) -# include <windows.h> -#else -# include <dlfcn.h> -#endif - -/** - * \brief Export the symbol. - * - * This is required on some platforms and you should put it before your function signature. - * - * \code{.cpp} - * extern "C" { - * - * DYNLIB_EXPORT void my_function() - * { - * } - * - * } - * \endcode - */ -#if defined(_WIN32) -# define DYNLIB_EXPORT __declspec(dllexport) -#else -# define DYNLIB_EXPORT -#endif - -/** - * \brief Usual suffix for the library. - * - * This macro expands to the suffix convention for this platform. - * - * \code{.cpp} - * Dynlib library("./myplugin" DYNLIB_SUFFIX); - * \endcode - * - * \note Don't use the suffix expanded value shown in Doxygen as it may be wrong. - */ -#if defined(_WIN32) -# define DYNLIB_SUFFIX ".dll" -#elif defined(__APPLE__) -# define DYNLIB_SUFFIX ".dylib" -#else -# define DYNLIB_SUFFIX ".so" -#endif - -namespace irccd { - -/** - * \brief Load a dynamic module. - * - * This class is a portable wrapper to load shared libraries on supported systems. - */ -class Dynlib { -private: -#if defined(_WIN32) - using Handle = HMODULE; - using Sym = FARPROC; -#else - using Handle = void *; - using Sym = void *; -#endif - -public: - /** - * \brief Policy for symbol resolution. - */ - enum Policy { - Immediately, //!< load symbols immediately - Lazy //!< load symbols when needed - }; - -private: - Handle m_handle; - - Dynlib(const Dynlib &) = delete; - Dynlib &operator=(const Dynlib &) = delete; - - Dynlib(Dynlib &&) = delete; - Dynlib &operator=(Dynlib &&) = delete; - -#if defined(_WIN32) - std::string error() - { - LPSTR error = nullptr; - std::string errmsg; - - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&error, 0, NULL); - - if (error) { - errmsg = std::string(error); - LocalFree(error); - } - - return errmsg; - } -#endif - -public: - /** - * Constructor to load a shared module. - * - * \param path the absolute path - * \param policy the policy to load - * \throw std::runtime_error on error - */ - inline Dynlib(const std::string &path, Policy policy = Immediately); - - /** - * Close the library automatically. - */ - inline ~Dynlib(); - - /** - * Get a symbol from the library. - * - * On some platforms the symbol must be manually exported. - * - * \param name the symbol - * \return the symbol - * \throw std::runtime_error on error - * \see DYNLIB_EXPORT - */ - template <typename T> - inline T sym(const std::string &name); -}; - -#if defined(_WIN32) - -/* - * Windows implementation - * ------------------------------------------------------------------ - */ - -Dynlib::Dynlib(const std::string &path, Policy) -{ - m_handle = LoadLibraryA(path.c_str()); - - if (m_handle == nullptr) - throw std::runtime_error(error()); -} - -Dynlib::~Dynlib() -{ - FreeLibrary(m_handle); - m_handle = nullptr; -} - -template <typename T> -T Dynlib::sym(const std::string &name) -{ - Sym sym = GetProcAddress(m_handle, name.c_str()); - - if (sym == nullptr) - throw std::runtime_error(error()); - - return reinterpret_cast<T>(sym); -} - -#else - -/* - * Unix implementation - * ------------------------------------------------------------------ - */ - -Dynlib::Dynlib(const std::string &path, Policy policy) -{ - m_handle = dlopen(path.c_str(), policy == Immediately ? RTLD_NOW : RTLD_LAZY); - - if (m_handle == nullptr) - throw std::runtime_error(dlerror()); -} - -Dynlib::~Dynlib() -{ - dlclose(m_handle); - m_handle = nullptr; -} - -template <typename T> -T Dynlib::sym(const std::string &name) -{ - Sym sym = dlsym(m_handle, name.c_str()); - - if (sym == nullptr) - throw std::runtime_error(dlerror()); - - return reinterpret_cast<T>(sym); -} - -#endif - -#endif // !IRCCD_DYNLIB_HPP - -} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/dynlib_plugin.cpp Mon Oct 02 13:05:30 2017 +0200 @@ -0,0 +1,184 @@ +/* + * dynlib_plugin.cpp -- native plugin implementation + * + * 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 <cctype> +#include <algorithm> + +#include <boost/filesystem.hpp> + +#include "dynlib_plugin.hpp" +#include "util.hpp" + +#if defined(IRCCD_SYSTEM_WINDOWS) +# define DYNLIB_EXTENSION ".dll" +#elif defined(IRCCD_SYSTEM_MAC) +# define DYNLIB_EXTENSION ".dylib" +#else +# define DYNLIB_EXTENSION ".so" +#endif + +namespace irccd { + +dynlib_plugin::dynlib_plugin(std::string name, std::string path) + : plugin(name, path) + , dso_(path) +{ + using load_t = std::unique_ptr<plugin>(std::string, std::string); + + /* + * Function name is determined from the plugin filename where all non + * alphabetic characters are removed. + * + * Example: foo_bar-baz___.so becomes irccd_foobarbaz_load. + */ + auto base = boost::filesystem::path(path).stem().string(); + auto need_remove = [] (auto c) { + return !std::isalnum(c); + }; + + base.erase(std::remove_if(base.begin(), base.end(), need_remove), base.end()); + + auto fname = util::sprintf("irccd_%s_load", base); + auto load = dso_.get<load_t>(fname); + + if (!load) + throw std::runtime_error(util::sprintf("missing plugin entry function '%s'", fname)); + + plugin_ = load(name, path); + + if (!plugin_) + throw std::runtime_error("plugin returned null"); +} + +void dynlib_plugin::on_command(irccd& irccd, const message_event& ev) +{ + plugin_->on_command(irccd, ev); +} + +void dynlib_plugin::on_connect(irccd& irccd, const connect_event& ev) +{ + plugin_->on_connect(irccd, ev); +} + +void dynlib_plugin::on_channel_mode(irccd& irccd, const channel_mode_event& ev) +{ + plugin_->on_channel_mode(irccd, ev); +} + +void dynlib_plugin::on_channel_notice(irccd& irccd, const channel_notice_event& ev) +{ + plugin_->on_channel_notice(irccd, ev); +} + +void dynlib_plugin::on_invite(irccd& irccd, const invite_event& ev) +{ + plugin_->on_invite(irccd, ev); +} + +void dynlib_plugin::on_join(irccd& irccd, const join_event& ev) +{ + plugin_->on_join(irccd, ev); +} + +void dynlib_plugin::on_kick(irccd& irccd, const kick_event& ev) +{ + plugin_->on_kick(irccd, ev); +} + +void dynlib_plugin::on_load(irccd& irccd) +{ + plugin_->on_load(irccd); +} + +void dynlib_plugin::on_message(irccd& irccd, const message_event& ev) +{ + plugin_->on_message(irccd, ev); +} + +void dynlib_plugin::on_me(irccd& irccd, const me_event& ev) +{ + plugin_->on_me(irccd, ev); +} + +void dynlib_plugin::on_mode(irccd& irccd, const mode_event& ev) +{ + plugin_->on_mode(irccd, ev); +} + +void dynlib_plugin::on_names(irccd& irccd, const names_event& ev) +{ + plugin_->on_names(irccd, ev); +} + +void dynlib_plugin::on_nick(irccd& irccd, const nick_event& ev) +{ + plugin_->on_nick(irccd, ev); +} + +void dynlib_plugin::on_notice(irccd& irccd, const notice_event& ev) +{ + plugin_->on_notice(irccd, ev); +} + +void dynlib_plugin::on_part(irccd& irccd, const part_event& ev) +{ + plugin_->on_part(irccd, ev); +} + +void dynlib_plugin::on_query(irccd& irccd, const query_event& ev) +{ + plugin_->on_query(irccd, ev); +} + +void dynlib_plugin::on_query_command(irccd& irccd, const query_event& ev) +{ + plugin_->on_query_command(irccd, ev); +} + +void dynlib_plugin::on_reload(irccd& irccd) +{ + plugin_->on_reload(irccd); +} + +void dynlib_plugin::on_topic(irccd& irccd, const topic_event& ev) +{ + plugin_->on_topic(irccd, ev); +} + +void dynlib_plugin::on_unload(irccd& irccd) +{ + plugin_->on_unload(irccd); +} + +void dynlib_plugin::on_whois(irccd& irccd, const whois_event& ev) +{ + plugin_->on_whois(irccd, ev); +} + +dynlib_plugin_loader::dynlib_plugin_loader(std::vector<std::string> directories) noexcept + : plugin_loader(std::move(directories), { DYNLIB_EXTENSION }) +{ +} + +std::shared_ptr<plugin> dynlib_plugin_loader::open(const std::string& id, + const std::string& path) noexcept +{ + return std::make_unique<dynlib_plugin>(id, path); +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/dynlib_plugin.hpp Mon Oct 02 13:05:30 2017 +0200 @@ -0,0 +1,179 @@ +/* + * dynlib_plugin.hpp -- native plugin implementation + * + * 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_DYNLIB_HPP +#define IRCCD_PLUGIN_DYNLIB_HPP + +/** + * \file plugin-dynlib.hpp + * \brief Native plugin implementation. + */ + +#include <boost/dll.hpp> + +#include "plugin.hpp" + +namespace irccd { + +/** + * \brief Dynlib based plugin. + * \ingroup plugins + */ +class dynlib_plugin : public plugin { +private: + boost::dll::shared_library dso_; + std::unique_ptr<plugin> plugin_; + +public: + /** + * Construct the plugin. + * + * \param name the name + * \param path the fully resolved path (must be absolute) + * \throw std::exception on failures + */ + dynlib_plugin(std::string name, std::string path); + + /** + * \copydoc plugin::on_command + */ + void on_command(irccd& irccd, const message_event& event) override; + + /** + * \copydoc plugin::on_connect + */ + void on_connect(irccd& irccd, const connect_event& event) override; + + /** + * \copydoc plugin::on_channel_mode + */ + void on_channel_mode(irccd& irccd, const channel_mode_event& event) override; + + /** + * \copydoc plugin::on_channel_notice + */ + void on_channel_notice(irccd& irccd, const channel_notice_event& event) override; + + /** + * \copydoc plugin::on_invite + */ + void on_invite(irccd& irccd, const invite_event& event) override; + + /** + * \copydoc plugin::on_join + */ + void on_join(irccd& irccd, const join_event& event) override; + + /** + * \copydoc plugin::on_kick + */ + void on_kick(irccd& irccd, const kick_event& event) override; + + /** + * \copydoc plugin::on_load + */ + void on_load(irccd& irccd) override; + + /** + * \copydoc plugin::on_message + */ + void on_message(irccd& irccd, const message_event& event) override; + + /** + * \copydoc plugin::on_me + */ + void on_me(irccd& irccd, const me_event& event) override; + + /** + * \copydoc plugin::on_mode + */ + void on_mode(irccd& irccd, const mode_event& event) override; + + /** + * \copydoc plugin::on_names + */ + void on_names(irccd& irccd, const names_event& event) override; + + /** + * \copydoc plugin::on_nick + */ + void on_nick(irccd& irccd, const nick_event& event) override; + + /** + * \copydoc plugin::on_notice + */ + void on_notice(irccd& irccd, const notice_event& event) override; + + /** + * \copydoc plugin::on_part + */ + void on_part(irccd& irccd, const part_event& event) override; + + /** + * \copydoc plugin::on_query + */ + void on_query(irccd& irccd, const query_event& event) override; + + /** + * \copydoc plugin::on_query_command + */ + void on_query_command(irccd& irccd, const query_event& event) override; + + /** + * \copydoc plugin::on_reload + */ + void on_reload(irccd& irccd) override; + + /** + * \copydoc plugin::on_topic + */ + void on_topic(irccd& irccd, const topic_event& event) override; + + /** + * \copydoc plugin::on_unload + */ + void on_unload(irccd& irccd) override; + + /** + * \copydoc plugin::on_whois + */ + void on_whois(irccd& irccd, const whois_event& event) override; +}; + +/** + * \brief Implementation for searching native plugins. + */ +class dynlib_plugin_loader : public plugin_loader { +public: + /** + * Constructor. + * + * \param directories optional directories to search, if empty use defaults. + */ + dynlib_plugin_loader(std::vector<std::string> directories = {}) noexcept; + + /** + * \copydoc plugin_loader::find + */ + std::shared_ptr<plugin> open(const std::string& id, + const std::string& path) noexcept override; +}; + +} // !irccd + +#endif // !IRCCD_PLUGIN_DYNLIB_HPP
--- a/libirccd/irccd/plugin-dynlib.cpp Mon Oct 02 13:04:17 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * plugin-dynlib.cpp -- native plugin implementation - * - * 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 "fs.hpp" -#include "logger.hpp" -#include "plugin-dynlib.hpp" - -namespace irccd { - -namespace { - -template <typename Sym> -inline Sym sym(Dynlib &dynlib, const std::string &name) -{ - try { - return dynlib.sym<Sym>(name); - } catch (...) { - return nullptr; - } -} - -template <typename Sym, typename... Args> -inline void call(Sym sym, Args&&... args) -{ - if (sym) - sym(std::forward<Args>(args)...); -} - -} // !namespace - -DynlibPlugin::DynlibPlugin(std::string name, std::string path) - : Plugin(name, path) - , m_dso(std::move(path)) - , m_onCommand(sym<OnCommand>(m_dso, "irccd_onCommand")) - , m_onConnect(sym<OnConnect>(m_dso, "irccd_onConnect")) - , m_onChannelMode(sym<OnChannelMode>(m_dso, "irccd_onChannelMode")) - , m_onChannelNotice(sym<OnChannelNotice>(m_dso, "irccd_onChannelNotice")) - , m_onInvite(sym<OnInvite>(m_dso, "irccd_onInvite")) - , m_onJoin(sym<OnJoin>(m_dso, "irccd_onJoin")) - , m_onKick(sym<OnKick>(m_dso, "irccd_onKick")) - , m_onLoad(sym<OnLoad>(m_dso, "irccd_onLoad")) - , m_onMessage(sym<OnMessage>(m_dso, "irccd_onMessage")) - , m_onMe(sym<OnMe>(m_dso, "irccd_onMe")) - , m_onMode(sym<OnMode>(m_dso, "irccd_onMode")) - , m_onNames(sym<OnNames>(m_dso, "irccd_onNames")) - , m_onNick(sym<OnNick>(m_dso, "irccd_onNick")) - , m_onNotice(sym<OnNotice>(m_dso, "irccd_onNotice")) - , m_onPart(sym<OnPart>(m_dso, "irccd_onPart")) - , m_onQuery(sym<OnQuery>(m_dso, "irccd_onQuery")) - , m_onQueryCommand(sym<OnQueryCommand>(m_dso, "irccd_onQueryCommand")) - , m_onReload(sym<OnReload>(m_dso, "irccd_onReload")) - , m_onTopic(sym<OnTopic>(m_dso, "irccd_onTopic")) - , m_onUnload(sym<OnUnload>(m_dso, "irccd_onUnload")) - , m_onWhois(sym<OnWhois>(m_dso, "irccd_onWhois")) -{ -} - -void DynlibPlugin::onCommand(Irccd &irccd, const MessageEvent &ev) -{ - call(m_onCommand, irccd, ev); -} - -void DynlibPlugin::onConnect(Irccd &irccd, const ConnectEvent &ev) -{ - call(m_onConnect, irccd, ev); -} - -void DynlibPlugin::onChannelMode(Irccd &irccd, const ChannelModeEvent &ev) -{ - call(m_onChannelMode, irccd, ev); -} - -void DynlibPlugin::onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &ev) -{ - call(m_onChannelNotice, irccd, ev); -} - -void DynlibPlugin::onInvite(Irccd &irccd, const InviteEvent &ev) -{ - call(m_onInvite, irccd, ev); -} - -void DynlibPlugin::onJoin(Irccd &irccd, const JoinEvent &ev) -{ - call(m_onJoin, irccd, ev); -} - -void DynlibPlugin::onKick(Irccd &irccd, const KickEvent &ev) -{ - call(m_onKick, irccd, ev); -} - -void DynlibPlugin::onLoad(Irccd &irccd) -{ - call(m_onLoad, irccd, *this); -} - -void DynlibPlugin::onMessage(Irccd &irccd, const MessageEvent &ev) -{ - call(m_onMessage, irccd, ev); -} - -void DynlibPlugin::onMe(Irccd &irccd, const MeEvent &ev) -{ - call(m_onMe, irccd, ev); -} - -void DynlibPlugin::onMode(Irccd &irccd, const ModeEvent &ev) -{ - call(m_onMode, irccd, ev); -} - -void DynlibPlugin::onNames(Irccd &irccd, const NamesEvent &ev) -{ - call(m_onNames, irccd, ev); -} - -void DynlibPlugin::onNick(Irccd &irccd, const NickEvent &ev) -{ - call(m_onNick, irccd, ev); -} - -void DynlibPlugin::onNotice(Irccd &irccd, const NoticeEvent &ev) -{ - call(m_onNotice, irccd, ev); -} - -void DynlibPlugin::onPart(Irccd &irccd, const PartEvent &ev) -{ - call(m_onPart, irccd, ev); -} - -void DynlibPlugin::onQuery(Irccd &irccd, const QueryEvent &ev) -{ - call(m_onQuery, irccd, ev); -} - -void DynlibPlugin::onQueryCommand(Irccd &irccd, const QueryEvent &ev) -{ - call(m_onQueryCommand, irccd, ev); -} - -void DynlibPlugin::onReload(Irccd &irccd) -{ - call(m_onReload, irccd, *this); -} - -void DynlibPlugin::onTopic(Irccd &irccd, const TopicEvent &ev) -{ - call(m_onTopic, irccd, ev); -} - -void DynlibPlugin::onUnload(Irccd &irccd) -{ - call(m_onUnload, irccd, *this); -} - -void DynlibPlugin::onWhois(Irccd &irccd, const WhoisEvent &ev) -{ - call(m_onWhois, irccd, ev); -} - -std::shared_ptr<Plugin> DynlibPluginLoader::open(const std::string &, - const std::string &) noexcept -{ - // TODO: dynlib plugins are unsupported for now. - return nullptr; -} - -std::shared_ptr<Plugin> DynlibPluginLoader::find(const std::string &) noexcept -{ - // TODO: dynlib plugins are unsupported for now. - return nullptr; -} - -} // !irccd
--- a/libirccd/irccd/plugin-dynlib.hpp Mon Oct 02 13:04:17 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * plugin-dynlib.hpp -- native plugin implementation - * - * 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_DYNLIB_HPP -#define IRCCD_PLUGIN_DYNLIB_HPP - -/** - * \file plugin-dynlib.hpp - * \brief Native plugin implementation. - */ - -#include "dynlib.hpp" -#include "plugin.hpp" - -namespace irccd { - -/** - * \brief Dynlib based plugin. - * \ingroup plugins - */ -class DynlibPlugin : public Plugin { -private: - using OnCommand = void (*)(Irccd &, const MessageEvent &); - using OnConnect = void (*)(Irccd &, const ConnectEvent &); - using OnChannelMode = void (*)(Irccd &, const ChannelModeEvent &); - using OnChannelNotice = void (*)(Irccd &, const ChannelNoticeEvent &); - using OnInvite = void (*)(Irccd &, const InviteEvent &); - using OnJoin = void (*)(Irccd &, const JoinEvent &); - using OnKick = void (*)(Irccd &, const KickEvent &); - using OnLoad = void (*)(Irccd &, DynlibPlugin &); - using OnMessage = void (*)(Irccd &, const MessageEvent &); - using OnMe = void (*)(Irccd &, const MeEvent &); - using OnMode = void (*)(Irccd &, const ModeEvent &); - using OnNames = void (*)(Irccd &, const NamesEvent &); - using OnNick = void (*)(Irccd &, const NickEvent &); - using OnNotice = void (*)(Irccd &, const NoticeEvent &); - using OnPart = void (*)(Irccd &, const PartEvent &); - using OnQuery = void (*)(Irccd &, const QueryEvent &); - using OnQueryCommand = void (*)(Irccd &, const QueryEvent &); - using OnReload = void (*)(Irccd &, DynlibPlugin &); - using OnTopic = void (*)(Irccd &, const TopicEvent &); - using OnUnload = void (*)(Irccd &, DynlibPlugin &); - using OnWhois = void (*)(Irccd &, const WhoisEvent &); - - Dynlib m_dso; - OnCommand m_onCommand; - OnConnect m_onConnect; - OnChannelMode m_onChannelMode; - OnChannelNotice m_onChannelNotice; - OnInvite m_onInvite; - OnJoin m_onJoin; - OnKick m_onKick; - OnLoad m_onLoad; - OnMessage m_onMessage; - OnMe m_onMe; - OnMode m_onMode; - OnNames m_onNames; - OnNick m_onNick; - OnNotice m_onNotice; - OnPart m_onPart; - OnQuery m_onQuery; - OnQueryCommand m_onQueryCommand; - OnReload m_onReload; - OnTopic m_onTopic; - OnUnload m_onUnload; - OnWhois m_onWhois; - - // Configuration and formats. - plugin_config m_config; - plugin_formats m_formats; - -public: - /** - * Construct the plugin. - * - * \param name the name - * \param path the fully resolved path (must be absolute) - * \throw std::exception on failures - */ - DynlibPlugin(std::string name, std::string path); - - /** - * \copydoc Plugin::onCommand - */ - IRCCD_EXPORT void onCommand(irccd &irccd, const MessageEvent &event) override; - - /** - * \copydoc Plugin::onConnect - */ - IRCCD_EXPORT void onConnect(irccd &irccd, const ConnectEvent &event) override; - - /** - * \copydoc Plugin::onChannelMode - */ - IRCCD_EXPORT void onChannelMode(irccd &irccd, const ChannelModeEvent &event) override; - - /** - * \copydoc Plugin::onChannelNotice - */ - IRCCD_EXPORT void onChannelNotice(irccd &irccd, const ChannelNoticeEvent &event) override; - - /** - * \copydoc Plugin::onInvite - */ - IRCCD_EXPORT void onInvite(irccd &irccd, const InviteEvent &event) override; - - /** - * \copydoc Plugin::onJoin - */ - IRCCD_EXPORT void onJoin(irccd &irccd, const JoinEvent &event) override; - - /** - * \copydoc Plugin::onKick - */ - IRCCD_EXPORT void onKick(irccd &irccd, const KickEvent &event) override; - - /** - * \copydoc Plugin::onLoad - */ - IRCCD_EXPORT void onLoad(irccd &irccd) override; - - /** - * \copydoc Plugin::onMessage - */ - IRCCD_EXPORT void onMessage(irccd &irccd, const MessageEvent &event) override; - - /** - * \copydoc Plugin::onMe - */ - IRCCD_EXPORT void onMe(irccd &irccd, const MeEvent &event) override; - - /** - * \copydoc Plugin::onMode - */ - IRCCD_EXPORT void onMode(irccd &irccd, const ModeEvent &event) override; - - /** - * \copydoc Plugin::onNames - */ - IRCCD_EXPORT void onNames(irccd &irccd, const NamesEvent &event) override; - - /** - * \copydoc Plugin::onNick - */ - IRCCD_EXPORT void onNick(irccd &irccd, const NickEvent &event) override; - - /** - * \copydoc Plugin::onNotice - */ - IRCCD_EXPORT void onNotice(irccd &irccd, const NoticeEvent &event) override; - - /** - * \copydoc Plugin::onPart - */ - IRCCD_EXPORT void onPart(irccd &irccd, const PartEvent &event) override; - - /** - * \copydoc Plugin::onQuery - */ - IRCCD_EXPORT void onQuery(irccd &irccd, const QueryEvent &event) override; - - /** - * \copydoc Plugin::onQueryCommand - */ - IRCCD_EXPORT void onQueryCommand(irccd &irccd, const QueryEvent &event) override; - - /** - * \copydoc Plugin::onReload - */ - IRCCD_EXPORT void onReload(irccd &irccd) override; - - /** - * \copydoc Plugin::onTopic - */ - IRCCD_EXPORT void onTopic(irccd &irccd, const TopicEvent &event) override; - - /** - * \copydoc Plugin::onUnload - */ - IRCCD_EXPORT void onUnload(irccd &irccd) override; - - /** - * \copydoc Plugin::onWhois - */ - IRCCD_EXPORT void onWhois(irccd &irccd, const WhoisEvent &event) override; -}; - -/** - * \brief Implementation for searching native plugins. - */ -class DynlibPluginLoader : public PluginLoader { -public: - /** - * \copydoc PluginLoader::find - */ - std::shared_ptr<Plugin> open(const std::string &id, - const std::string &path) noexcept override; - - /** - * \copydoc PluginLoader::find - */ - std::shared_ptr<Plugin> find(const std::string &id) noexcept override; -}; - -} // !irccd - -#endif // !IRCCD_PLUGIN_DYNLIB_HPP
--- a/tests/CMakeLists.txt Mon Oct 02 13:04:17 2017 +0200 +++ b/tests/CMakeLists.txt Mon Oct 02 13:05:30 2017 +0200 @@ -49,6 +49,7 @@ add_subdirectory(cmd-server-part) add_subdirectory(cmd-server-reconnect) add_subdirectory(cmd-server-topic) + add_subdirectory(dynlib_plugin) # Misc add_subdirectory(logger)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dynlib_plugin/CMakeLists.txt Mon Oct 02 13:05:30 2017 +0200 @@ -0,0 +1,43 @@ +# +# 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. +# + +find_package(Boost REQUIRED) + +add_library(test-plugin MODULE test_plugin.cpp) +target_link_libraries(test-plugin libirccd Boost::boost) +set_target_properties( + test-plugin + PROPERTIES + PREFIX "" + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +foreach (c ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${c} c) + set_target_properties( + test-plugin + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${c} ${CMAKE_CURRENT_BINARY_DIR} + ) +endforeach () + +irccd_define_test( + NAME dynlib-plugin + SOURCES main.cpp + LIBRARIES libirccd libirccd-test +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dynlib_plugin/main.cpp Mon Oct 02 13:05:30 2017 +0200 @@ -0,0 +1,237 @@ +/* + * main.cpp -- test dynlib_plugin + * + * 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. + */ + +#define BOOST_TEST_MODULE "dynlib_plugin" +#include <boost/test/unit_test.hpp> + +/* + * For this test, we open a plugin written in C++ and pass a journal_server + * class for each of the plugin function. + * + * Then we verify that the appropriate function has been called correctly. + * + * Functions load, unload and reload can not be tested though. + */ + +#include <irccd.hpp> +#include <dynlib_plugin.hpp> +#include <journal_server.hpp> + +namespace irccd { + +class fixture { +protected: + std::shared_ptr<journal_server> server_; + std::shared_ptr<plugin> plugin_; + irccd irccd_; + + inline fixture() + : server_(std::make_shared<journal_server>("test")) + { + plugin_ = dynlib_plugin_loader({CMAKE_CURRENT_BINARY_DIR}).find("test-plugin"); + + if (!plugin_) + throw std::runtime_error("test plugin not found"); + } +}; + +BOOST_FIXTURE_TEST_SUITE(dynlib_plugin_suite, fixture) + +BOOST_AUTO_TEST_CASE(on_command) +{ + plugin_->on_command(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_command"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_connect) +{ + plugin_->on_connect(irccd_, {server_}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_connect"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_channel_mode) +{ + plugin_->on_channel_mode(irccd_, {server_, "", "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_channel_mode"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_channel_notice) +{ + plugin_->on_channel_notice(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_channel_notice"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_invite) +{ + plugin_->on_invite(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_invite"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_join) +{ + plugin_->on_join(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_join"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_kick) +{ + plugin_->on_kick(irccd_, {server_, "", "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_kick"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_message) +{ + plugin_->on_message(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_message"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_me) +{ + plugin_->on_me(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_me"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_mode) +{ + plugin_->on_mode(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_mode"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_names) +{ + plugin_->on_names(irccd_, {server_, "", {}}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_names"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_nick) +{ + plugin_->on_nick(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_nick"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_notice) +{ + plugin_->on_notice(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_notice"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_part) +{ + plugin_->on_part(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_part"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_query) +{ + plugin_->on_query(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_query"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_query_command) +{ + plugin_->on_query_command(irccd_, {server_, "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_query_command"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_query_topic) +{ + plugin_->on_topic(irccd_, {server_, "", "", ""}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_topic"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_CASE(on_whois) +{ + plugin_->on_whois(irccd_, {server_, {"", "", "", "", {}}}); + + BOOST_TEST(server_->cqueue().size() == 1U); + BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); + BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "on_whois"); + BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dynlib_plugin/test_plugin.cpp Mon Oct 02 13:05:30 2017 +0200 @@ -0,0 +1,130 @@ +/* + * test_plugin.cpp -- basic exported plugin test + * + * 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 <boost/dll.hpp> + +#include <plugin.hpp> + +namespace irccd { + +class test_plugin : public plugin { +public: + using plugin::plugin; + + void on_command(irccd&, const message_event& event) override + { + event.server->message("test", "on_command"); + } + + void on_connect(irccd&, const connect_event& event) override + { + event.server->message("test", "on_connect"); + } + + void on_channel_mode(irccd&, const channel_mode_event& event) override + { + event.server->message("test", "on_channel_mode"); + } + + void on_channel_notice(irccd&, const channel_notice_event& event) override + { + event.server->message("test", "on_channel_notice"); + } + + void on_invite(irccd&, const invite_event& event) override + { + event.server->message("test", "on_invite"); + } + + void on_join(irccd&, const join_event& event) override + { + event.server->message("test", "on_join"); + } + + void on_kick(irccd&, const kick_event& event) override + { + event.server->message("test", "on_kick"); + } + + void on_message(irccd&, const message_event& event) override + { + event.server->message("test", "on_message"); + } + + void on_me(irccd&, const me_event& event) override + { + event.server->message("test", "on_me"); + } + + void on_mode(irccd&, const mode_event& event) override + { + event.server->message("test", "on_mode"); + } + + void on_names(irccd&, const names_event& event) override + { + event.server->message("test", "on_names"); + } + + void on_nick(irccd&, const nick_event& event) override + { + event.server->message("test", "on_nick"); + } + + void on_notice(irccd&, const notice_event& event) override + { + event.server->message("test", "on_notice"); + } + + void on_part(irccd&, const part_event& event) override + { + event.server->message("test", "on_part"); + } + + void on_query(irccd&, const query_event& event) override + { + event.server->message("test", "on_query"); + } + + void on_query_command(irccd&, const query_event& event) override + { + event.server->message("test", "on_query_command"); + } + + void on_topic(irccd&, const topic_event& event) override + { + event.server->message("test", "on_topic"); + } + + void on_whois(irccd&, const whois_event& event) override + { + event.server->message("test", "on_whois"); + } +}; + +} // !irccd + +extern "C" { + +BOOST_SYMBOL_EXPORT +std::unique_ptr<irccd::plugin> irccd_testplugin_load(std::string name, std::string path) +{ + return std::make_unique<irccd::test_plugin>(name, path); +} + +} // !C