changeset 193:209bdaa13a49

Tests: rename directories to match targets
author David Demelier <markand@malikania.fr>
date Sat, 27 Oct 2018 07:16:28 +0200
parents 74afc5a41c83
children 61dd98874d82
files CMakeLists.txt client/CMakeLists.txt client/main.cpp client/resources/fonts/DejaVuSans-Bold.ttf client/resources/fonts/DejaVuSans-BoldOblique.ttf client/resources/fonts/DejaVuSans-ExtraLight.ttf client/resources/fonts/DejaVuSans-Oblique.ttf client/resources/fonts/DejaVuSans.ttf client/resources/images/mokodemo.png mlk-client/CMakeLists.txt mlk-client/main.cpp mlk-client/resources/fonts/DejaVuSans-Bold.ttf mlk-client/resources/fonts/DejaVuSans-BoldOblique.ttf mlk-client/resources/fonts/DejaVuSans-ExtraLight.ttf mlk-client/resources/fonts/DejaVuSans-Oblique.ttf mlk-client/resources/fonts/DejaVuSans.ttf mlk-server/CMakeLists.txt mlk-server/main.cpp server/CMakeLists.txt server/main.cpp tests/CMakeLists.txt tests/libclient/CMakeLists.txt tests/libclient/color/CMakeLists.txt tests/libclient/color/main.cpp tests/libclient/js-color/CMakeLists.txt tests/libclient/js-color/main.cpp tests/libcommon/CMakeLists.txt tests/libcommon/js-elapsed-timer/CMakeLists.txt tests/libcommon/js-elapsed-timer/main.cpp tests/libcommon/js-line/CMakeLists.txt tests/libcommon/js-line/main.cpp tests/libcommon/js-point/CMakeLists.txt tests/libcommon/js-point/main.cpp tests/libcommon/js-rectangle/CMakeLists.txt tests/libcommon/js-rectangle/main.cpp tests/libcommon/js-size/CMakeLists.txt tests/libcommon/js-size/main.cpp tests/libcommon/line/CMakeLists.txt tests/libcommon/line/main.cpp tests/libcommon/point/CMakeLists.txt tests/libcommon/point/main.cpp tests/libcommon/rectangle/CMakeLists.txt tests/libcommon/rectangle/main.cpp tests/libcommon/size/CMakeLists.txt tests/libcommon/size/main.cpp tests/libcommon/socket/CMakeLists.txt tests/libcommon/socket/main.cpp tests/libcommon/util/CMakeLists.txt tests/libcommon/util/main.cpp tests/libmlk-client/CMakeLists.txt tests/libmlk-client/color/CMakeLists.txt tests/libmlk-client/color/main.cpp tests/libmlk-client/js-color/CMakeLists.txt tests/libmlk-client/js-color/main.cpp tests/libmlk/CMakeLists.txt tests/libmlk/js-elapsed-timer/CMakeLists.txt tests/libmlk/js-elapsed-timer/main.cpp tests/libmlk/js-line/CMakeLists.txt tests/libmlk/js-line/main.cpp tests/libmlk/js-point/CMakeLists.txt tests/libmlk/js-point/main.cpp tests/libmlk/js-rectangle/CMakeLists.txt tests/libmlk/js-rectangle/main.cpp tests/libmlk/js-size/CMakeLists.txt tests/libmlk/js-size/main.cpp tests/libmlk/line/CMakeLists.txt tests/libmlk/line/main.cpp tests/libmlk/point/CMakeLists.txt tests/libmlk/point/main.cpp tests/libmlk/rectangle/CMakeLists.txt tests/libmlk/rectangle/main.cpp tests/libmlk/size/CMakeLists.txt tests/libmlk/size/main.cpp tests/libmlk/socket/CMakeLists.txt tests/libmlk/socket/main.cpp tests/libmlk/util/CMakeLists.txt tests/libmlk/util/main.cpp
diffstat 77 files changed, 3890 insertions(+), 3890 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ b/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -54,8 +54,8 @@
 add_subdirectory(libmlk-db)
 add_subdirectory(libmlk-js)
 add_subdirectory(libmlk-server)
-add_subdirectory(client)
-add_subdirectory(server)
+add_subdirectory(mlk-client)
+add_subdirectory(mlk-server)
 
 # Unit test libs.
 add_subdirectory(libmlk-js-test)
