changeset 794:6e108be0835d

tests: rename libcommon to libirccd-core
author David Demelier <markand@malikania.fr>
date Sun, 11 Nov 2018 10:41:30 +0100
parents 292482f36454
children d42e8415e477
files tests/CMakeLists.txt tests/src/libcommon/CMakeLists.txt tests/src/libcommon/fs-util/CMakeLists.txt tests/src/libcommon/fs-util/main.cpp tests/src/libcommon/stream/CMakeLists.txt tests/src/libcommon/stream/main.cpp tests/src/libcommon/string-util/CMakeLists.txt tests/src/libcommon/string-util/main.cpp tests/src/libirccd-core/CMakeLists.txt tests/src/libirccd-core/fs-util/CMakeLists.txt tests/src/libirccd-core/fs-util/main.cpp tests/src/libirccd-core/stream/CMakeLists.txt tests/src/libirccd-core/stream/main.cpp tests/src/libirccd-core/string-util/CMakeLists.txt tests/src/libirccd-core/string-util/main.cpp
diffstat 15 files changed, 820 insertions(+), 820 deletions(-) [+]
line wrap: on
line diff
--- a/tests/CMakeLists.txt	Sun Nov 11 10:39:10 2018 +0100
+++ b/tests/CMakeLists.txt	Sun Nov 11 10:41:30 2018 +0100
@@ -18,7 +18,7 @@
 
 project(tests)
 
-add_subdirectory(src/libcommon)
+add_subdirectory(src/libirccd-core)
 add_subdirectory(src/libirccd)
 add_subdirectory(src/irccdctl)
 