--- a/client/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-project(mlk-client)
-
-set(
-	SOURCES
-	${mlk-client_SOURCE_DIR}/main.cpp
-)
-
-find_package(Threads REQUIRED)
-
-malikania_define_executable(
-	TARGET mlk-client
-	SOURCES ${SOURCES}
-	LIBRARIES
-		Threads::Threads
-		libmlk-client-js
-)
--- a/client/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * main.cpp -- main client file
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-#include <chrono>
-#include <thread>
-
-#include <malikania/client/color.hpp>
-#include <malikania/client/button.hpp>
-#include <malikania/client/window.hpp>
-
-using namespace mlk;
-using namespace mlk::client;
-
-int main()
-{
-	window w;
-
-	//SDL_RenderSetScale(w.get_renderer(), 2, 2);
-	button b("click me");
-
-	b.set_position({50, 50});
-	b.set_size({100, 20});
-
-	w.set_drawing_color(color::from_name("white"));
-	w.clear();
-	b.draw(w);
-	w.present();
-	std::this_thread::sleep_for(std::chrono::seconds(10));
-
-
-#if 0
-	boost::asio::io_service service;
-
-	mlk::client::connection conn(service);
-	mlk::client::window w;
-	mlk::client::client clt(service, conn, w);
-
-	clt.set_state(std::make_unique<mlk::client::login_state>(clt));
-	clt.run();
-#endif
-}
Binary file client/resources/fonts/DejaVuSans-Bold.ttf has changed
Binary file client/resources/fonts/DejaVuSans-BoldOblique.ttf has changed
Binary file client/resources/fonts/DejaVuSans-ExtraLight.ttf has changed
Binary file client/resources/fonts/DejaVuSans-Oblique.ttf has changed
Binary file client/resources/fonts/DejaVuSans.ttf has changed
Binary file client/resources/images/mokodemo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mlk-client/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,34 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+project(mlk-client)
+
+set(
+	SOURCES
+	${mlk-client_SOURCE_DIR}/main.cpp
+)
+
+find_package(Threads REQUIRED)
+
+malikania_define_executable(
+	TARGET mlk-client
+	SOURCES ${SOURCES}
+	LIBRARIES
+		Threads::Threads
+		libmlk-client-js
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mlk-client/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * main.cpp -- main client file
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+
+#include <malikania/client/color.hpp>
+#include <malikania/client/button.hpp>
+#include <malikania/client/window.hpp>
+
+using namespace mlk;
+using namespace mlk::client;
+
+int main()
+{
+	window w;
+
+	//SDL_RenderSetScale(w.get_renderer(), 2, 2);
+	button b("click me");
+
+	b.set_position({50, 50});
+	b.set_size({100, 20});
+
+	w.set_drawing_color(color::from_name("white"));
+	w.clear();
+	b.draw(w);
+	w.present();
+	std::this_thread::sleep_for(std::chrono::seconds(10));
+
+
+#if 0
+	boost::asio::io_service service;
+
+	mlk::client::connection conn(service);
+	mlk::client::window w;
+	mlk::client::client clt(service, conn, w);
+
+	clt.set_state(std::make_unique<mlk::client::login_state>(clt));
+	clt.run();
+#endif
+}
Binary file mlk-client/resources/fonts/DejaVuSans-Bold.ttf has changed
Binary file mlk-client/resources/fonts/DejaVuSans-BoldOblique.ttf has changed
Binary file mlk-client/resources/fonts/DejaVuSans-ExtraLight.ttf has changed
Binary file mlk-client/resources/fonts/DejaVuSans-Oblique.ttf has changed
Binary file mlk-client/resources/fonts/DejaVuSans.ttf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mlk-server/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,27 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+project(mlk-server)
+
+malikania_define_executable(
+	TARGET mlk-server
+	SOURCES ${mlk-server_SOURCE_DIR}/main.cpp
+	LIBRARIES
+		libmlk-db
+		libmlk-server
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mlk-server/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * main.cpp -- main server executable file
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include <malikania/db/database.hpp>
+#include <malikania/db/account.hpp>
+
+#include <malikania/server/server.hpp>
+
+using namespace mlk;
+
+int main()
+{
+	boost::asio::io_context ctx;
+
+	try {
+		server::settings settings;
+
+		settings.key = "/home/markand/server.key";
+		settings.certificate = "/home/markand/server.crt";
+		settings.port = 3320;
+		
+		server::server sv(ctx, settings);
+
+		db::open("", "", "markand", "malikaniadb", "");
+		db::init();
+		
+		ctx.run();
+	} catch (const std::exception& ex) {
+		std::cerr << "abort: " << ex.what() << std::endl;
+	}
+}
--- a/server/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-project(mlk-server)
-
-malikania_define_executable(
-	TARGET mlk-server
-	SOURCES ${mlk-server_SOURCE_DIR}/main.cpp
-	LIBRARIES
-		libmlk-db
-		libmlk-server
-)
--- a/server/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * main.cpp -- main server executable file
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include <malikania/db/database.hpp>
-#include <malikania/db/account.hpp>
-
-#include <malikania/server/server.hpp>
-
-using namespace mlk;
-
-int main()
-{
-	boost::asio::io_context ctx;
-
-	try {
-		server::settings settings;
-
-		settings.key = "/home/markand/server.key";
-		settings.certificate = "/home/markand/server.crt";
-		settings.port = 3320;
-		
-		server::server sv(ctx, settings);
-
-		db::open("", "", "markand", "malikaniadb", "");
-		db::init();
-		
-		ctx.run();
-	} catch (const std::exception& ex) {
-		std::cerr << "abort: " << ex.what() << std::endl;
-	}
-}
--- a/tests/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ b/tests/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -18,6 +18,6 @@
 
 project(test)
 
-add_subdirectory(libcommon)
-add_subdirectory(libclient)
+add_subdirectory(libmlk)
+add_subdirectory(libmlk-client)
 add_subdirectory(tools)
--- a/tests/libclient/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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(color)
-
-# JavaScript bindings
-add_subdirectory(js-color)
--- a/tests/libclient/color/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME color
-	LIBRARIES libmlk-client
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libclient/color/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-/*
- * main.cpp -- test mlk::client::color
- *
- * 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 "Color"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/client/color.hpp>
-
-namespace mlk::client {
-
-namespace {
-
-/*
- * Separate arguments.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(basic)
-
-BOOST_AUTO_TEST_CASE(black)
-{
-	color c;
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(white)
-{
-	color c{255, 255, 255, 255};
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(red)
-{
-	color c{255, 0, 0, 255};
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(green)
-{
-	color c{0, 255, 0, 255};
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(blue)
-{
-	color c{0, 0, 255, 255};
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Hexadecimal.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(hex)
-
-BOOST_AUTO_TEST_CASE(black)
-{
-	const auto c = color::from_hex(0xff000000);
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(white)
-{
-	const auto c = color::from_hex(0xffffffff);
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(red)
-{
-	const auto c = color::from_hex(0xffff0000);
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(green)
-{
-	const auto c = color::from_hex(0xff00ff00);
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(blue)
-{
-	const auto c = color::from_hex(0xff0000ff);
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Names.
- * ------------------------------------------------------------------
- *
- * Test most famous.
- */
-
-BOOST_AUTO_TEST_SUITE(named)
-
-BOOST_AUTO_TEST_CASE(black)
-{
-	const auto c = color::from_name("black");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(white)
-{
-	const auto c = color::from_name("white");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(red)
-{
-	const auto c = color::from_name("red");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(green)
-{
-	const auto c = color::from_name("green");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 128);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(blue)
-{
-	const auto c = color::from_name("blue");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(wrong)
-{
-	BOOST_REQUIRE_THROW(color::from_name("does not exist"), std::exception);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * #rrggbb.
- * ------------------------------------------------------------------
- *
- * Test most famous.
- */
-
-BOOST_AUTO_TEST_SUITE(long_rgb)
-
-BOOST_AUTO_TEST_CASE(black)
-{
-	const auto c = color::from_name("#000000");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(white)
-{
-	const auto c = color::from_name("#ffffff");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(red)
-{
-	const auto c = color::from_name("#ff0000");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(green)
-{
-	const auto c = color::from_name("#00ff00");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(blue)
-{
-	const auto c = color::from_name("#0000ff");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(wrong)
-{
-	BOOST_REQUIRE_THROW(color::from_name("#ghijkl"), std::exception);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * #rgb.
- * ------------------------------------------------------------------
- *
- * Test most famous.
- */
-
-BOOST_AUTO_TEST_SUITE(short_rgb)
-
-BOOST_AUTO_TEST_CASE(black)
-{
-	const auto c = color::from_name("#000");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(white)
-{
-	const auto c = color::from_name("#fff");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(red)
-{
-	const auto c = color::from_name("#f00");
-
-	BOOST_TEST(c.red == 255);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(green)
-{
-	const auto c = color::from_name("#0f0");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 255);
-	BOOST_TEST(c.blue == 0);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(blue)
-{
-	const auto c = color::from_name("#00f");
-
-	BOOST_TEST(c.red == 0);
-	BOOST_TEST(c.green == 0);
-	BOOST_TEST(c.blue == 255);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(combination)
-{
-	const auto c = color::from_name("#123");
-
-	BOOST_TEST(c.red == 17);
-	BOOST_TEST(c.green == 34);
-	BOOST_TEST(c.blue == 51);
-	BOOST_TEST(c.alpha == 255);
-}
-
-BOOST_AUTO_TEST_CASE(wrong)
-{
-	BOOST_REQUIRE_THROW(color::from_name("#ghi"), std::exception);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libclient/js-color/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-color
-	LIBRARIES libmlk-client-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libclient/js-color/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,698 +0,0 @@
-/*
- * main.cpp -- test Color (JavaScript binding)
- *
- * 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 "Javascript Color"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/client/js/test/js_api_fixture.hpp>
-
-namespace mlk::client {
-
-namespace {
-
-auto component(duk_context* ctx, const char* name) -> int
-{
-	duk_get_global_string(ctx, name);
-	auto value = duk_require_int(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-BOOST_FIXTURE_TEST_SUITE(test_color_suite, js::test::js_api_fixture)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color();"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 0);
-	BOOST_TEST(component(ctx_, "g") == 0);
-	BOOST_TEST(component(ctx_, "b") == 0);
-	BOOST_TEST(component(ctx_, "a") == 255);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_string)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color('white');"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 255);
-	BOOST_TEST(component(ctx_, "g") == 255);
-	BOOST_TEST(component(ctx_, "b") == 255);
-	BOOST_TEST(component(ctx_, "a") == 255);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_string_rgb)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color('#0000ff');"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 0);
-	BOOST_TEST(component(ctx_, "g") == 0);
-	BOOST_TEST(component(ctx_, "b") == 255);
-	BOOST_TEST(component(ctx_, "a") == 255);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_3_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color(10, 20, 30);"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 10);
-	BOOST_TEST(component(ctx_, "g") == 20);
-	BOOST_TEST(component(ctx_, "b") == 30);
-	BOOST_TEST(component(ctx_, "a") == 255);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_4_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color(10, 20, 30, 40);"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 10);
-	BOOST_TEST(component(ctx_, "g") == 20);
-	BOOST_TEST(component(ctx_, "b") == 30);
-	BOOST_TEST(component(ctx_, "a") == 40);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object_no_alpha)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color({ red: 10, green: 20, blue: 30 });"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 10);
-	BOOST_TEST(component(ctx_, "g") == 20);
-	BOOST_TEST(component(ctx_, "b") == 30);
-	BOOST_TEST(component(ctx_, "a") == 255);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object_alpha)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"c = Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 10);
-	BOOST_TEST(component(ctx_, "g") == 20);
-	BOOST_TEST(component(ctx_, "b") == 30);
-	BOOST_TEST(component(ctx_, "a") == 40);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	/*
-	 * Just one test, function parse the same way, only 'this' or a new
-	 * object is returned.
-	 */
-	const auto ret = duk_peval_string(ctx_,
-		"c = new Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });"
-		"r = c.red;"
-		"g = c.green;"
-		"b = c.blue;"
-		"a = c.alpha;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	BOOST_TEST(component(ctx_, "r") == 10);
-	BOOST_TEST(component(ctx_, "g") == 20);
-	BOOST_TEST(component(ctx_, "b") == 30);
-	BOOST_TEST(component(ctx_, "a") == 40);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color(null);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_arg_2)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color(10, null, 30);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#if 0
-
-// TODO: determine what's the best thing to do with negative values
-
-BOOST_AUTO_TEST_CASE(constructor_range_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color(-1, 20, 30);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_2)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color(10, 20, 256);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_3)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color(10, 20, 30, 800);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object_range_red)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color({ red: -1, green: 20, blue: 30 });"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object_range_alpha)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 800 });"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#endif
-
-BOOST_AUTO_TEST_CASE(constructor_string)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color('does not exist');"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof Error);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_string_rgb)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Color('#ghijkl');"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof Error);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- *
- * TypeTraits<Color>::require expect to have a valid color, it raises an error
- * for any invalid component. Only alpha can be ommitted but if it is present
- * and incorrect, an exception is also raised.
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto color = mlk::js::duk::require<mlk::client::color>(ctx, 0);
-
-		duk_push_uint(ctx, color.red);
-		duk_put_global_string(ctx, "r");
-		duk_push_uint(ctx, color.green);
-		duk_put_global_string(ctx, "g");
-		duk_push_uint(ctx, color.blue);
-		duk_put_global_string(ctx, "b");
-		duk_push_uint(ctx, color.alpha);
-		duk_put_global_string(ctx, "a");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_, "draw('#ff0000');");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "r");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "g");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "b");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "a");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::client::color>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  draw('#ghijkl');"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof Error);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#if 0
-
-TODO: check what to do with out of range value
-
-BOOST_AUTO_TEST_CASE(fail_alpha)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::client::color>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  draw({ red: 10, green: 20, blue: 30, alpha: 800 });"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#endif
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- *
- * TypeTraits<Color>::get readjust any invalid values.
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(normal)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
-
-		duk_push_uint(ctx, color.red);
-		duk_put_global_string(ctx, "r");
-		duk_push_uint(ctx, color.green);
-		duk_put_global_string(ctx, "g");
-		duk_push_uint(ctx, color.blue);
-		duk_put_global_string(ctx, "b");
-		duk_push_uint(ctx, color.alpha);
-		duk_put_global_string(ctx, "a");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_, "draw('#ff0000');");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "r");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "g");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "b");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "a");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(adjust_rgb)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
-
-		duk_push_uint(ctx, color.red);
-		duk_put_global_string(ctx, "r");
-		duk_push_uint(ctx, color.green);
-		duk_put_global_string(ctx, "g");
-		duk_push_uint(ctx, color.blue);
-		duk_put_global_string(ctx, "b");
-		duk_push_uint(ctx, color.alpha);
-		duk_put_global_string(ctx, "a");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_, "draw('#ghijkl');");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "r");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "g");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "b");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "a");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-}
-
-#if 0
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
-
-		duk_push_uint(ctx, color.red);
-		duk_put_global_string(ctx, "r");
-		duk_push_uint(ctx, color.green);
-		duk_put_global_string(ctx, "g");
-		duk_push_uint(ctx, color.blue);
-		duk_put_global_string(ctx, "b");
-		duk_push_uint(ctx, color.alpha);
-		duk_put_global_string(ctx, "a");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "r");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "g");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "b");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "a");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-}
-
-#endif
-
-BOOST_AUTO_TEST_CASE(something_else)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
-
-		duk_push_uint(ctx, color.red);
-		duk_put_global_string(ctx, "r");
-		duk_push_uint(ctx, color.green);
-		duk_put_global_string(ctx, "g");
-		duk_push_uint(ctx, color.blue);
-		duk_put_global_string(ctx, "b");
-		duk_push_uint(ctx, color.alpha);
-		duk_put_global_string(ctx, "a");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "draw");
-
-	const auto ret = duk_peval_string(ctx_, "draw(null);");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "r");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "g");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "b");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "a");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libcommon/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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(line)
-add_subdirectory(point)
-add_subdirectory(rectangle)
-add_subdirectory(size)
-add_subdirectory(util)
-add_subdirectory(socket)
-
-# JavaScript bindings
-add_subdirectory(js-elapsed-timer)
-add_subdirectory(js-line)
-add_subdirectory(js-point)
-add_subdirectory(js-rectangle)
-add_subdirectory(js-size)
--- a/tests/libcommon/js-elapsed-timer/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-elapsed-timer
-	LIBRARIES libmlk-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/js-elapsed-timer/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * main.cpp -- test ElapsedTimer (JavaScript binding)
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <thread>
-
-#define BOOST_TEST_MODULE "Javascript ElapsedTimer"
-#include <boost/format.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/js/test/js_api_fixture.hpp>
-
-using boost::format;
-using boost::str;
-
-using namespace std::chrono_literals;
-
-namespace mlk {
-
-namespace {
-
-/*
- * For all tests, we tolerate 30 ms because some systems have bigger lags.
- */
-constexpr int margin = 30;
-
-void assert_range(int value, int expected)
-{
-	if (value < (expected - margin) || value > (expected + margin))
-		throw std::invalid_argument(
-			str(format("%d is bigger than [%d, %d]") % value % (expected - margin) % (expected + margin)));
-}
-
-BOOST_FIXTURE_TEST_SUITE(test_elapsed_timer_suite, js::test::js_api_fixture)
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	std::this_thread::sleep_for(300ms);
-
-	if (duk_peval_string(ctx_, "result = timer.elapsed();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "result");
-	assert_range(duk_to_int(ctx_, -1), 300);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(pause)
-{
-	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	/*
-	 * Simulate a pause in the game like this:
-	 *
-	 * start pause restart elapsed
-	 * |   10ms   |.5ms.| 6ms  |
-	 *
-	 * Since the game was paused, the 5ms must not be totalized.
-	 */
-	std::this_thread::sleep_for(10ms);
-
-	if (duk_peval_string(ctx_, "timer.pause();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	std::this_thread::sleep_for(5ms);
-
-	if (duk_peval_string(ctx_, "timer.restart();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	std::this_thread::sleep_for(6ms);
-
-	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "result");
-	assert_range(duk_to_int(ctx_, -1), 16);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(doublecheck)
-{
-	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	std::this_thread::sleep_for(50ms);
-
-	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	std::this_thread::sleep_for(50ms);
-
-	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "result");
-	assert_range(duk_to_int(ctx_, -1), 100);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/js-line/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-line
-	LIBRARIES libmlk-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/js-line/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,305 +0,0 @@
-/*
- * main.cpp -- test Line (JavaScript binding)
- *
- * 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 "Javascript Line"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/line.hpp>
-
-#include <malikania/js/test/js_api_fixture.hpp>
-
-namespace mlk {
-
-namespace {
-
-BOOST_FIXTURE_TEST_SUITE(test_line_suite, js::test::js_api_fixture)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Line();"
-		"x1 = r.x1;"
-		"y1 = r.y1;"
-		"x2 = r.x2;"
-		"y2 = r.y2;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_4_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Line(10, 20, 30, 40);"
-		"x1 = r.x1;"
-		"y1 = r.y1;"
-		"x2 = r.x2;"
-		"y2 = r.y2;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });"
-		"x1 = r.x1;"
-		"y1 = r.y1;"
-		"x2 = r.x2;"
-		"y2 = r.y2;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = new Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });"
-		"x1 = r.x1;"
-		"y1 = r.y1;"
-		"x2 = r.x2;"
-		"y2 = r.y2;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(arg_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Line(null);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto line = mlk::js::duk::require<mlk::line>(ctx, 0);
-
-		duk_push_int(ctx, line.x1);
-		duk_put_global_string(ctx, "x1");
-		duk_push_int(ctx, line.y1);
-		duk_put_global_string(ctx, "y1");
-		duk_push_int(ctx, line.x2);
-		duk_put_global_string(ctx, "x2");
-		duk_push_int(ctx, line.y2);
-		duk_put_global_string(ctx, "y2");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 50);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 80);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::line>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  build({});"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto line = mlk::js::duk::get<mlk::line>(ctx, 0);
-
-		duk_push_int(ctx, line.x1);
-		duk_put_global_string(ctx, "x1");
-		duk_push_int(ctx, line.y1);
-		duk_put_global_string(ctx, "y1");
-		duk_push_int(ctx, line.x2);
-		duk_put_global_string(ctx, "x2");
-		duk_push_int(ctx, line.y2);
-		duk_put_global_string(ctx, "y2");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({});");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y1");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "x2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y2");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/js-point/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-point
-	LIBRARIES libmlk-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/js-point/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-/*
- * main.cpp -- test Point (JavaScript binding)
- *
- * 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 "Javascript Point"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/point.hpp>
-
-#include <malikania/js/test/js_api_fixture.hpp>
-
-namespace mlk {
-
-namespace {
-
-BOOST_FIXTURE_TEST_SUITE(test_point_suite, js::test::js_api_fixture)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"p = Malikania.Point();"
-		"x = p.x;"
-		"y = p.y;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_2_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"p = Malikania.Point(-10, -20);"
-		"x = p.x;"
-		"y = p.y;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == -10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == -20);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"p = Malikania.Point({ x: 100, y: 200 });"
-		"x = p.x;"
-		"y = p.y;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"p = new Malikania.Point({ x: 100, y: 200 });"
-		"x = p.x;"
-		"y = p.y;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Point(null);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto point = mlk::js::duk::require<mlk::point>(ctx, 0);
-
-		duk_push_int(ctx, point.x);
-		duk_put_global_string(ctx, "x");
-		duk_push_int(ctx, point.y);
-		duk_put_global_string(ctx, "y");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({ x: 100, y: 200 });");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::point>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  build({});"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto point = mlk::js::duk::get<mlk::point>(ctx, 0);
-
-		duk_push_int(ctx, point.x);
-		duk_put_global_string(ctx, "x");
-		duk_push_int(ctx, point.y);
-		duk_put_global_string(ctx, "y");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({});");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/js-rectangle/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-rectangle
-	LIBRARIES libmlk-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/js-rectangle/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,332 +0,0 @@
-/*
- * main.cpp -- test Rectangle (JavaScript binding)
- *
- * 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 "Javascript Rectangle"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/rectangle.hpp>
-
-#include <malikania/js/test/js_api_fixture.hpp>
-
-namespace mlk {
-
-namespace {
-
-BOOST_FIXTURE_TEST_SUITE(test_rectangle_suite, js::test::js_api_fixture)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Rectangle();"
-		"x = r.x;"
-		"y = r.y;"
-		"w = r.width;"
-		"h = r.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_4_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Rectangle(10, 20, 30, 40);"
-		"x = r.x;"
-		"y = r.y;"
-		"w = r.width;"
-		"h = r.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });"
-		"x = r.x;"
-		"y = r.y;"
-		"w = r.width;"
-		"h = r.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"r = new Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });"
-		"x = r.x;"
-		"y = r.y;"
-		"w = r.width;"
-		"h = r.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Rectangle(null);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#if 0
-
-// TODO: determine what's the best thing to do with negative values
-
-BOOST_AUTO_TEST_CASE(constructor_range_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Rectangle(0, 0, -10, -10);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#endif
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto rect = mlk::js::duk::require<mlk::rectangle>(ctx, 0);
-
-		duk_push_int(ctx, rect.x);
-		duk_put_global_string(ctx, "x");
-		duk_push_int(ctx, rect.y);
-		duk_put_global_string(ctx, "y");
-		duk_push_uint(ctx, rect.width);
-		duk_put_global_string(ctx, "w");
-		duk_push_uint(ctx, rect.height);
-		duk_put_global_string(ctx, "h");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({ x: 50, y: 80, width: 100, height: 200 });");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 50);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 80);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::rectangle>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  build({});"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto rect = mlk::js::duk::get<mlk::rectangle>(ctx, 0);
-
-		duk_push_int(ctx, rect.x);
-		duk_put_global_string(ctx, "x");
-		duk_push_int(ctx, rect.y);
-		duk_put_global_string(ctx, "y");
-		duk_push_uint(ctx, rect.width);
-		duk_put_global_string(ctx, "w");
-		duk_push_uint(ctx, rect.height);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({});");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "x");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "y");
-	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/js-size/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME js-size
-	LIBRARIES libmlk-js-test
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/js-size/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +0,0 @@
-/*
- * main.cpp -- test Size (JavaScript binding)
- *
- * 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 "Javascript Size"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/js/test/js_api_fixture.hpp>
-
-namespace mlk {
-
-namespace {
-
-BOOST_FIXTURE_TEST_SUITE(test_size_suite, js::test::js_api_fixture)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"s = Malikania.Size();"
-		"w = s.width;"
-		"h = s.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_2_args)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"s = Malikania.Size(100, 200);"
-		"w = s.width;"
-		"h = s.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"s = Malikania.Size({ width: 100, height: 200 });"
-		"w = s.width;"
-		"h = s.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"s = new Malikania.Size({ width: 100, height: 200 });"
-		"w = s.width;"
-		"h = s.height;"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Size(null);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#if 0
-
-// TODO: determine what's the best thing to do with negative values
-
-BOOST_AUTO_TEST_CASE(constructor_range_1)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Size(-1, 200);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_2)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Size(100, -1);"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_3)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Size({ width: -1, height: 200 });"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_4)
-{
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  Malikania.Size({ width: 100, height: -1 });"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof RangeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-#endif
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto size = mlk::js::duk::require<mlk::size>(ctx, 0);
-
-		duk_push_uint(ctx, size.width);
-		duk_put_global_string(ctx, "w");
-		duk_push_uint(ctx, size.height);
-		duk_put_global_string(ctx, "h");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({ width: 100, height: 200 });");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		mlk::js::duk::require<mlk::size>(ctx, 0);
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_,
-		"try {"
-		"  build({});"
-		"} catch (e) {"
-		"  name = e.name;"
-		"  correct = (e instanceof TypeError);"
-		"}"
-	);
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "name");
-	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "correct");
-	BOOST_TEST(duk_to_boolean(ctx_, -1));
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	duk_push_c_function(ctx_, [] (auto ctx) {
-		const auto size = mlk::js::duk::get<mlk::size>(ctx, 0);
-
-		duk_push_uint(ctx, size.width);
-		duk_put_global_string(ctx, "w");
-		duk_push_uint(ctx, size.height);
-		duk_put_global_string(ctx, "h");
-
-		return 0;
-	}, 1);
-	duk_put_global_string(ctx_, "build");
-
-	const auto ret = duk_peval_string(ctx_, "build({});");
-
-	if (ret != 0)
-		throw mlk::js::duk::get_stack(ctx_, -1);
-
-	duk_get_global_string(ctx_, "w");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-	duk_get_global_string(ctx_, "h");
-	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
-	duk_pop(ctx_);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/line/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME line
-	LIBRARIES libmlk-client
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/line/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * main.cpp -- test mlk::client::line
- *
- * 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 "Line"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/line.hpp>
-
-namespace mlk {
-
-auto operator<<(std::ostream& out, const line& line) -> std::ostream&
-{
-	out << "{";
-	out << line.x1 << ", " << line.y1 << ", ";
-	out << line.x2 << ", " << line.y2;
-	out << "}";
-
-	return out;
-}
-
-namespace {
-
-BOOST_AUTO_TEST_CASE(none)
-{
-	line line;
-
-	BOOST_TEST(line.x1 == 0);
-	BOOST_TEST(line.y1 == 0);
-	BOOST_TEST(line.x2 == 0);
-	BOOST_TEST(line.y2 == 0);
-}
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	line line{10, 20, 30, 40};
-
-	BOOST_TEST(line.x1 == 10);
-	BOOST_TEST(line.y1 == 20);
-	BOOST_TEST(line.x2 == 30);
-	BOOST_TEST(line.y2 == 40);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq)
-{
-	line line1, line2;
-
-	BOOST_TEST(line2 == line1);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq1)
-{
-	line line1{10, 20, 30, 40};
-	line line2{10, 20, 30, 40};
-
-	BOOST_TEST(line2 == line1);
-}
-
-BOOST_AUTO_TEST_CASE(operator_neq)
-{
-	BOOST_TEST((line{10} != line{20}));
-	BOOST_TEST((line{10, 10} != line{10, 20}));
-	BOOST_TEST((line{10, 10, 10} != line{10, 10, 20}));
-	BOOST_TEST((line{10, 10, 10, 10} != line{10, 10, 10, 20}));
-}
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libcommon/point/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME point
-	LIBRARIES libmlk-client
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/point/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * main.cpp -- test mlk::client::point
- *
- * 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 "Point"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/point.hpp>
-
-namespace mlk {
-
-auto operator<<(std::ostream& out, const point& point) -> std::ostream&
-{
-	out << "{" << point.x << ", " << point.y << "}";
-
-	return out;
-}
-
-namespace {
-
-BOOST_AUTO_TEST_CASE(none)
-{
-	point point;
-
-	BOOST_TEST(point.x == 0);
-	BOOST_TEST(point.y == 0);
-}
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	point point{10, 20};
-
-	BOOST_TEST(point.x == 10);
-	BOOST_TEST(point.y == 20);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq)
-{
-	point point1, point2;
-
-	BOOST_TEST(point1 == point2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq1)
-{
-	point point1{10, 20};
-	point point2{10, 20};
-
-	BOOST_TEST(point1 == point2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_neq)
-{
-	BOOST_TEST((point{10} != point{20}));
-	BOOST_TEST((point{10, 10} != point{10, 20}));
-}
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libcommon/rectangle/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME rectangle
-	LIBRARIES libmlk-client
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/rectangle/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * main.cpp -- test mlk::client::rectangle
- *
- * 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 "Rectangle"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/rectangle.hpp>
-
-namespace mlk {
-
-auto operator<<(std::ostream& out, const rectangle& rectangle) -> std::ostream&
-{
-	out << "{";
-	out << rectangle.width << ", " << rectangle.height << ", ";
-	out << rectangle.x << ", " << rectangle.y;
-	out << "}";
-
-	return out;
-}
-
-namespace {
-
-BOOST_AUTO_TEST_CASE(none)
-{
-	rectangle rectangle;
-
-	BOOST_TEST(rectangle.x == 0);
-	BOOST_TEST(rectangle.y == 0);
-	BOOST_TEST(rectangle.width == 0U);
-	BOOST_TEST(rectangle.height == 0U);
-}
-
-BOOST_AUTO_TEST_CASE(null)
-{
-	BOOST_TEST(rectangle().is_null());
-	BOOST_TEST((!rectangle{0, 0, 10, 0}.is_null()));
-	BOOST_TEST((!rectangle{0, 0, 0, 10}.is_null()));
-	BOOST_TEST((!rectangle{0, 0, 10, 10}.is_null()));
-}
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	rectangle rectangle{10, 20, 30, 40};
-
-	BOOST_TEST(rectangle.x == 10);
-	BOOST_TEST(rectangle.y == 20);
-	BOOST_TEST(rectangle.width == 30U);
-	BOOST_TEST(rectangle.height == 40U);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq)
-{
-	rectangle rectangle1, rectangle2;
-
-	BOOST_TEST(rectangle1 == rectangle2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq1)
-{
-	rectangle rectangle1{10, 20, 30, 40};
-	rectangle rectangle2{10, 20, 30, 40};
-
-	BOOST_TEST(rectangle1 == rectangle2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_neq)
-{
-	BOOST_TEST((rectangle{10} != rectangle{20}));
-	BOOST_TEST((rectangle{10, 10} != rectangle{10, 20}));
-	BOOST_TEST((rectangle{10, 10, 10} != rectangle{10, 10, 20}));
-	BOOST_TEST((rectangle{10, 10, 10, 10} != rectangle{10, 10, 10, 20}));
-}
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libcommon/size/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME size
-	LIBRARIES libmlk
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/size/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * main.cpp -- test size
- *
- * 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 "Size"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/size.hpp>
-
-namespace mlk {
-
-namespace {
-
-BOOST_AUTO_TEST_CASE(none)
-{
-	const size size;
-
-	BOOST_TEST(size.width == 0U);
-	BOOST_TEST(size.height == 0U);
-}
-
-BOOST_AUTO_TEST_CASE(null)
-{
-	BOOST_TEST(size().is_null());
-	BOOST_TEST((!size{0, 10}.is_null()));
-	BOOST_TEST((!size{10, 0}.is_null()));
-}
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	const size size{10, 20};
-
-	BOOST_TEST(size.width == 10U);
-	BOOST_TEST(size.height == 20U);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq)
-{
-	const size size1, size2;
-
-	BOOST_TEST(size1 == size2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq_1)
-{
-	const size size1{10, 20};
-	const size size2{10, 20};
-
-	BOOST_TEST(size1 == size2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_neq)
-{
-	BOOST_TEST((size{10} != size{20}));
-	BOOST_TEST((size{10, 10} != size{10, 20}));
-}
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/socket/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME socket
-	LIBRARIES libmlk
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/socket/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * main.cpp -- test socket
- *
- * 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 "socket"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/socket.hpp>
-
-using boost::asio::io_context;
-using boost::asio::ip::make_address;
-using boost::asio::ip::tcp;
-using boost::asio::ssl::context;
-using boost::asio::ssl::stream_base;
-
-namespace mlk {
-
-namespace {
-
-class socket_fixture {
-private:
-	auto init() -> context;
-	void handshake();
-	void pair();
-
-protected:
-	// SSL and Asio context.
-	context ssl_context_{init()};
-	io_context ctx_;
-
-	// two connected sockets.
-	socket server_{ctx_, ssl_context_};
-	socket client_{ctx_, ssl_context_};
-
-	socket_fixture();
-};
-
-auto socket_fixture::init() -> context
-{
-	context ret{context::sslv23};
-
-	ret.use_private_key_file(CMAKE_SOURCE_DIR "/tests/assets/test.key", context::pem);
-	ret.use_certificate_file(CMAKE_SOURCE_DIR "/tests/assets/test.crt", context::pem);
-
-	return ret;
-}
-
-void socket_fixture::handshake()
-{
-	server_.get_socket().async_handshake(stream_base::server, [] (auto code) {
-		if (code)
-			throw std::system_error(code);
-	});
-	client_.get_socket().async_handshake(stream_base::client, [] (auto code) {
-		if (code)
-			throw std::system_error(code);
-	});
-
-	ctx_.run();
-	ctx_.reset();
-}
-
-void socket_fixture::pair()
-{
-	tcp::acceptor acc(ctx_, tcp::endpoint(tcp::v4(), 0U));
-
-	acc.async_accept(server_.get_socket().lowest_layer(), [] (auto code) {
-		if (code)
-			throw std::system_error(code);
-	});
-
-	tcp::endpoint ep(make_address("127.0.0.1"), acc.local_endpoint().port());
-
-	client_.get_socket().lowest_layer().async_connect(ep, [] (auto code) {
-		if (code)
-			throw std::system_error(code);
-	});
-
-	ctx_.run();
-	ctx_.reset();
-}
-
-socket_fixture::socket_fixture()
-{
-	pair();
-	handshake();
-}
-
-BOOST_FIXTURE_TEST_SUITE(socket_suite, socket_fixture)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	server_.recv([] (auto code, auto json) {
-		BOOST_TEST(!code);
-		BOOST_TEST(json["hello"].template get<std::string>() == "world");
-	});
-	client_.send({{ "hello", "world" }}, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	ctx_.run();
-}
-
-BOOST_AUTO_TEST_CASE(multiple)
-{
-	server_.recv([] (auto code, auto json) {
-		BOOST_TEST(!code);
-		BOOST_TEST(json["hello"].template get<std::string>() == "world");
-	});
-	client_.send({{ "hello", "world" }}, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	ctx_.run();
-	ctx_.reset();
-
-	server_.recv([] (auto code, auto json) {
-		BOOST_TEST(!code);
-		BOOST_TEST(json["hello"].template get<std::string>() == "what's up?");
-	});
-	client_.send({{ "hello", "what's up?" }}, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	ctx_.run();
-}
-
-BOOST_AUTO_TEST_CASE(simple_then_too_big)
-{
-	std::string big(102400, 'a');
-
-	server_.recv([] (auto code, auto json) {
-		BOOST_TEST(!code);
-		BOOST_TEST(json["hello"].template get<std::string>() == "world");
-	});
-	client_.send({{ "hello", "world" }}, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	ctx_.run();
-	ctx_.reset();
-
-	server_.recv([] (auto code, auto json) {
-		BOOST_TEST(code.value() == static_cast<int>(std::errc::argument_list_too_long));
-		BOOST_TEST(json.is_null());
-	});
-	client_.send({{ "hello", std::move(big) }}, [] (auto code) {
-		BOOST_TEST(!code);
-	});
-	ctx_.run();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk
--- a/tests/libcommon/util/CMakeLists.txt	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for malikania
-#
-# 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.
-#
-
-malikania_create_test(
-	NAME util
-	LIBRARIES libmlk
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libcommon/util/main.cpp	Sat Oct 27 07:11:03 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,468 +0,0 @@
-/*
- * main.cpp -- test util
- *
- * 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 "Util"
-#include <boost/test/unit_test.hpp>
-
-#include <malikania/util.hpp>
-#include <malikania/size.hpp>
-
-using namespace mlk;
-using namespace nlohmann;
-
-namespace nlohmann {
-
-namespace detail {
-
-auto operator<<(std::ostream& out, json::value_t type) -> std::ostream&
-{
-	out << json(type).type_name();
-	return out;
-}
-
-} // !detail
-
-} // !nlohmann
-
-/*
- * util::clamp
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(clamp)
-
-BOOST_AUTO_TEST_CASE(normal)
-{
-	BOOST_REQUIRE_EQUAL(5, util::clamp(5, 0, 10));
-}
-
-BOOST_AUTO_TEST_CASE(minimum)
-{
-	BOOST_REQUIRE_EQUAL(0, util::clamp(0, 0, 10));
-}
-
-BOOST_AUTO_TEST_CASE(maximum)
-{
-	BOOST_REQUIRE_EQUAL(10, util::clamp(10, 0, 10));
-}
-
-BOOST_AUTO_TEST_CASE(less)
-{
-	BOOST_REQUIRE_EQUAL(0, util::clamp(-10, 0, 10));
-}
-
-BOOST_AUTO_TEST_CASE(higher)
-{
-	BOOST_REQUIRE_EQUAL(10, util::clamp(20, 0, 10));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "b", true },
-		{ "i", 123 },
-		{ "s", "blabla" }
-	};
-
-	BOOST_REQUIRE_EQUAL(util::json::require(
-		object, "/b"_json_pointer, json::value_t::boolean).type(), json::value_t::boolean);
-	BOOST_REQUIRE_EQUAL(util::json::require(
-		object, "/i"_json_pointer, json::value_t::number_integer).type(), json::value_t::number_integer);
-	BOOST_REQUIRE_EQUAL(util::json::require(
-		object, "/s"_json_pointer, json::value_t::string).type(), json::value_t::string);
-}
-
-BOOST_AUTO_TEST_CASE(nonexistent)
-{
-	auto json = json::object();
-
-	try {
-		util::json::require(json, "/non-existent"_json_pointer, json::value_t::string);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::null);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
-	}
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-string", 123 }
-	};
-
-	try {
-		util::json::require(object, "/not-string"_json_pointer, json::value_t::string);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_array
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_array)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "a", { 1, 2, 3 } },
-		{ "l1", {
-				{ "l2", { 4, 5, 6 } }
-			}
-		}
-	};
-
-	auto a = util::json::require_array(object, "/a"_json_pointer);
-	auto l2 = util::json::require_array(object, "/l1/l2"_json_pointer);
-
-	BOOST_REQUIRE(a.is_array());
-	BOOST_REQUIRE(l2.is_array());
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-array", 123 }
-	};
-
-	try {
-		util::json::require_array(object, "/not-array"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::array);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_bool
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_bool)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "b", true }
-	};
-
-	BOOST_REQUIRE_EQUAL(util::json::require_bool(object, "/b"_json_pointer), true);
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-bool", 123 }
-	};
-
-	try {
-		util::json::require_bool(object, "/not-bool"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::boolean);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_int
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_int)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "i", 123 }
-	};
-
-	BOOST_REQUIRE_EQUAL(util::json::require_int(object, "/i"_json_pointer), 123);
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-int", true }
-	};
-
-	try {
-		util::json::require_int(object, "/not-int"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::boolean);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_integer);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_object
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_object)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{
-			"network", json::object({
-				{ "host", "localhost" },
-				{ "port", 9090 }
-			})
-		}
-	};
-
-	BOOST_REQUIRE(util::json::require_object(object, "/network"_json_pointer).is_object());
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-object", 123 }
-	};
-
-	try {
-		util::json::require_object(object, "/not-object"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::object);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_string
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_string)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "s", "hello" }
-	};
-
-	BOOST_REQUIRE_EQUAL(util::json::require_string(object, "/s"_json_pointer), "hello");
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-string", 123 }
-	};
-
-	try {
-		util::json::require_string(object, "/not-string"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * util::json::require_uint
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(json_require_uint)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "u1", 123U }
-	};
-
-	BOOST_REQUIRE_EQUAL(util::json::require_uint(object, "/u1"_json_pointer), 123U);
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	json object{
-		{ "not-uint", true }
-	};
-
-	try {
-		util::json::require_uint(object, "/not-uint"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::boolean);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE(json_require_size)
-
-/*
- * util::json::require_size
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "size", {
-				{ "width", 10 },
-				{ "height", 20 }
-			}
-		}
-	};
-
-	BOOST_TEST((util::json::require_size(object, "/size"_json_pointer) == mlk::size{10, 20}));
-}
-
-BOOST_AUTO_TEST_CASE(not_object)
-{
-	json object{
-		{ "size", false }
-	};
-
-	try {
-		util::json::require_size(object, "/size"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::null);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
-	}
-}
-
-BOOST_AUTO_TEST_CASE(not_int_width)
-{
-	json object{
-		{ "size", {
-				{ "width", "10" },
-				{ "height", 20 }
-			}
-		}
-	};
-
-	try {
-		util::json::require_size(object, "/size"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::string);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
-	}
-}
-
-BOOST_AUTO_TEST_CASE(not_int_height)
-{
-	json object{
-		{ "size", {
-				{ "width", 10 },
-				{ "height", "20" }
-			}
-		}
-	};
-
-	try {
-		util::json::require_size(object, "/size"_json_pointer);
-		BOOST_FAIL("exception expected");
-	} catch (const util::json::property_error& ex) {
-		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::string);
-		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE(json_get_size)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-	json object{
-		{ "size", {
-				{ "width", 10 },
-				{ "height", 20 }
-			}
-		}
-	};
-
-	BOOST_TEST((util::json::get_size(object, "/size"_json_pointer) == mlk::size{10, 20}));
-}
-
-BOOST_AUTO_TEST_CASE(not_object)
-{
-	const json object{{ "size", false }};
-	const mlk::size def{10, 20};
-
-	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
-}
-
-BOOST_AUTO_TEST_CASE(not_int_width)
-{
-	const json object{
-		{ "size", {
-				{ "width", "10" },
-				{ "height", 20 }
-			}
-		}
-	};
-
-	const mlk::size def{10, 20};
-
-	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
-}
-
-BOOST_AUTO_TEST_CASE(not_int_height)
-{
-	const json object{
-		{ "size", {
-				{ "width", 10 },
-				{ "height", "20" }
-			}
-		}
-	};
-
-	const mlk::size def{10, 20};
-
-	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk-client/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,22 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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(color)
+
+# JavaScript bindings
+add_subdirectory(js-color)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk-client/color/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME color
+	LIBRARIES libmlk-client
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk-client/color/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,356 @@
+/*
+ * main.cpp -- test mlk::client::color
+ *
+ * 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 "Color"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/client/color.hpp>
+
+namespace mlk::client {
+
+namespace {
+
+/*
+ * Separate arguments.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(basic)
+
+BOOST_AUTO_TEST_CASE(black)
+{
+	color c;
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(white)
+{
+	color c{255, 255, 255, 255};
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(red)
+{
+	color c{255, 0, 0, 255};
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(green)
+{
+	color c{0, 255, 0, 255};
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(blue)
+{
+	color c{0, 0, 255, 255};
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Hexadecimal.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(hex)
+
+BOOST_AUTO_TEST_CASE(black)
+{
+	const auto c = color::from_hex(0xff000000);
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(white)
+{
+	const auto c = color::from_hex(0xffffffff);
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(red)
+{
+	const auto c = color::from_hex(0xffff0000);
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(green)
+{
+	const auto c = color::from_hex(0xff00ff00);
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(blue)
+{
+	const auto c = color::from_hex(0xff0000ff);
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Names.
+ * ------------------------------------------------------------------
+ *
+ * Test most famous.
+ */
+
+BOOST_AUTO_TEST_SUITE(named)
+
+BOOST_AUTO_TEST_CASE(black)
+{
+	const auto c = color::from_name("black");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(white)
+{
+	const auto c = color::from_name("white");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(red)
+{
+	const auto c = color::from_name("red");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(green)
+{
+	const auto c = color::from_name("green");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 128);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(blue)
+{
+	const auto c = color::from_name("blue");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(wrong)
+{
+	BOOST_REQUIRE_THROW(color::from_name("does not exist"), std::exception);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * #rrggbb.
+ * ------------------------------------------------------------------
+ *
+ * Test most famous.
+ */
+
+BOOST_AUTO_TEST_SUITE(long_rgb)
+
+BOOST_AUTO_TEST_CASE(black)
+{
+	const auto c = color::from_name("#000000");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(white)
+{
+	const auto c = color::from_name("#ffffff");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(red)
+{
+	const auto c = color::from_name("#ff0000");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(green)
+{
+	const auto c = color::from_name("#00ff00");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(blue)
+{
+	const auto c = color::from_name("#0000ff");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(wrong)
+{
+	BOOST_REQUIRE_THROW(color::from_name("#ghijkl"), std::exception);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * #rgb.
+ * ------------------------------------------------------------------
+ *
+ * Test most famous.
+ */
+
+BOOST_AUTO_TEST_SUITE(short_rgb)
+
+BOOST_AUTO_TEST_CASE(black)
+{
+	const auto c = color::from_name("#000");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(white)
+{
+	const auto c = color::from_name("#fff");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(red)
+{
+	const auto c = color::from_name("#f00");
+
+	BOOST_TEST(c.red == 255);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(green)
+{
+	const auto c = color::from_name("#0f0");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 255);
+	BOOST_TEST(c.blue == 0);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(blue)
+{
+	const auto c = color::from_name("#00f");
+
+	BOOST_TEST(c.red == 0);
+	BOOST_TEST(c.green == 0);
+	BOOST_TEST(c.blue == 255);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(combination)
+{
+	const auto c = color::from_name("#123");
+
+	BOOST_TEST(c.red == 17);
+	BOOST_TEST(c.green == 34);
+	BOOST_TEST(c.blue == 51);
+	BOOST_TEST(c.alpha == 255);
+}
+
+BOOST_AUTO_TEST_CASE(wrong)
+{
+	BOOST_REQUIRE_THROW(color::from_name("#ghi"), std::exception);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk::client
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk-client/js-color/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-color
+	LIBRARIES libmlk-client-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk-client/js-color/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,698 @@
+/*
+ * main.cpp -- test Color (JavaScript binding)
+ *
+ * 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 "Javascript Color"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/client/js/test/js_api_fixture.hpp>
+
+namespace mlk::client {
+
+namespace {
+
+auto component(duk_context* ctx, const char* name) -> int
+{
+	duk_get_global_string(ctx, name);
+	auto value = duk_require_int(ctx, -1);
+	duk_pop(ctx);
+
+	return value;
+}
+
+BOOST_FIXTURE_TEST_SUITE(test_color_suite, js::test::js_api_fixture)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color();"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 0);
+	BOOST_TEST(component(ctx_, "g") == 0);
+	BOOST_TEST(component(ctx_, "b") == 0);
+	BOOST_TEST(component(ctx_, "a") == 255);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_string)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color('white');"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 255);
+	BOOST_TEST(component(ctx_, "g") == 255);
+	BOOST_TEST(component(ctx_, "b") == 255);
+	BOOST_TEST(component(ctx_, "a") == 255);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_string_rgb)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color('#0000ff');"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 0);
+	BOOST_TEST(component(ctx_, "g") == 0);
+	BOOST_TEST(component(ctx_, "b") == 255);
+	BOOST_TEST(component(ctx_, "a") == 255);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_3_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color(10, 20, 30);"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 10);
+	BOOST_TEST(component(ctx_, "g") == 20);
+	BOOST_TEST(component(ctx_, "b") == 30);
+	BOOST_TEST(component(ctx_, "a") == 255);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_4_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color(10, 20, 30, 40);"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 10);
+	BOOST_TEST(component(ctx_, "g") == 20);
+	BOOST_TEST(component(ctx_, "b") == 30);
+	BOOST_TEST(component(ctx_, "a") == 40);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object_no_alpha)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color({ red: 10, green: 20, blue: 30 });"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 10);
+	BOOST_TEST(component(ctx_, "g") == 20);
+	BOOST_TEST(component(ctx_, "b") == 30);
+	BOOST_TEST(component(ctx_, "a") == 255);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object_alpha)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"c = Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 10);
+	BOOST_TEST(component(ctx_, "g") == 20);
+	BOOST_TEST(component(ctx_, "b") == 30);
+	BOOST_TEST(component(ctx_, "a") == 40);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	/*
+	 * Just one test, function parse the same way, only 'this' or a new
+	 * object is returned.
+	 */
+	const auto ret = duk_peval_string(ctx_,
+		"c = new Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });"
+		"r = c.red;"
+		"g = c.green;"
+		"b = c.blue;"
+		"a = c.alpha;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	BOOST_TEST(component(ctx_, "r") == 10);
+	BOOST_TEST(component(ctx_, "g") == 20);
+	BOOST_TEST(component(ctx_, "b") == 30);
+	BOOST_TEST(component(ctx_, "a") == 40);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color(null);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_arg_2)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color(10, null, 30);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#if 0
+
+// TODO: determine what's the best thing to do with negative values
+
+BOOST_AUTO_TEST_CASE(constructor_range_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color(-1, 20, 30);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_2)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color(10, 20, 256);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_3)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color(10, 20, 30, 800);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object_range_red)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color({ red: -1, green: 20, blue: 30 });"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object_range_alpha)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 800 });"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#endif
+
+BOOST_AUTO_TEST_CASE(constructor_string)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color('does not exist');"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof Error);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_string_rgb)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Color('#ghijkl');"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof Error);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ *
+ * TypeTraits<Color>::require expect to have a valid color, it raises an error
+ * for any invalid component. Only alpha can be ommitted but if it is present
+ * and incorrect, an exception is also raised.
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto color = mlk::js::duk::require<mlk::client::color>(ctx, 0);
+
+		duk_push_uint(ctx, color.red);
+		duk_put_global_string(ctx, "r");
+		duk_push_uint(ctx, color.green);
+		duk_put_global_string(ctx, "g");
+		duk_push_uint(ctx, color.blue);
+		duk_put_global_string(ctx, "b");
+		duk_push_uint(ctx, color.alpha);
+		duk_put_global_string(ctx, "a");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_, "draw('#ff0000');");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "r");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "g");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "b");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "a");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::client::color>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  draw('#ghijkl');"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof Error);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "Error");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#if 0
+
+TODO: check what to do with out of range value
+
+BOOST_AUTO_TEST_CASE(fail_alpha)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::client::color>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  draw({ red: 10, green: 20, blue: 30, alpha: 800 });"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ *
+ * TypeTraits<Color>::get readjust any invalid values.
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(normal)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
+
+		duk_push_uint(ctx, color.red);
+		duk_put_global_string(ctx, "r");
+		duk_push_uint(ctx, color.green);
+		duk_put_global_string(ctx, "g");
+		duk_push_uint(ctx, color.blue);
+		duk_put_global_string(ctx, "b");
+		duk_push_uint(ctx, color.alpha);
+		duk_put_global_string(ctx, "a");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_, "draw('#ff0000');");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "r");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "g");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "b");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "a");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(adjust_rgb)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
+
+		duk_push_uint(ctx, color.red);
+		duk_put_global_string(ctx, "r");
+		duk_push_uint(ctx, color.green);
+		duk_put_global_string(ctx, "g");
+		duk_push_uint(ctx, color.blue);
+		duk_put_global_string(ctx, "b");
+		duk_push_uint(ctx, color.alpha);
+		duk_put_global_string(ctx, "a");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_, "draw('#ghijkl');");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "r");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "g");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "b");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "a");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+}
+
+#if 0
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
+
+		duk_push_uint(ctx, color.red);
+		duk_put_global_string(ctx, "r");
+		duk_push_uint(ctx, color.green);
+		duk_put_global_string(ctx, "g");
+		duk_push_uint(ctx, color.blue);
+		duk_put_global_string(ctx, "b");
+		duk_push_uint(ctx, color.alpha);
+		duk_put_global_string(ctx, "a");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "r");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "g");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "b");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "a");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+}
+
+#endif
+
+BOOST_AUTO_TEST_CASE(something_else)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0);
+
+		duk_push_uint(ctx, color.red);
+		duk_put_global_string(ctx, "r");
+		duk_push_uint(ctx, color.green);
+		duk_put_global_string(ctx, "g");
+		duk_push_uint(ctx, color.blue);
+		duk_put_global_string(ctx, "b");
+		duk_push_uint(ctx, color.alpha);
+		duk_put_global_string(ctx, "a");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "draw");
+
+	const auto ret = duk_peval_string(ctx_, "draw(null);");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "r");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "g");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "b");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "a");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 255U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk::client
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,31 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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(line)
+add_subdirectory(point)
+add_subdirectory(rectangle)
+add_subdirectory(size)
+add_subdirectory(util)
+add_subdirectory(socket)
+
+# JavaScript bindings
+add_subdirectory(js-elapsed-timer)
+add_subdirectory(js-line)
+add_subdirectory(js-point)
+add_subdirectory(js-rectangle)
+add_subdirectory(js-size)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-elapsed-timer/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-elapsed-timer
+	LIBRARIES libmlk-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-elapsed-timer/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,122 @@
+/*
+ * main.cpp -- test ElapsedTimer (JavaScript binding)
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <thread>
+
+#define BOOST_TEST_MODULE "Javascript ElapsedTimer"
+#include <boost/format.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/js/test/js_api_fixture.hpp>
+
+using boost::format;
+using boost::str;
+
+using namespace std::chrono_literals;
+
+namespace mlk {
+
+namespace {
+
+/*
+ * For all tests, we tolerate 30 ms because some systems have bigger lags.
+ */
+constexpr int margin = 30;
+
+void assert_range(int value, int expected)
+{
+	if (value < (expected - margin) || value > (expected + margin))
+		throw std::invalid_argument(
+			str(format("%d is bigger than [%d, %d]") % value % (expected - margin) % (expected + margin)));
+}
+
+BOOST_FIXTURE_TEST_SUITE(test_elapsed_timer_suite, js::test::js_api_fixture)
+
+BOOST_AUTO_TEST_CASE(standard)
+{
+	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	std::this_thread::sleep_for(300ms);
+
+	if (duk_peval_string(ctx_, "result = timer.elapsed();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "result");
+	assert_range(duk_to_int(ctx_, -1), 300);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(pause)
+{
+	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	/*
+	 * Simulate a pause in the game like this:
+	 *
+	 * start pause restart elapsed
+	 * |   10ms   |.5ms.| 6ms  |
+	 *
+	 * Since the game was paused, the 5ms must not be totalized.
+	 */
+	std::this_thread::sleep_for(10ms);
+
+	if (duk_peval_string(ctx_, "timer.pause();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	std::this_thread::sleep_for(5ms);
+
+	if (duk_peval_string(ctx_, "timer.restart();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	std::this_thread::sleep_for(6ms);
+
+	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "result");
+	assert_range(duk_to_int(ctx_, -1), 16);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(doublecheck)
+{
+	if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	std::this_thread::sleep_for(50ms);
+
+	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	std::this_thread::sleep_for(50ms);
+
+	if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "result");
+	assert_range(duk_to_int(ctx_, -1), 100);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-line/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-line
+	LIBRARIES libmlk-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-line/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,305 @@
+/*
+ * main.cpp -- test Line (JavaScript binding)
+ *
+ * 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 "Javascript Line"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/line.hpp>
+
+#include <malikania/js/test/js_api_fixture.hpp>
+
+namespace mlk {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(test_line_suite, js::test::js_api_fixture)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Line();"
+		"x1 = r.x1;"
+		"y1 = r.y1;"
+		"x2 = r.x2;"
+		"y2 = r.y2;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_4_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Line(10, 20, 30, 40);"
+		"x1 = r.x1;"
+		"y1 = r.y1;"
+		"x2 = r.x2;"
+		"y2 = r.y2;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });"
+		"x1 = r.x1;"
+		"y1 = r.y1;"
+		"x2 = r.x2;"
+		"y2 = r.y2;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = new Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });"
+		"x1 = r.x1;"
+		"y1 = r.y1;"
+		"x2 = r.x2;"
+		"y2 = r.y2;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 30);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 40);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(arg_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Line(null);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto line = mlk::js::duk::require<mlk::line>(ctx, 0);
+
+		duk_push_int(ctx, line.x1);
+		duk_put_global_string(ctx, "x1");
+		duk_push_int(ctx, line.y1);
+		duk_put_global_string(ctx, "y1");
+		duk_push_int(ctx, line.x2);
+		duk_put_global_string(ctx, "x2");
+		duk_push_int(ctx, line.y2);
+		duk_put_global_string(ctx, "y2");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 50);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 80);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::line>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  build({});"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto line = mlk::js::duk::get<mlk::line>(ctx, 0);
+
+		duk_push_int(ctx, line.x1);
+		duk_put_global_string(ctx, "x1");
+		duk_push_int(ctx, line.y1);
+		duk_put_global_string(ctx, "y1");
+		duk_push_int(ctx, line.x2);
+		duk_put_global_string(ctx, "x2");
+		duk_push_int(ctx, line.y2);
+		duk_put_global_string(ctx, "y2");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({});");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y1");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "x2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y2");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-point/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-point
+	LIBRARIES libmlk-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-point/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,253 @@
+/*
+ * main.cpp -- test Point (JavaScript binding)
+ *
+ * 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 "Javascript Point"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/point.hpp>
+
+#include <malikania/js/test/js_api_fixture.hpp>
+
+namespace mlk {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(test_point_suite, js::test::js_api_fixture)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"p = Malikania.Point();"
+		"x = p.x;"
+		"y = p.y;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_2_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"p = Malikania.Point(-10, -20);"
+		"x = p.x;"
+		"y = p.y;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == -10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == -20);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"p = Malikania.Point({ x: 100, y: 200 });"
+		"x = p.x;"
+		"y = p.y;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"p = new Malikania.Point({ x: 100, y: 200 });"
+		"x = p.x;"
+		"y = p.y;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Point(null);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto point = mlk::js::duk::require<mlk::point>(ctx, 0);
+
+		duk_push_int(ctx, point.x);
+		duk_put_global_string(ctx, "x");
+		duk_push_int(ctx, point.y);
+		duk_put_global_string(ctx, "y");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({ x: 100, y: 200 });");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 100);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 200);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::point>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  build({});"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto point = mlk::js::duk::get<mlk::point>(ctx, 0);
+
+		duk_push_int(ctx, point.x);
+		duk_put_global_string(ctx, "x");
+		duk_push_int(ctx, point.y);
+		duk_put_global_string(ctx, "y");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({});");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-rectangle/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-rectangle
+	LIBRARIES libmlk-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-rectangle/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,332 @@
+/*
+ * main.cpp -- test Rectangle (JavaScript binding)
+ *
+ * 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 "Javascript Rectangle"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/rectangle.hpp>
+
+#include <malikania/js/test/js_api_fixture.hpp>
+
+namespace mlk {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(test_rectangle_suite, js::test::js_api_fixture)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Rectangle();"
+		"x = r.x;"
+		"y = r.y;"
+		"w = r.width;"
+		"h = r.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_4_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Rectangle(10, 20, 30, 40);"
+		"x = r.x;"
+		"y = r.y;"
+		"w = r.width;"
+		"h = r.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });"
+		"x = r.x;"
+		"y = r.y;"
+		"w = r.width;"
+		"h = r.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"r = new Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });"
+		"x = r.x;"
+		"y = r.y;"
+		"w = r.width;"
+		"h = r.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 10);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 20);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 30U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 40U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Rectangle(null);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#if 0
+
+// TODO: determine what's the best thing to do with negative values
+
+BOOST_AUTO_TEST_CASE(constructor_range_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Rectangle(0, 0, -10, -10);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto rect = mlk::js::duk::require<mlk::rectangle>(ctx, 0);
+
+		duk_push_int(ctx, rect.x);
+		duk_put_global_string(ctx, "x");
+		duk_push_int(ctx, rect.y);
+		duk_put_global_string(ctx, "y");
+		duk_push_uint(ctx, rect.width);
+		duk_put_global_string(ctx, "w");
+		duk_push_uint(ctx, rect.height);
+		duk_put_global_string(ctx, "h");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({ x: 50, y: 80, width: 100, height: 200 });");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 50);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 80);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::rectangle>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  build({});"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto rect = mlk::js::duk::get<mlk::rectangle>(ctx, 0);
+
+		duk_push_int(ctx, rect.x);
+		duk_put_global_string(ctx, "x");
+		duk_push_int(ctx, rect.y);
+		duk_put_global_string(ctx, "y");
+		duk_push_uint(ctx, rect.width);
+		duk_put_global_string(ctx, "w");
+		duk_push_uint(ctx, rect.height);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({});");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "x");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "y");
+	BOOST_TEST(duk_to_int(ctx_, -1) == 0);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-size/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME js-size
+	LIBRARIES libmlk-js-test
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/js-size/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,345 @@
+/*
+ * main.cpp -- test Size (JavaScript binding)
+ *
+ * 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 "Javascript Size"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/js/test/js_api_fixture.hpp>
+
+namespace mlk {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(test_size_suite, js::test::js_api_fixture)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"s = Malikania.Size();"
+		"w = s.width;"
+		"h = s.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_2_args)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"s = Malikania.Size(100, 200);"
+		"w = s.width;"
+		"h = s.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"s = Malikania.Size({ width: 100, height: 200 });"
+		"w = s.width;"
+		"h = s.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"s = new Malikania.Size({ width: 100, height: 200 });"
+		"w = s.width;"
+		"h = s.height;"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Size(null);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#if 0
+
+// TODO: determine what's the best thing to do with negative values
+
+BOOST_AUTO_TEST_CASE(constructor_range_1)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Size(-1, 200);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_2)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Size(100, -1);"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_3)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Size({ width: -1, height: 200 });"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_4)
+{
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  Malikania.Size({ width: 100, height: -1 });"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof RangeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto size = mlk::js::duk::require<mlk::size>(ctx, 0);
+
+		duk_push_uint(ctx, size.width);
+		duk_put_global_string(ctx, "w");
+		duk_push_uint(ctx, size.height);
+		duk_put_global_string(ctx, "h");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({ width: 100, height: 200 });");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 100U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 200U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		mlk::js::duk::require<mlk::size>(ctx, 0);
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_,
+		"try {"
+		"  build({});"
+		"} catch (e) {"
+		"  name = e.name;"
+		"  correct = (e instanceof TypeError);"
+		"}"
+	);
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "name");
+	BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError");
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "correct");
+	BOOST_TEST(duk_to_boolean(ctx_, -1));
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	duk_push_c_function(ctx_, [] (auto ctx) {
+		const auto size = mlk::js::duk::get<mlk::size>(ctx, 0);
+
+		duk_push_uint(ctx, size.width);
+		duk_put_global_string(ctx, "w");
+		duk_push_uint(ctx, size.height);
+		duk_put_global_string(ctx, "h");
+
+		return 0;
+	}, 1);
+	duk_put_global_string(ctx_, "build");
+
+	const auto ret = duk_peval_string(ctx_, "build({});");
+
+	if (ret != 0)
+		throw mlk::js::duk::get_stack(ctx_, -1);
+
+	duk_get_global_string(ctx_, "w");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+	duk_get_global_string(ctx_, "h");
+	BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
+	duk_pop(ctx_);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/line/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME line
+	LIBRARIES libmlk-client
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/line/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * main.cpp -- test mlk::client::line
+ *
+ * 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 "Line"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/line.hpp>
+
+namespace mlk {
+
+auto operator<<(std::ostream& out, const line& line) -> std::ostream&
+{
+	out << "{";
+	out << line.x1 << ", " << line.y1 << ", ";
+	out << line.x2 << ", " << line.y2;
+	out << "}";
+
+	return out;
+}
+
+namespace {
+
+BOOST_AUTO_TEST_CASE(none)
+{
+	line line;
+
+	BOOST_TEST(line.x1 == 0);
+	BOOST_TEST(line.y1 == 0);
+	BOOST_TEST(line.x2 == 0);
+	BOOST_TEST(line.y2 == 0);
+}
+
+BOOST_AUTO_TEST_CASE(standard)
+{
+	line line{10, 20, 30, 40};
+
+	BOOST_TEST(line.x1 == 10);
+	BOOST_TEST(line.y1 == 20);
+	BOOST_TEST(line.x2 == 30);
+	BOOST_TEST(line.y2 == 40);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq)
+{
+	line line1, line2;
+
+	BOOST_TEST(line2 == line1);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq1)
+{
+	line line1{10, 20, 30, 40};
+	line line2{10, 20, 30, 40};
+
+	BOOST_TEST(line2 == line1);
+}
+
+BOOST_AUTO_TEST_CASE(operator_neq)
+{
+	BOOST_TEST((line{10} != line{20}));
+	BOOST_TEST((line{10, 10} != line{10, 20}));
+	BOOST_TEST((line{10, 10, 10} != line{10, 10, 20}));
+	BOOST_TEST((line{10, 10, 10, 10} != line{10, 10, 10, 20}));
+}
+
+} // !namespace
+
+} // !mlk::client
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/point/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME point
+	LIBRARIES libmlk-client
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/point/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * main.cpp -- test mlk::client::point
+ *
+ * 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 "Point"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/point.hpp>
+
+namespace mlk {
+
+auto operator<<(std::ostream& out, const point& point) -> std::ostream&
+{
+	out << "{" << point.x << ", " << point.y << "}";
+
+	return out;
+}
+
+namespace {
+
+BOOST_AUTO_TEST_CASE(none)
+{
+	point point;
+
+	BOOST_TEST(point.x == 0);
+	BOOST_TEST(point.y == 0);
+}
+
+BOOST_AUTO_TEST_CASE(standard)
+{
+	point point{10, 20};
+
+	BOOST_TEST(point.x == 10);
+	BOOST_TEST(point.y == 20);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq)
+{
+	point point1, point2;
+
+	BOOST_TEST(point1 == point2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq1)
+{
+	point point1{10, 20};
+	point point2{10, 20};
+
+	BOOST_TEST(point1 == point2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_neq)
+{
+	BOOST_TEST((point{10} != point{20}));
+	BOOST_TEST((point{10, 10} != point{10, 20}));
+}
+
+} // !namespace
+
+} // !mlk::client
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/rectangle/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME rectangle
+	LIBRARIES libmlk-client
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/rectangle/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * main.cpp -- test mlk::client::rectangle
+ *
+ * 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 "Rectangle"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/rectangle.hpp>
+
+namespace mlk {
+
+auto operator<<(std::ostream& out, const rectangle& rectangle) -> std::ostream&
+{
+	out << "{";
+	out << rectangle.width << ", " << rectangle.height << ", ";
+	out << rectangle.x << ", " << rectangle.y;
+	out << "}";
+
+	return out;
+}
+
+namespace {
+
+BOOST_AUTO_TEST_CASE(none)
+{
+	rectangle rectangle;
+
+	BOOST_TEST(rectangle.x == 0);
+	BOOST_TEST(rectangle.y == 0);
+	BOOST_TEST(rectangle.width == 0U);
+	BOOST_TEST(rectangle.height == 0U);
+}
+
+BOOST_AUTO_TEST_CASE(null)
+{
+	BOOST_TEST(rectangle().is_null());
+	BOOST_TEST((!rectangle{0, 0, 10, 0}.is_null()));
+	BOOST_TEST((!rectangle{0, 0, 0, 10}.is_null()));
+	BOOST_TEST((!rectangle{0, 0, 10, 10}.is_null()));
+}
+
+BOOST_AUTO_TEST_CASE(standard)
+{
+	rectangle rectangle{10, 20, 30, 40};
+
+	BOOST_TEST(rectangle.x == 10);
+	BOOST_TEST(rectangle.y == 20);
+	BOOST_TEST(rectangle.width == 30U);
+	BOOST_TEST(rectangle.height == 40U);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq)
+{
+	rectangle rectangle1, rectangle2;
+
+	BOOST_TEST(rectangle1 == rectangle2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq1)
+{
+	rectangle rectangle1{10, 20, 30, 40};
+	rectangle rectangle2{10, 20, 30, 40};
+
+	BOOST_TEST(rectangle1 == rectangle2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_neq)
+{
+	BOOST_TEST((rectangle{10} != rectangle{20}));
+	BOOST_TEST((rectangle{10, 10} != rectangle{10, 20}));
+	BOOST_TEST((rectangle{10, 10, 10} != rectangle{10, 10, 20}));
+	BOOST_TEST((rectangle{10, 10, 10, 10} != rectangle{10, 10, 10, 20}));
+}
+
+} // !namespace
+
+} // !mlk::client
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/size/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME size
+	LIBRARIES libmlk
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/size/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * main.cpp -- test size
+ *
+ * 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 "Size"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/size.hpp>
+
+namespace mlk {
+
+namespace {
+
+BOOST_AUTO_TEST_CASE(none)
+{
+	const size size;
+
+	BOOST_TEST(size.width == 0U);
+	BOOST_TEST(size.height == 0U);
+}
+
+BOOST_AUTO_TEST_CASE(null)
+{
+	BOOST_TEST(size().is_null());
+	BOOST_TEST((!size{0, 10}.is_null()));
+	BOOST_TEST((!size{10, 0}.is_null()));
+}
+
+BOOST_AUTO_TEST_CASE(standard)
+{
+	const size size{10, 20};
+
+	BOOST_TEST(size.width == 10U);
+	BOOST_TEST(size.height == 20U);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq)
+{
+	const size size1, size2;
+
+	BOOST_TEST(size1 == size2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq_1)
+{
+	const size size1{10, 20};
+	const size size2{10, 20};
+
+	BOOST_TEST(size1 == size2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_neq)
+{
+	BOOST_TEST((size{10} != size{20}));
+	BOOST_TEST((size{10, 10} != size{10, 20}));
+}
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/socket/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME socket
+	LIBRARIES libmlk
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/socket/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,167 @@
+/*
+ * main.cpp -- test socket
+ *
+ * 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 "socket"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/socket.hpp>
+
+using boost::asio::io_context;
+using boost::asio::ip::make_address;
+using boost::asio::ip::tcp;
+using boost::asio::ssl::context;
+using boost::asio::ssl::stream_base;
+
+namespace mlk {
+
+namespace {
+
+class socket_fixture {
+private:
+	auto init() -> context;
+	void handshake();
+	void pair();
+
+protected:
+	// SSL and Asio context.
+	context ssl_context_{init()};
+	io_context ctx_;
+
+	// two connected sockets.
+	socket server_{ctx_, ssl_context_};
+	socket client_{ctx_, ssl_context_};
+
+	socket_fixture();
+};
+
+auto socket_fixture::init() -> context
+{
+	context ret{context::sslv23};
+
+	ret.use_private_key_file(CMAKE_SOURCE_DIR "/tests/assets/test.key", context::pem);
+	ret.use_certificate_file(CMAKE_SOURCE_DIR "/tests/assets/test.crt", context::pem);
+
+	return ret;
+}
+
+void socket_fixture::handshake()
+{
+	server_.get_socket().async_handshake(stream_base::server, [] (auto code) {
+		if (code)
+			throw std::system_error(code);
+	});
+	client_.get_socket().async_handshake(stream_base::client, [] (auto code) {
+		if (code)
+			throw std::system_error(code);
+	});
+
+	ctx_.run();
+	ctx_.reset();
+}
+
+void socket_fixture::pair()
+{
+	tcp::acceptor acc(ctx_, tcp::endpoint(tcp::v4(), 0U));
+
+	acc.async_accept(server_.get_socket().lowest_layer(), [] (auto code) {
+		if (code)
+			throw std::system_error(code);
+	});
+
+	tcp::endpoint ep(make_address("127.0.0.1"), acc.local_endpoint().port());
+
+	client_.get_socket().lowest_layer().async_connect(ep, [] (auto code) {
+		if (code)
+			throw std::system_error(code);
+	});
+
+	ctx_.run();
+	ctx_.reset();
+}
+
+socket_fixture::socket_fixture()
+{
+	pair();
+	handshake();
+}
+
+BOOST_FIXTURE_TEST_SUITE(socket_suite, socket_fixture)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	server_.recv([] (auto code, auto json) {
+		BOOST_TEST(!code);
+		BOOST_TEST(json["hello"].template get<std::string>() == "world");
+	});
+	client_.send({{ "hello", "world" }}, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	ctx_.run();
+}
+
+BOOST_AUTO_TEST_CASE(multiple)
+{
+	server_.recv([] (auto code, auto json) {
+		BOOST_TEST(!code);
+		BOOST_TEST(json["hello"].template get<std::string>() == "world");
+	});
+	client_.send({{ "hello", "world" }}, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	ctx_.run();
+	ctx_.reset();
+
+	server_.recv([] (auto code, auto json) {
+		BOOST_TEST(!code);
+		BOOST_TEST(json["hello"].template get<std::string>() == "what's up?");
+	});
+	client_.send({{ "hello", "what's up?" }}, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	ctx_.run();
+}
+
+BOOST_AUTO_TEST_CASE(simple_then_too_big)
+{
+	std::string big(102400, 'a');
+
+	server_.recv([] (auto code, auto json) {
+		BOOST_TEST(!code);
+		BOOST_TEST(json["hello"].template get<std::string>() == "world");
+	});
+	client_.send({{ "hello", "world" }}, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	ctx_.run();
+	ctx_.reset();
+
+	server_.recv([] (auto code, auto json) {
+		BOOST_TEST(code.value() == static_cast<int>(std::errc::argument_list_too_long));
+		BOOST_TEST(json.is_null());
+	});
+	client_.send({{ "hello", std::move(big) }}, [] (auto code) {
+		BOOST_TEST(!code);
+	});
+	ctx_.run();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/util/CMakeLists.txt	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for malikania
+#
+# 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.
+#
+
+malikania_create_test(
+	NAME util
+	LIBRARIES libmlk
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libmlk/util/main.cpp	Sat Oct 27 07:16:28 2018 +0200
@@ -0,0 +1,468 @@
+/*
+ * main.cpp -- test util
+ *
+ * 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 "Util"
+#include <boost/test/unit_test.hpp>
+
+#include <malikania/util.hpp>
+#include <malikania/size.hpp>
+
+using namespace mlk;
+using namespace nlohmann;
+
+namespace nlohmann {
+
+namespace detail {
+
+auto operator<<(std::ostream& out, json::value_t type) -> std::ostream&
+{
+	out << json(type).type_name();
+	return out;
+}
+
+} // !detail
+
+} // !nlohmann
+
+/*
+ * util::clamp
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(clamp)
+
+BOOST_AUTO_TEST_CASE(normal)
+{
+	BOOST_REQUIRE_EQUAL(5, util::clamp(5, 0, 10));
+}
+
+BOOST_AUTO_TEST_CASE(minimum)
+{
+	BOOST_REQUIRE_EQUAL(0, util::clamp(0, 0, 10));
+}
+
+BOOST_AUTO_TEST_CASE(maximum)
+{
+	BOOST_REQUIRE_EQUAL(10, util::clamp(10, 0, 10));
+}
+
+BOOST_AUTO_TEST_CASE(less)
+{
+	BOOST_REQUIRE_EQUAL(0, util::clamp(-10, 0, 10));
+}
+
+BOOST_AUTO_TEST_CASE(higher)
+{
+	BOOST_REQUIRE_EQUAL(10, util::clamp(20, 0, 10));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "b", true },
+		{ "i", 123 },
+		{ "s", "blabla" }
+	};
+
+	BOOST_REQUIRE_EQUAL(util::json::require(
+		object, "/b"_json_pointer, json::value_t::boolean).type(), json::value_t::boolean);
+	BOOST_REQUIRE_EQUAL(util::json::require(
+		object, "/i"_json_pointer, json::value_t::number_integer).type(), json::value_t::number_integer);
+	BOOST_REQUIRE_EQUAL(util::json::require(
+		object, "/s"_json_pointer, json::value_t::string).type(), json::value_t::string);
+}
+
+BOOST_AUTO_TEST_CASE(nonexistent)
+{
+	auto json = json::object();
+
+	try {
+		util::json::require(json, "/non-existent"_json_pointer, json::value_t::string);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::null);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
+	}
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-string", 123 }
+	};
+
+	try {
+		util::json::require(object, "/not-string"_json_pointer, json::value_t::string);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_array
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_array)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "a", { 1, 2, 3 } },
+		{ "l1", {
+				{ "l2", { 4, 5, 6 } }
+			}
+		}
+	};
+
+	auto a = util::json::require_array(object, "/a"_json_pointer);
+	auto l2 = util::json::require_array(object, "/l1/l2"_json_pointer);
+
+	BOOST_REQUIRE(a.is_array());
+	BOOST_REQUIRE(l2.is_array());
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-array", 123 }
+	};
+
+	try {
+		util::json::require_array(object, "/not-array"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::array);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_bool
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_bool)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "b", true }
+	};
+
+	BOOST_REQUIRE_EQUAL(util::json::require_bool(object, "/b"_json_pointer), true);
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-bool", 123 }
+	};
+
+	try {
+		util::json::require_bool(object, "/not-bool"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::boolean);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_int
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_int)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "i", 123 }
+	};
+
+	BOOST_REQUIRE_EQUAL(util::json::require_int(object, "/i"_json_pointer), 123);
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-int", true }
+	};
+
+	try {
+		util::json::require_int(object, "/not-int"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::boolean);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_integer);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_object
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_object)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{
+			"network", json::object({
+				{ "host", "localhost" },
+				{ "port", 9090 }
+			})
+		}
+	};
+
+	BOOST_REQUIRE(util::json::require_object(object, "/network"_json_pointer).is_object());
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-object", 123 }
+	};
+
+	try {
+		util::json::require_object(object, "/not-object"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::object);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_string
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_string)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "s", "hello" }
+	};
+
+	BOOST_REQUIRE_EQUAL(util::json::require_string(object, "/s"_json_pointer), "hello");
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-string", 123 }
+	};
+
+	try {
+		util::json::require_string(object, "/not-string"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::number_integer);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::string);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::json::require_uint
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(json_require_uint)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "u1", 123U }
+	};
+
+	BOOST_REQUIRE_EQUAL(util::json::require_uint(object, "/u1"_json_pointer), 123U);
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	json object{
+		{ "not-uint", true }
+	};
+
+	try {
+		util::json::require_uint(object, "/not-uint"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::boolean);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(json_require_size)
+
+/*
+ * util::json::require_size
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "size", {
+				{ "width", 10 },
+				{ "height", 20 }
+			}
+		}
+	};
+
+	BOOST_TEST((util::json::require_size(object, "/size"_json_pointer) == mlk::size{10, 20}));
+}
+
+BOOST_AUTO_TEST_CASE(not_object)
+{
+	json object{
+		{ "size", false }
+	};
+
+	try {
+		util::json::require_size(object, "/size"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::null);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
+	}
+}
+
+BOOST_AUTO_TEST_CASE(not_int_width)
+{
+	json object{
+		{ "size", {
+				{ "width", "10" },
+				{ "height", 20 }
+			}
+		}
+	};
+
+	try {
+		util::json::require_size(object, "/size"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::string);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
+	}
+}
+
+BOOST_AUTO_TEST_CASE(not_int_height)
+{
+	json object{
+		{ "size", {
+				{ "width", 10 },
+				{ "height", "20" }
+			}
+		}
+	};
+
+	try {
+		util::json::require_size(object, "/size"_json_pointer);
+		BOOST_FAIL("exception expected");
+	} catch (const util::json::property_error& ex) {
+		BOOST_REQUIRE_EQUAL(ex.type(), json::value_t::string);
+		BOOST_REQUIRE_EQUAL(ex.expected(), json::value_t::number_unsigned);
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(json_get_size)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	json object{
+		{ "size", {
+				{ "width", 10 },
+				{ "height", 20 }
+			}
+		}
+	};
+
+	BOOST_TEST((util::json::get_size(object, "/size"_json_pointer) == mlk::size{10, 20}));
+}
+
+BOOST_AUTO_TEST_CASE(not_object)
+{
+	const json object{{ "size", false }};
+	const mlk::size def{10, 20};
+
+	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
+}
+
+BOOST_AUTO_TEST_CASE(not_int_width)
+{
+	const json object{
+		{ "size", {
+				{ "width", "10" },
+				{ "height", 20 }
+			}
+		}
+	};
+
+	const mlk::size def{10, 20};
+
+	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
+}
+
+BOOST_AUTO_TEST_CASE(not_int_height)
+{
+	const json object{
+		{ "size", {
+				{ "width", 10 },
+				{ "height", "20" }
+			}
+		}
+	};
+
+	const mlk::size def{10, 20};
+
+	BOOST_TEST(util::json::get_size(object, "/size"_json_pointer, def) == def);
+}
+
+BOOST_AUTO_TEST_SUITE_END()