--- a/tests/src/libcommon/CMakeLists.txt	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-add_subdirectory(fs-util)
-add_subdirectory(stream)
-add_subdirectory(string-util)
--- a/tests/src/libcommon/fs-util/CMakeLists.txt	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-irccd_define_test(
-	NAME fs-util
-	SOURCES main.cpp
-	LIBRARIES libirccd-core
-)
--- a/tests/src/libcommon/fs-util/main.cpp	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * main.cpp -- test fs_util functions
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define BOOST_TEST_MODULE "fs_util"
-#include <boost/test/unit_test.hpp>
-
-#include <irccd/fs_util.hpp>
-#include <irccd/system.hpp>
-
-namespace irccd {
-
-namespace {
-
-/*
- * fs_util::find function (name)
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(fs_find_name)
-
-BOOST_AUTO_TEST_CASE(not_recursive)
-{
-	auto file1 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-1.txt", false);
-	auto file2 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-2.txt", false);
-
-	BOOST_TEST(file1.find("file-1.txt") != std::string::npos);
-	BOOST_TEST(file2.empty());
-}
-
-BOOST_AUTO_TEST_CASE(recursive)
-{
-	auto file1 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-1.txt", true);
-	auto file2 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-2.txt", true);
-
-	BOOST_TEST(file1.find("file-1.txt") != std::string::npos);
-	BOOST_TEST(file2.find("file-2.txt") != std::string::npos);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * fs_util::find function (regex)
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(fs_find_regex)
-
-BOOST_AUTO_TEST_CASE(not_recursive)
-{
-	const std::regex regex("file-[12]\\.txt");
-	const auto file = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", regex, false);
-
-	BOOST_TEST(file.find("file-1.txt") != std::string::npos);
-}
-
-BOOST_AUTO_TEST_CASE(recursive)
-{
-	const std::regex regex("file-[12]\\.txt");
-	const auto file = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root/level-1", regex, true);
-
-	BOOST_TEST(file.find("file-2.txt") != std::string::npos);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !irccd
--- a/tests/src/libcommon/stream/CMakeLists.txt	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-irccd_define_test(
-	NAME stream
-	SOURCES main.cpp
-	LIBRARIES libirccd-core
-)
--- a/tests/src/libcommon/stream/main.cpp	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,262 +0,0 @@
-/*
- * main.cpp -- test network classes
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define BOOST_TEST_MODULE "stream"
-#include <boost/test/unit_test.hpp>
-#include <boost/mpl/list.hpp>
-#include <boost/predef/os.h>
-
-#include <irccd/sysconfig.hpp>
-
-#include <irccd/acceptor.hpp>
-#include <irccd/connector.hpp>
-#include <irccd/stream.hpp>
-
-using boost::asio::io_service;
-using boost::asio::ip::tcp;
-
-#if defined(IRCCD_HAVE_SSL)
-using boost::asio::ssl::context;
-#endif
-
-namespace irccd {
-
-namespace {
-
-class stream_fixture {
-public:
-	io_service service_;
-
-	std::unique_ptr<acceptor> acceptor_;
-	std::unique_ptr<connector> connector_;
-
-	std::shared_ptr<stream> stream1_;
-	std::shared_ptr<stream> stream2_;
-
-	virtual auto create_acceptor() -> std::unique_ptr<acceptor> = 0;
-
-	virtual auto create_connector() -> std::unique_ptr<connector> = 0;
-
-	void init()
-	{
-		acceptor_ = create_acceptor();
-		connector_ = create_connector();
-
-		acceptor_->accept([this] (auto code, auto stream) {
-			if (code)
-				throw std::system_error(code);
-
-			stream1_ = std::move(stream);
-		});
-		connector_->connect([this] (auto code, auto stream) {
-			if (code)
-				throw std::system_error(code);
-
-			stream2_ = std::move(stream);
-		});
-
-		service_.run();
-		service_.reset();
-	}
-};
-
-class ip_stream_fixture : public stream_fixture {
-private:
-	tcp::endpoint endpoint_;
-
-protected:
-	/**
-	 * \copydoc io_fixture::create_acceptor
-	 */
-	auto create_acceptor() -> std::unique_ptr<acceptor> override
-	{
-		tcp::endpoint endpoint(tcp::v4(), 0U);
-		tcp::acceptor acceptor(service_, std::move(endpoint));
-
-		endpoint_ = acceptor.local_endpoint();
-
-		return std::make_unique<ip_acceptor>(service_, std::move(acceptor));
-	}
-
-	/**
-	 * \copydoc io_fixture::create_connector
-	 */
-	auto create_connector() -> std::unique_ptr<connector> override
-	{
-		const auto hostname = "127.0.0.1";
-		const auto port = std::to_string(endpoint_.port());
-
-		return std::make_unique<ip_connector>(service_, hostname, port, true, false);
-	}
-};
-
-#if defined(IRCCD_HAVE_SSL)
-
-class tls_ip_stream_fixture : public stream_fixture {
-private:
-	tcp::endpoint endpoint_;
-
-protected:
-	/**
-	 * \copydoc io_fixture::create_acceptor
-	 */
-	auto create_acceptor() -> std::unique_ptr<acceptor> override
-	{
-		context context(context::tlsv12);
-
-		context.use_certificate_file(TESTS_SOURCE_DIR "/data/test.crt", context::pem);
-		context.use_private_key_file(TESTS_SOURCE_DIR "/data/test.key", context::pem);
-
-		tcp::endpoint endpoint(tcp::v4(), 0U);
-		tcp::acceptor acceptor(service_, std::move(endpoint));
-
-		endpoint_ = acceptor.local_endpoint();
-
-		return std::make_unique<tls_acceptor<ip_acceptor>>(std::move(context), service_, std::move(acceptor));
-	}
-
-	/**
-	 * \copydoc io_fixture::create_connector
-	 */
-	auto create_connector() -> std::unique_ptr<connector> override
-	{
-		context context(context::tlsv12);
-
-		const auto hostname = "127.0.0.1";
-		const auto port = std::to_string(endpoint_.port());
-
-		return std::make_unique<tls_connector<ip_connector>>(std::move(context),
-			service_, hostname, port, true, false);
-	}
-};
-
-#endif // !IRCCD_HAVE_SSL
-
-#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
-
-class local_stream_fixture : public stream_fixture {
-private:
-	const std::string path_{CMAKE_BINARY_DIR "/tmp/stream-test.sock"};
-
-public:
-
-	/**
-	 * \copydoc io_fixture::create_acceptor
-	 */
-	auto create_acceptor() -> std::unique_ptr<acceptor> override
-	{
-		return std::make_unique<local_acceptor>(service_, path_);
-	}
-
-	/**
-	 * \copydoc io_fixture::create_connector
-	 */
-	auto create_connector() -> std::unique_ptr<connector> override
-	{
-		return std::make_unique<local_connector>(service_, path_);
-	}
-};
-
-#if defined(IRCCD_HAVE_SSL)
-
-class tls_local_stream_fixture : public stream_fixture {
-private:
-	const std::string path_{CMAKE_BINARY_DIR "/tmp/stream-test.sock"};
-
-public:
-
-	/**
-	 * \copydoc io_fixture::create_acceptor
-	 */
-	auto create_acceptor() -> std::unique_ptr<acceptor> override
-	{
-		context context(context::tlsv12);
-
-		context.use_certificate_file(TESTS_SOURCE_DIR "/data/test.crt", context::pem);
-		context.use_private_key_file(TESTS_SOURCE_DIR "/data/test.key", context::pem);
-
-		return std::make_unique<tls_acceptor<local_acceptor>>(std::move(context), service_, path_);
-	}
-
-	/**
-	 * \copydoc io_fixture::create_connector
-	 */
-	auto create_connector() -> std::unique_ptr<connector> override
-	{
-		return std::make_unique<tls_connector<local_connector>>(context(context::tlsv12), service_, path_);
-	}
-};
-
-#endif // !IRCCD_HAVE_SSL
-
-#endif // !BOOST_ASIO_HAS_LOCAL_SOCKETS
-
-/**
- * List of fixtures to tests.
- */
-using list = boost::mpl::list<
-	ip_stream_fixture
-#if defined(IRCCD_HAVE_SSL)
-	, tls_ip_stream_fixture
-#endif
-#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
-	, local_stream_fixture
-#	if defined(IRCCD_HAVE_SSL)
-	, tls_local_stream_fixture
-#	endif
-#endif
->;
-
-BOOST_AUTO_TEST_CASE_TEMPLATE(invalid_argument, Test, list)
-{
-	Test fixture;
-
-	const nlohmann::json message{
-		{ "abc", 123 },
-		{ "def", 456 }
-	};
-
-	fixture.init();
-	fixture.stream1_->recv([] (auto code, auto message) {
-		BOOST_TEST(!code);
-		BOOST_TEST(message.is_object());
-		BOOST_TEST(message["abc"].template get<int>() == 123);
-		BOOST_TEST(message["def"].template get<int>() == 456);
-	});
-	fixture.stream2_->send(message, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	fixture.service_.run();
-}
-
-BOOST_AUTO_TEST_CASE_TEMPLATE(connection_reset, Test, list)
-{
-	Test fixture;
-
-	fixture.init();
-	fixture.stream1_->recv([] (auto code, auto message) {
-		BOOST_TEST(code.value() == static_cast<int>(std::errc::connection_reset));
-		BOOST_TEST(message.is_null());
-	});
-	fixture.stream2_ = nullptr;
-	fixture.service_.run();
-}
-
-} // !namespace
-
-} // !irccd
--- a/tests/src/libcommon/string-util/CMakeLists.txt	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-irccd_define_test(
-	NAME string-util
-	SOURCES main.cpp
-	LIBRARIES libirccd-core
-)
--- a/tests/src/libcommon/string-util/main.cpp	Sun Nov 11 10:39:10 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,384 +0,0 @@
-/*
- * main.cpp -- test string_util functions
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define BOOST_TEST_MODULE "string_util"
-#include <boost/test/unit_test.hpp>
-
-#include <irccd/string_util.hpp>
-#include <irccd/system.hpp>
-
-namespace irccd {
-
-namespace {
-
-/*
- * string_util::format function
- * --------------------------------------------------------
- */
-BOOST_AUTO_TEST_SUITE(format)
-
-BOOST_AUTO_TEST_CASE(nothing)
-{
-	std::string expected = "hello world!";
-	std::string result = string_util::format("hello world!");
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(escape)
-{
-	string_util::subst params;
-
-	params.keywords.emplace("target", "hello");
-
-	BOOST_TEST(string_util::format("$@#") == "$@#");
-	BOOST_TEST(string_util::format(" $ @ # ") == " $ @ # ");
-	BOOST_TEST(string_util::format("#") == "#");
-	BOOST_TEST(string_util::format(" # ") == " # ");
-	BOOST_TEST(string_util::format("#@") == "#@");
-	BOOST_TEST(string_util::format("##") == "##");
-	BOOST_TEST(string_util::format("#!") == "#!");
-	BOOST_TEST(string_util::format("##{target}") == "#{target}");
-	BOOST_TEST(string_util::format("@#{target}", params) == "@hello");
-	BOOST_TEST(string_util::format("#{target}#", params) == "hello#");
-	BOOST_REQUIRE_THROW(string_util::format("#{failure"), std::exception);
-}
-
-BOOST_AUTO_TEST_CASE(disable_date)
-{
-	string_util::subst params;
-
-	params.flags &= ~(string_util::subst_flags::date);
-
-	BOOST_TEST(string_util::format("%H:%M", params) == "%H:%M");
-}
-
-BOOST_AUTO_TEST_CASE(disable_keywords)
-{
-	string_util::subst params;
-
-	params.keywords.emplace("target", "hello");
-	params.flags &= ~(string_util::subst_flags::keywords);
-
-	BOOST_TEST(string_util::format("#{target}", params) == "#{target}");
-}
-
-BOOST_AUTO_TEST_CASE(disable_env)
-{
-	string_util::subst params;
-
-	params.flags &= ~(string_util::subst_flags::env);
-
-	BOOST_TEST(string_util::format("${HOME}", params) == "${HOME}");
-}
-
-BOOST_AUTO_TEST_CASE(keyword_simple)
-{
-	string_util::subst params;
-
-	params.keywords.insert({"target", "irccd"});
-
-	std::string expected = "hello irccd!";
-	std::string result = string_util::format("hello #{target}!", params);
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(keyword_multiple)
-{
-	string_util::subst params;
-
-	params.keywords.insert({"target", "irccd"});
-	params.keywords.insert({"source", "nightmare"});
-
-	std::string expected = "hello irccd from nightmare!";
-	std::string result = string_util::format("hello #{target} from #{source}!", params);
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(keyword_adj_twice)
-{
-	string_util::subst params;
-
-	params.keywords.insert({"target", "irccd"});
-
-	std::string expected = "hello irccdirccd!";
-	std::string result = string_util::format("hello #{target}#{target}!", params);
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(keyword_missing)
-{
-	std::string expected = "hello !";
-	std::string result = string_util::format("hello #{target}!");
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(env_simple)
-{
-	std::string home = sys::env("HOME");
-
-	if (!home.empty()) {
-		std::string expected = "my home is " + home;
-		std::string result = string_util::format("my home is ${HOME}");
-
-		BOOST_TEST(expected == result);
-	}
-}
-
-BOOST_AUTO_TEST_CASE(env_missing)
-{
-	std::string expected = "value is ";
-	std::string result = string_util::format("value is ${HOPE_THIS_VAR_NOT_EXIST}");
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * string_util::split function
- * --------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(split)
-
-using list = std::vector<std::string>;
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	list expected { "a", "b" };
-	list result = string_util::split("a;b", ";");
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(cut)
-{
-	list expected { "msg", "#staff", "foo bar baz" };
-	list result = string_util::split("msg;#staff;foo bar baz", ";", 3);
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * string_util::strip function
- * --------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(strip)
-
-BOOST_AUTO_TEST_CASE(left)
-{
-	std::string value = "   123";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "123");
-}
-
-BOOST_AUTO_TEST_CASE(right)
-{
-	std::string value = "123   ";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "123");
-}
-
-BOOST_AUTO_TEST_CASE(both)
-{
-	std::string value = "   123   ";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "123");
-}
-
-BOOST_AUTO_TEST_CASE(none)
-{
-	std::string value = "without";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "without");
-}
-
-BOOST_AUTO_TEST_CASE(between_empty)
-{
-	std::string value = "one list";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "one list");
-}
-
-BOOST_AUTO_TEST_CASE(between_left)
-{
-	std::string value = "  space at left";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "space at left");
-}
-
-BOOST_AUTO_TEST_CASE(between_right)
-{
-	std::string value = "space at right  ";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "space at right");
-}
-
-BOOST_AUTO_TEST_CASE(between_both)
-{
-	std::string value = "  space at both  ";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "space at both");
-}
-
-BOOST_AUTO_TEST_CASE(empty)
-{
-	std::string value = "    ";
-	std::string result = string_util::strip(value);
-
-	BOOST_TEST(result == "");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * string_util::join function
- * --------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(join)
-
-BOOST_AUTO_TEST_CASE(empty)
-{
-	std::string expected = "";
-	std::string result = string_util::join<int>({});
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(one)
-{
-	std::string expected = "1";
-	std::string result = string_util::join({1});
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(two)
-{
-	std::string expected = "1:2";
-	std::string result = string_util::join({1, 2});
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(delimiter_string)
-{
-	std::string expected = "1;;2;;3";
-	std::string result = string_util::join({1, 2, 3}, ";;");
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_CASE(delimiter_char)
-{
-	std::string expected = "1@2@3@4";
-	std::string result = string_util::join({1, 2, 3, 4}, '@');
-
-	BOOST_TEST(expected == result);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * string_util::is_identifier function
- * --------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(is_identifier_valid)
-
-BOOST_AUTO_TEST_CASE(correct)
-{
-	BOOST_TEST(string_util::is_identifier("localhost"));
-	BOOST_TEST(string_util::is_identifier("localhost2"));
-	BOOST_TEST(string_util::is_identifier("localhost2-4_"));
-}
-
-BOOST_AUTO_TEST_CASE(incorrect)
-{
-	BOOST_TEST(!string_util::is_identifier(""));
-	BOOST_TEST(!string_util::is_identifier("localhost with spaces"));
-	BOOST_TEST(!string_util::is_identifier("localhost*"));
-	BOOST_TEST(!string_util::is_identifier("&&"));
-	BOOST_TEST(!string_util::is_identifier("@'"));
-	BOOST_TEST(!string_util::is_identifier("##"));
-	BOOST_TEST(!string_util::is_identifier("===++"));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * string_util::is_boolean function
- * --------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(is_boolean)
-
-BOOST_AUTO_TEST_CASE(correct)
-{
-	// true
-	BOOST_TEST(string_util::is_boolean("true"));
-	BOOST_TEST(string_util::is_boolean("True"));
-	BOOST_TEST(string_util::is_boolean("TRUE"));
-	BOOST_TEST(string_util::is_boolean("TruE"));
-
-	// yes
-	BOOST_TEST(string_util::is_boolean("yes"));
-	BOOST_TEST(string_util::is_boolean("Yes"));
-	BOOST_TEST(string_util::is_boolean("YES"));
-	BOOST_TEST(string_util::is_boolean("YeS"));
-
-	// on
-	BOOST_TEST(string_util::is_boolean("on"));
-	BOOST_TEST(string_util::is_boolean("On"));
-	BOOST_TEST(string_util::is_boolean("oN"));
-	BOOST_TEST(string_util::is_boolean("ON"));
-
-	// 1
-	BOOST_TEST(string_util::is_boolean("1"));
-}
-
-BOOST_AUTO_TEST_CASE(incorrect)
-{
-	BOOST_TEST(!string_util::is_boolean("false"));
-	BOOST_TEST(!string_util::is_boolean("lol"));
-	BOOST_TEST(!string_util::is_boolean(""));
-	BOOST_TEST(!string_util::is_boolean("0"));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/CMakeLists.txt	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,21 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+add_subdirectory(fs-util)
+add_subdirectory(stream)
+add_subdirectory(string-util)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/fs-util/CMakeLists.txt	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME fs-util
+	SOURCES main.cpp
+	LIBRARIES libirccd-core
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/fs-util/main.cpp	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,83 @@
+/*
+ * main.cpp -- test fs_util functions
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "fs_util"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/fs_util.hpp>
+#include <irccd/system.hpp>
+
+namespace irccd {
+
+namespace {
+
+/*
+ * fs_util::find function (name)
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(fs_find_name)
+
+BOOST_AUTO_TEST_CASE(not_recursive)
+{
+	auto file1 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-1.txt", false);
+	auto file2 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-2.txt", false);
+
+	BOOST_TEST(file1.find("file-1.txt") != std::string::npos);
+	BOOST_TEST(file2.empty());
+}
+
+BOOST_AUTO_TEST_CASE(recursive)
+{
+	auto file1 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-1.txt", true);
+	auto file2 = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", "file-2.txt", true);
+
+	BOOST_TEST(file1.find("file-1.txt") != std::string::npos);
+	BOOST_TEST(file2.find("file-2.txt") != std::string::npos);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * fs_util::find function (regex)
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(fs_find_regex)
+
+BOOST_AUTO_TEST_CASE(not_recursive)
+{
+	const std::regex regex("file-[12]\\.txt");
+	const auto file = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root", regex, false);
+
+	BOOST_TEST(file.find("file-1.txt") != std::string::npos);
+}
+
+BOOST_AUTO_TEST_CASE(recursive)
+{
+	const std::regex regex("file-[12]\\.txt");
+	const auto file = fs_util::find(CMAKE_SOURCE_DIR "/tests/data/root/level-1", regex, true);
+
+	BOOST_TEST(file.find("file-2.txt") != std::string::npos);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/stream/CMakeLists.txt	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME stream
+	SOURCES main.cpp
+	LIBRARIES libirccd-core
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/stream/main.cpp	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,262 @@
+/*
+ * main.cpp -- test network classes
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "stream"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/predef/os.h>
+
+#include <irccd/sysconfig.hpp>
+
+#include <irccd/acceptor.hpp>
+#include <irccd/connector.hpp>
+#include <irccd/stream.hpp>
+
+using boost::asio::io_service;
+using boost::asio::ip::tcp;
+
+#if defined(IRCCD_HAVE_SSL)
+using boost::asio::ssl::context;
+#endif
+
+namespace irccd {
+
+namespace {
+
+class stream_fixture {
+public:
+	io_service service_;
+
+	std::unique_ptr<acceptor> acceptor_;
+	std::unique_ptr<connector> connector_;
+
+	std::shared_ptr<stream> stream1_;
+	std::shared_ptr<stream> stream2_;
+
+	virtual auto create_acceptor() -> std::unique_ptr<acceptor> = 0;
+
+	virtual auto create_connector() -> std::unique_ptr<connector> = 0;
+
+	void init()
+	{
+		acceptor_ = create_acceptor();
+		connector_ = create_connector();
+
+		acceptor_->accept([this] (auto code, auto stream) {
+			if (code)
+				throw std::system_error(code);
+
+			stream1_ = std::move(stream);
+		});
+		connector_->connect([this] (auto code, auto stream) {
+			if (code)
+				throw std::system_error(code);
+
+			stream2_ = std::move(stream);
+		});
+
+		service_.run();
+		service_.reset();
+	}
+};
+
+class ip_stream_fixture : public stream_fixture {
+private:
+	tcp::endpoint endpoint_;
+
+protected:
+	/**
+	 * \copydoc io_fixture::create_acceptor
+	 */
+	auto create_acceptor() -> std::unique_ptr<acceptor> override
+	{
+		tcp::endpoint endpoint(tcp::v4(), 0U);
+		tcp::acceptor acceptor(service_, std::move(endpoint));
+
+		endpoint_ = acceptor.local_endpoint();
+
+		return std::make_unique<ip_acceptor>(service_, std::move(acceptor));
+	}
+
+	/**
+	 * \copydoc io_fixture::create_connector
+	 */
+	auto create_connector() -> std::unique_ptr<connector> override
+	{
+		const auto hostname = "127.0.0.1";
+		const auto port = std::to_string(endpoint_.port());
+
+		return std::make_unique<ip_connector>(service_, hostname, port, true, false);
+	}
+};
+
+#if defined(IRCCD_HAVE_SSL)
+
+class tls_ip_stream_fixture : public stream_fixture {
+private:
+	tcp::endpoint endpoint_;
+
+protected:
+	/**
+	 * \copydoc io_fixture::create_acceptor
+	 */
+	auto create_acceptor() -> std::unique_ptr<acceptor> override
+	{
+		context context(context::tlsv12);
+
+		context.use_certificate_file(TESTS_SOURCE_DIR "/data/test.crt", context::pem);
+		context.use_private_key_file(TESTS_SOURCE_DIR "/data/test.key", context::pem);
+
+		tcp::endpoint endpoint(tcp::v4(), 0U);
+		tcp::acceptor acceptor(service_, std::move(endpoint));
+
+		endpoint_ = acceptor.local_endpoint();
+
+		return std::make_unique<tls_acceptor<ip_acceptor>>(std::move(context), service_, std::move(acceptor));
+	}
+
+	/**
+	 * \copydoc io_fixture::create_connector
+	 */
+	auto create_connector() -> std::unique_ptr<connector> override
+	{
+		context context(context::tlsv12);
+
+		const auto hostname = "127.0.0.1";
+		const auto port = std::to_string(endpoint_.port());
+
+		return std::make_unique<tls_connector<ip_connector>>(std::move(context),
+			service_, hostname, port, true, false);
+	}
+};
+
+#endif // !IRCCD_HAVE_SSL
+
+#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
+
+class local_stream_fixture : public stream_fixture {
+private:
+	const std::string path_{CMAKE_BINARY_DIR "/tmp/stream-test.sock"};
+
+public:
+
+	/**
+	 * \copydoc io_fixture::create_acceptor
+	 */
+	auto create_acceptor() -> std::unique_ptr<acceptor> override
+	{
+		return std::make_unique<local_acceptor>(service_, path_);
+	}
+
+	/**
+	 * \copydoc io_fixture::create_connector
+	 */
+	auto create_connector() -> std::unique_ptr<connector> override
+	{
+		return std::make_unique<local_connector>(service_, path_);
+	}
+};
+
+#if defined(IRCCD_HAVE_SSL)
+
+class tls_local_stream_fixture : public stream_fixture {
+private:
+	const std::string path_{CMAKE_BINARY_DIR "/tmp/stream-test.sock"};
+
+public:
+
+	/**
+	 * \copydoc io_fixture::create_acceptor
+	 */
+	auto create_acceptor() -> std::unique_ptr<acceptor> override
+	{
+		context context(context::tlsv12);
+
+		context.use_certificate_file(TESTS_SOURCE_DIR "/data/test.crt", context::pem);
+		context.use_private_key_file(TESTS_SOURCE_DIR "/data/test.key", context::pem);
+
+		return std::make_unique<tls_acceptor<local_acceptor>>(std::move(context), service_, path_);
+	}
+
+	/**
+	 * \copydoc io_fixture::create_connector
+	 */
+	auto create_connector() -> std::unique_ptr<connector> override
+	{
+		return std::make_unique<tls_connector<local_connector>>(context(context::tlsv12), service_, path_);
+	}
+};
+
+#endif // !IRCCD_HAVE_SSL
+
+#endif // !BOOST_ASIO_HAS_LOCAL_SOCKETS
+
+/**
+ * List of fixtures to tests.
+ */
+using list = boost::mpl::list<
+	ip_stream_fixture
+#if defined(IRCCD_HAVE_SSL)
+	, tls_ip_stream_fixture
+#endif
+#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
+	, local_stream_fixture
+#	if defined(IRCCD_HAVE_SSL)
+	, tls_local_stream_fixture
+#	endif
+#endif
+>;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(invalid_argument, Test, list)
+{
+	Test fixture;
+
+	const nlohmann::json message{
+		{ "abc", 123 },
+		{ "def", 456 }
+	};
+
+	fixture.init();
+	fixture.stream1_->recv([] (auto code, auto message) {
+		BOOST_TEST(!code);
+		BOOST_TEST(message.is_object());
+		BOOST_TEST(message["abc"].template get<int>() == 123);
+		BOOST_TEST(message["def"].template get<int>() == 456);
+	});
+	fixture.stream2_->send(message, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	fixture.service_.run();
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(connection_reset, Test, list)
+{
+	Test fixture;
+
+	fixture.init();
+	fixture.stream1_->recv([] (auto code, auto message) {
+		BOOST_TEST(code.value() == static_cast<int>(std::errc::connection_reset));
+		BOOST_TEST(message.is_null());
+	});
+	fixture.stream2_ = nullptr;
+	fixture.service_.run();
+}
+
+} // !namespace
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/string-util/CMakeLists.txt	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME string-util
+	SOURCES main.cpp
+	LIBRARIES libirccd-core
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-core/string-util/main.cpp	Sun Nov 11 10:41:30 2018 +0100
@@ -0,0 +1,384 @@
+/*
+ * main.cpp -- test string_util functions
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "string_util"
+#include <boost/test/unit_test.hpp>
+
+#include <irccd/string_util.hpp>
+#include <irccd/system.hpp>
+
+namespace irccd {
+
+namespace {
+
+/*
+ * string_util::format function
+ * --------------------------------------------------------
+ */
+BOOST_AUTO_TEST_SUITE(format)
+
+BOOST_AUTO_TEST_CASE(nothing)
+{
+	std::string expected = "hello world!";
+	std::string result = string_util::format("hello world!");
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(escape)
+{
+	string_util::subst params;
+
+	params.keywords.emplace("target", "hello");
+
+	BOOST_TEST(string_util::format("$@#") == "$@#");
+	BOOST_TEST(string_util::format(" $ @ # ") == " $ @ # ");
+	BOOST_TEST(string_util::format("#") == "#");
+	BOOST_TEST(string_util::format(" # ") == " # ");
+	BOOST_TEST(string_util::format("#@") == "#@");
+	BOOST_TEST(string_util::format("##") == "##");
+	BOOST_TEST(string_util::format("#!") == "#!");
+	BOOST_TEST(string_util::format("##{target}") == "#{target}");
+	BOOST_TEST(string_util::format("@#{target}", params) == "@hello");
+	BOOST_TEST(string_util::format("#{target}#", params) == "hello#");
+	BOOST_REQUIRE_THROW(string_util::format("#{failure"), std::exception);
+}
+
+BOOST_AUTO_TEST_CASE(disable_date)
+{
+	string_util::subst params;
+
+	params.flags &= ~(string_util::subst_flags::date);
+
+	BOOST_TEST(string_util::format("%H:%M", params) == "%H:%M");
+}
+
+BOOST_AUTO_TEST_CASE(disable_keywords)
+{
+	string_util::subst params;
+
+	params.keywords.emplace("target", "hello");
+	params.flags &= ~(string_util::subst_flags::keywords);
+
+	BOOST_TEST(string_util::format("#{target}", params) == "#{target}");
+}
+
+BOOST_AUTO_TEST_CASE(disable_env)
+{
+	string_util::subst params;
+
+	params.flags &= ~(string_util::subst_flags::env);
+
+	BOOST_TEST(string_util::format("${HOME}", params) == "${HOME}");
+}
+
+BOOST_AUTO_TEST_CASE(keyword_simple)
+{
+	string_util::subst params;
+
+	params.keywords.insert({"target", "irccd"});
+
+	std::string expected = "hello irccd!";
+	std::string result = string_util::format("hello #{target}!", params);
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(keyword_multiple)
+{
+	string_util::subst params;
+
+	params.keywords.insert({"target", "irccd"});
+	params.keywords.insert({"source", "nightmare"});
+
+	std::string expected = "hello irccd from nightmare!";
+	std::string result = string_util::format("hello #{target} from #{source}!", params);
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(keyword_adj_twice)
+{
+	string_util::subst params;
+
+	params.keywords.insert({"target", "irccd"});
+
+	std::string expected = "hello irccdirccd!";
+	std::string result = string_util::format("hello #{target}#{target}!", params);
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(keyword_missing)
+{
+	std::string expected = "hello !";
+	std::string result = string_util::format("hello #{target}!");
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(env_simple)
+{
+	std::string home = sys::env("HOME");
+
+	if (!home.empty()) {
+		std::string expected = "my home is " + home;
+		std::string result = string_util::format("my home is ${HOME}");
+
+		BOOST_TEST(expected == result);
+	}
+}
+
+BOOST_AUTO_TEST_CASE(env_missing)
+{
+	std::string expected = "value is ";
+	std::string result = string_util::format("value is ${HOPE_THIS_VAR_NOT_EXIST}");
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * string_util::split function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(split)
+
+using list = std::vector<std::string>;
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	list expected { "a", "b" };
+	list result = string_util::split("a;b", ";");
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(cut)
+{
+	list expected { "msg", "#staff", "foo bar baz" };
+	list result = string_util::split("msg;#staff;foo bar baz", ";", 3);
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * string_util::strip function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(strip)
+
+BOOST_AUTO_TEST_CASE(left)
+{
+	std::string value = "   123";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "123");
+}
+
+BOOST_AUTO_TEST_CASE(right)
+{
+	std::string value = "123   ";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "123");
+}
+
+BOOST_AUTO_TEST_CASE(both)
+{
+	std::string value = "   123   ";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "123");
+}
+
+BOOST_AUTO_TEST_CASE(none)
+{
+	std::string value = "without";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "without");
+}
+
+BOOST_AUTO_TEST_CASE(between_empty)
+{
+	std::string value = "one list";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "one list");
+}
+
+BOOST_AUTO_TEST_CASE(between_left)
+{
+	std::string value = "  space at left";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "space at left");
+}
+
+BOOST_AUTO_TEST_CASE(between_right)
+{
+	std::string value = "space at right  ";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "space at right");
+}
+
+BOOST_AUTO_TEST_CASE(between_both)
+{
+	std::string value = "  space at both  ";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "space at both");
+}
+
+BOOST_AUTO_TEST_CASE(empty)
+{
+	std::string value = "    ";
+	std::string result = string_util::strip(value);
+
+	BOOST_TEST(result == "");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * string_util::join function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(join)
+
+BOOST_AUTO_TEST_CASE(empty)
+{
+	std::string expected = "";
+	std::string result = string_util::join<int>({});
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(one)
+{
+	std::string expected = "1";
+	std::string result = string_util::join({1});
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(two)
+{
+	std::string expected = "1:2";
+	std::string result = string_util::join({1, 2});
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(delimiter_string)
+{
+	std::string expected = "1;;2;;3";
+	std::string result = string_util::join({1, 2, 3}, ";;");
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_CASE(delimiter_char)
+{
+	std::string expected = "1@2@3@4";
+	std::string result = string_util::join({1, 2, 3, 4}, '@');
+
+	BOOST_TEST(expected == result);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * string_util::is_identifier function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(is_identifier_valid)
+
+BOOST_AUTO_TEST_CASE(correct)
+{
+	BOOST_TEST(string_util::is_identifier("localhost"));
+	BOOST_TEST(string_util::is_identifier("localhost2"));
+	BOOST_TEST(string_util::is_identifier("localhost2-4_"));
+}
+
+BOOST_AUTO_TEST_CASE(incorrect)
+{
+	BOOST_TEST(!string_util::is_identifier(""));
+	BOOST_TEST(!string_util::is_identifier("localhost with spaces"));
+	BOOST_TEST(!string_util::is_identifier("localhost*"));
+	BOOST_TEST(!string_util::is_identifier("&&"));
+	BOOST_TEST(!string_util::is_identifier("@'"));
+	BOOST_TEST(!string_util::is_identifier("##"));
+	BOOST_TEST(!string_util::is_identifier("===++"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * string_util::is_boolean function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(is_boolean)
+
+BOOST_AUTO_TEST_CASE(correct)
+{
+	// true
+	BOOST_TEST(string_util::is_boolean("true"));
+	BOOST_TEST(string_util::is_boolean("True"));
+	BOOST_TEST(string_util::is_boolean("TRUE"));
+	BOOST_TEST(string_util::is_boolean("TruE"));
+
+	// yes
+	BOOST_TEST(string_util::is_boolean("yes"));
+	BOOST_TEST(string_util::is_boolean("Yes"));
+	BOOST_TEST(string_util::is_boolean("YES"));
+	BOOST_TEST(string_util::is_boolean("YeS"));
+
+	// on
+	BOOST_TEST(string_util::is_boolean("on"));
+	BOOST_TEST(string_util::is_boolean("On"));
+	BOOST_TEST(string_util::is_boolean("oN"));
+	BOOST_TEST(string_util::is_boolean("ON"));
+
+	// 1
+	BOOST_TEST(string_util::is_boolean("1"));
+}
+
+BOOST_AUTO_TEST_CASE(incorrect)
+{
+	BOOST_TEST(!string_util::is_boolean("false"));
+	BOOST_TEST(!string_util::is_boolean("lol"));
+	BOOST_TEST(!string_util::is_boolean(""));
+	BOOST_TEST(!string_util::is_boolean("0"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd