changeset 186:16ff680a8a94

Common: move point, line and rectangle, closes #913 @30m
author David Demelier <markand@malikania.fr>
date Sat, 20 Oct 2018 21:12:20 +0200
parents 975dffc6567a
children eaa7f85bfc22
files examples/animation/main.cpp examples/font/main.cpp examples/image/main.cpp examples/sprite/main.cpp libclient-js/CMakeLists.txt libclient-js/malikania/js_line.cpp libclient-js/malikania/js_line.hpp libclient-js/malikania/js_point.cpp libclient-js/malikania/js_point.hpp libclient-js/malikania/js_rectangle.cpp libclient-js/malikania/js_rectangle.hpp libclient-js/malikania/js_window.cpp libclient/CMakeLists.txt libclient/malikania/client/animator.hpp libclient/malikania/client/line.hpp libclient/malikania/client/point.hpp libclient/malikania/client/rectangle.hpp libclient/malikania/client/sprite.hpp libclient/malikania/client/theme.hpp libclient/malikania/client/window.hpp libcommon-js/CMakeLists.txt libcommon-js/malikania/js_line.cpp libcommon-js/malikania/js_line.hpp libcommon-js/malikania/js_point.cpp libcommon-js/malikania/js_point.hpp libcommon-js/malikania/js_rectangle.cpp libcommon-js/malikania/js_rectangle.hpp libcommon/CMakeLists.txt libcommon/malikania/line.hpp libcommon/malikania/point.hpp libcommon/malikania/rectangle.hpp tests/libclient/CMakeLists.txt tests/libclient/js-line/CMakeLists.txt tests/libclient/js-line/main.cpp tests/libclient/js-point/CMakeLists.txt tests/libclient/js-point/main.cpp tests/libclient/js-rectangle/CMakeLists.txt tests/libclient/js-rectangle/main.cpp tests/libclient/line/CMakeLists.txt tests/libclient/line/main.cpp tests/libclient/point/CMakeLists.txt tests/libclient/point/main.cpp tests/libclient/rectangle/CMakeLists.txt tests/libclient/rectangle/main.cpp tests/libcommon/CMakeLists.txt 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/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
diffstat 57 files changed, 2332 insertions(+), 2323 deletions(-) [+]
line wrap: on
line diff
--- a/examples/animation/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/examples/animation/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -25,9 +25,9 @@
 #include <malikania/client/animator.hpp>
 #include <malikania/client/loader.hpp>
 #include <malikania/client/window.hpp>
-#include <malikania/client/point.hpp>
 
 #include <malikania/locator.hpp>
+#include <malikania/point.hpp>
 
 int main()
 {
@@ -45,7 +45,7 @@
 
 		while (timer.elapsed().wall / 1000000LL < 8000) {
 			win.clear();
-			animator.draw(win, mlk::client::point{x, y});
+			animator.draw(win, {x, y});
 			animator.update();
 			win.present();
 		}
--- a/examples/font/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/examples/font/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -23,11 +23,11 @@
 #include <malikania/client/loader.hpp>
 #include <malikania/client/color.hpp>
 #include <malikania/client/font.hpp>
-#include <malikania/client/point.hpp>
 #include <malikania/client/window.hpp>
 
+#include <malikania/locator.hpp>
+#include <malikania/point.hpp>
 #include <malikania/size.hpp>
-#include <malikania/locator.hpp>
 
 using namespace std::chrono_literals;
 
@@ -36,7 +36,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("top left", font, mlk::client::point{10, 10});
+	window.draw_text("top left", font, {10, 10});
 	window.present();
 
 	std::this_thread::sleep_for(1s);
@@ -49,7 +49,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("top right", font, mlk::client::point{
+	window.draw_text("top right", font, {
 		static_cast<int>(400 - dim.width - 10),
 		static_cast<int>(10)
 	});
@@ -65,7 +65,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("bottom left", font, mlk::client::point{
+	window.draw_text("bottom left", font, {
 		static_cast<int>(10),
 		static_cast<int>(400 - dim.height - 10)
 	});
@@ -81,7 +81,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("bottom right", font, mlk::client::point{
+	window.draw_text("bottom right", font, {
 		static_cast<int>(400 - dim.width - 10),
 		static_cast<int>(400 - dim.height - 10)
 	});
@@ -97,7 +97,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("center", font, mlk::client::point{
+	window.draw_text("center", font, {
 		static_cast<int>(200 - (dim.width / 2)),
 		static_cast<int>(200 - (dim.height -2))
 	});
@@ -113,7 +113,7 @@
 	window.set_drawing_color(mlk::client::color::from_name("black"));
 	window.clear();
 	window.set_drawing_color(mlk::client::color::from_name("white"));
-	window.draw_text("The world is Malikania.", font, mlk::client::point{
+	window.draw_text("The world is Malikania.", font, {
 		static_cast<int>(200 - (dim.width / 2)),
 		static_cast<int>(200 - (dim.height -2))
 	});
--- a/examples/image/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/examples/image/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -35,7 +35,7 @@
 		auto y = (400 / 2) - (image.get_size().height / 2);
 
 		window.clear();
-		image.draw(window, mlk::client::point{
+		image.draw(window, {
 			static_cast<int>(x),
 			static_cast<int>(y)
 		});
--- a/examples/sprite/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/examples/sprite/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -37,7 +37,7 @@
 
 	for (unsigned c = 0; c < total; ++c) {
 		window.clear();
-		sprite.draw(window, c, mlk::client::point{
+		sprite.draw(window, c, {
 		static_cast<int>(x),
 		static_cast<int>(y)
 	});
--- a/libclient-js/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient-js/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -26,9 +26,6 @@
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_color.hpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_font.hpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_image.hpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_line.hpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_point.hpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_rectangle.hpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_sprite.hpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_window.hpp
 )
@@ -41,9 +38,6 @@
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_color.cpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_font.cpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_image.cpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_line.cpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_point.cpp
-	${libmlk-client-js_SOURCE_DIR}/malikania/js_rectangle.cpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_sprite.cpp
 	${libmlk-client-js_SOURCE_DIR}/malikania/js_window.cpp
 )
--- a/libclient-js/malikania/js_line.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * js_line.cpp -- line description (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 <cassert>
-
-#include "js_line.hpp"
-
-namespace mlk::client {
-
-namespace {
-
-auto constructor(duk_context* ctx) -> duk_ret_t
-{
-	line obj;
-
-	if (duk_get_top(ctx) == 4) {
-		obj = line{
-			duk_get_int(ctx, 0),
-			duk_get_int(ctx, 1),
-			duk_get_int(ctx, 2),
-			duk_get_int(ctx, 3)
-		};
-	} else if (duk_get_top(ctx) == 1)
-		obj = dukx_require_line(ctx, 0);
-
-	duk_ret_t ret;
-
-	// Allow both constructor and non constructor calls.
-	if (duk_is_constructor_call(ctx)) {
-		duk_push_this(ctx);
-		dukx_put_line(ctx, obj);
-		ret = 0;
-	} else {
-		dukx_push_line(ctx, obj);
-		ret = 1;
-	}
-
-	return ret;
-}
-
-} // !namespace
-
-auto dukx_get_line(duk_context* ctx, duk_idx_t index) -> line
-{
-	const auto get = [&] (auto name) {
-		dukx_stack_assert sa(ctx);
-
-		duk_get_prop_string(ctx, index, name);
-		auto v = duk_get_int(ctx, -1);
-		duk_pop(ctx);
-
-		return v;
-	};
-
-	return line{get("x1"), get("y1"), get("x2"), get("y2")};
-}
-
-auto dukx_require_line(duk_context* ctx, duk_idx_t index) -> line
-{
-	auto get = [&] (auto prop) {
-		if (!duk_has_prop_string(ctx, index, prop))
-			duk_error(ctx, DUK_ERR_ERROR, "missing %s property in line description", prop);
-
-		duk_get_prop_string(ctx, index, prop);
-
-		if (!duk_is_number(ctx, -1)) {
-			duk_pop(ctx);
-			duk_error(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", prop);
-		}
-
-		auto value = duk_to_int(ctx, -1);
-
-		duk_pop(ctx);
-
-		return value;
-	};
-
-	return line{get("x1"), get("y1"), get("x2"), get("y2")};
-}
-
-auto dukx_optional_line(duk_context* ctx, duk_idx_t index, line def) -> line
-{
-	return duk_is_object(ctx, index) ? dukx_get_line(ctx, index) : def;
-}
-
-void dukx_push_line(duk_context* ctx, const line& line)
-{
-	dukx_stack_assert sa(ctx, 1);
-
-	duk_push_object(ctx);
-	dukx_put_line(ctx, line);
-}
-
-void dukx_put_line(duk_context* ctx, const line& line)
-{
-	assert(duk_is_object(ctx, -1));
-
-	dukx_stack_assert sa(ctx);
-
-	duk_push_int(ctx, line.x1);
-	duk_put_prop_string(ctx, -2, "x1");
-	duk_push_int(ctx, line.y1);
-	duk_put_prop_string(ctx, -2, "y1");
-	duk_push_int(ctx, line.x2);
-	duk_put_prop_string(ctx, -2, "x2");
-	duk_push_int(ctx, line.y2);
-	duk_put_prop_string(ctx, -2, "y2");
-}
-
-void dukx_load_line(duk_context* ctx)
-{
-	dukx_stack_assert sa(ctx, 0);
-
-	duk_get_global_string(ctx, "Malikania");
-	duk_push_c_function(ctx, constructor, DUK_VARARGS);
-	duk_put_prop_string(ctx, -2, "Line");
-	duk_pop(ctx);
-}
-
-} // !mlk::client
--- a/libclient-js/malikania/js_line.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * js_line.hpp -- line description (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.
- */
-
-#ifndef MALIKANIA_JS_LINE_HPP
-#define MALIKANIA_JS_LINE_HPP
-
-/**
- * \file js_line.hpp
- * \brief JavaScript binding for line.
- *
- * lines are plain objects.
- *
- * ````
- * {
- *   x1: 10,
- *   y1: 10,
- *   x2: 50,
- *   y2: 50
- * }
- * ````
- */
-
-#include <malikania/duktape.hpp>
-#include <malikania/client/line.hpp>
-
-namespace mlk::client {
-
-/**
- * Get a line.
- *
- * \param ctx the context
- * \param index the index
- * \return the line
- */
-auto dukx_get_line(duk_context* ctx, duk_idx_t index) -> line;
-
-/**
- * Require a line.
- *
- * If value is not an object or any property is invalid, raise a JavaScript error.
- *
- * \param ctx the context
- * \param index the index
- * \return the line
- */
-auto dukx_require_line(duk_context* ctx, duk_idx_t index) -> line;
-
-/**
- * Like get but return def if the value at the given index is not an object.
- *
- * \param ctx the context
- * \param index the index
- * \param def the default value
- * \return the line
- */
-auto dukx_optional_line(duk_context* ctx, duk_idx_t index, line def) -> line;
-
-/**
- * Push the line as object.
- *
- * \param ctx the context
- * \param line the line
- */
-void dukx_push_line(duk_context* ctx, const line &line);
-
-/**
- * Put the line properties into the object at the top of the stack.
- *
- * \param ctx the context
- * \param line the line
- */
-void dukx_put_line(duk_context* ctx, const line &line);
-
-void dukx_load_line(duk_context* ctx);
-
-} // !mlk::client
-
-#endif // !MALIKANIA_JS_LINE_HPP
--- a/libclient-js/malikania/js_point.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * js_point.cpp -- point description (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 <cassert>
-
-#include "js_point.hpp"
-
-namespace mlk::client {
-
-namespace {
-
-auto parse(duk_context* ctx, duk_idx_t index, bool required, point ret = {}) -> point
-{
-	dukx_stack_assert sa(ctx);
-
-	if (duk_is_object(ctx, index)) {
-		if (required && !duk_has_prop_string(ctx, index, "x"))
-			duk_error(ctx, DUK_ERR_ERROR, "missing x property in point description");
-		else if (required && !duk_has_prop_string(ctx, index, "y"))
-			duk_error(ctx, DUK_ERR_ERROR, "missing y property in point description");
-
-		int x;
-		int y;
-
-		duk_get_prop_string(ctx, index, "x");
-		x = duk_to_int(ctx, -1);
-		duk_pop(ctx);
-		duk_get_prop_string(ctx, index, "y");
-		y = duk_to_int(ctx, -1);
-		duk_pop(ctx);
-
-		ret = point{x, y};
-	} else if (required)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "point object expected");
-
-	return ret;
-}
-
-auto constructor(duk_context* ctx) -> duk_ret_t
-{
-	point obj;
-
-	if (duk_get_top(ctx) == 2)
-		obj = point{duk_require_int(ctx, 0), duk_require_int(ctx, 1)};
-	else if (duk_get_top(ctx) == 1)
-		obj = parse(ctx, 0, true);
-
-	duk_ret_t ret;
-
-	// Allow both constructor and non constructor calls.
-	if (duk_is_constructor_call(ctx)) {
-		duk_push_this(ctx);
-		dukx_put_point(ctx, obj);
-		duk_pop(ctx);
-		ret = 0;
-	} else {
-		dukx_push_point(ctx, obj);
-		ret = 1;
-	}
-
-	return ret;
-}
-
-} // !namespace
-
-auto dukx_get_point(duk_context* ctx, duk_idx_t index) -> point
-{
-	return parse(ctx, index, false);
-}
-
-auto dukx_require_point(duk_context* ctx, duk_idx_t index) -> point
-{
-	return parse(ctx, index, true);
-}
-
-auto dukx_optional_point(duk_context* ctx, duk_idx_t index, point def) -> point
-{
-	return parse(ctx, index, false, std::move(def));
-}
-
-void dukx_push_point(duk_context* ctx, const point &point)
-{
-	dukx_stack_assert sa(ctx, 1);
-
-	duk_push_object(ctx);
-	dukx_put_point(ctx, point);
-}
-
-void dukx_put_point(duk_context* ctx, const point& point)
-{
-	assert(duk_is_object(ctx, -1));
-
-	dukx_stack_assert sa(ctx);
-
-	duk_push_int(ctx, point.x);
-	duk_put_prop_string(ctx, -2, "x");
-	duk_push_int(ctx, point.y);
-	duk_put_prop_string(ctx, -2, "y");
-}
-
-void dukx_load_point(duk_context* ctx)
-{
-	dukx_stack_assert sa(ctx, 0);
-
-	duk_get_global_string(ctx, "Malikania");
-	duk_push_c_function(ctx, constructor, DUK_VARARGS);
-	duk_put_prop_string(ctx, -2, "Point");
-	duk_pop(ctx);
-}
-
-} // !mlk::client
--- a/libclient-js/malikania/js_point.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * js_point.hpp -- point description (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.
- */
-
-#ifndef MALIKANIA_JS_POINT_HPP
-#define MALIKANIA_JS_POINT_HPP
-
-#include <malikania/client/point.hpp>
-#include <malikania/duktape.hpp>
-
-namespace mlk::client {
-
-auto dukx_require_point(duk_context* ctx, duk_idx_t index) -> point;
-
-auto dukx_get_point(duk_context* ctx, duk_idx_t index) -> point;
-
-void dukx_push_point(duk_context* ctx, const point& point);
-
-void dukx_put_point(duk_context* ctx, const point& point);
-
-void dukx_load_point(duk_context* ctx);
-
-} // !mlk::client
-
-#endif // !MALIKANIA_JS_POINT_HPP
--- a/libclient-js/malikania/js_rectangle.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * js_rectangle.cpp -- rectangle description (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 <cassert>
-
-#include "js_rectangle.hpp"
-
-namespace mlk::client {
-
-namespace {
-
-auto clamp(duk_context* ctx, int value, bool required) -> unsigned
-{
-    if (value < 0) {
-        if (required)
-            duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d can not be negative", value);
-        else
-            value = 0;
-    }
-
-    return static_cast<unsigned>(value);
-}
-
-auto parse(duk_context* ctx, duk_idx_t index, bool required, rectangle rect = {}) -> rectangle
-{
-    dukx_stack_assert sa(ctx);
-
-    if (duk_is_object(ctx, index)) {
-        auto get = [&] (auto prop) {
-            if (required && !duk_has_prop_string(ctx, index, prop))
-                duk_error(ctx, DUK_ERR_ERROR, "missing '%s' property", prop);
-
-            duk_get_prop_string(ctx, index, prop);
-
-            if (required && !duk_is_number(ctx, -1)) {
-                duk_pop(ctx);
-                duk_error(ctx, DUK_ERR_ERROR, "invalid '%s' property (number expected)", prop);
-            }
-
-            auto value = duk_to_int(ctx, -1);
-
-            duk_pop(ctx);
-
-            return value;
-        };
-
-        rect = rectangle{get("x"), get("y"),
-            clamp(ctx, get("width"), required), clamp(ctx, get("height"), required)};
-    } else if (required)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "rectangle object expected");
-
-    return rect;
-}
-
-auto constructor(duk_context* ctx) -> duk_ret_t
-{
-    rectangle rect;
-
-    if (duk_get_top(ctx) == 4) {
-        rect = rectangle{
-            duk_require_int(ctx, 0),
-            duk_require_int(ctx, 1),
-            clamp(ctx, duk_require_int(ctx, 2), true),
-            clamp(ctx, duk_require_int(ctx, 3), true)
-        };
-    } else if (duk_get_top(ctx) == 1)
-        rect = parse(ctx, 0, true);
-
-    duk_ret_t ret;
-
-    // Allow both constructor and non constructor calls.
-    if (duk_is_constructor_call(ctx)) {
-        duk_push_this(ctx);
-        dukx_put_rect(ctx, rect);
-        duk_pop(ctx);
-        ret = 0;
-    } else {
-        dukx_push_rect(ctx, rect);
-        ret = 1;
-    }
-
-    return ret;
-}
-
-} // !namespace
-
-auto dukx_get_rect(duk_context* ctx, duk_idx_t index) -> rectangle
-{
-    return parse(ctx, index, false);
-}
-
-auto dukx_require_rect(duk_context* ctx, duk_idx_t index) -> rectangle
-{
-    return parse(ctx, index, true);
-}
-
-auto dukx_optional_rect(duk_context* ctx, duk_idx_t index, rectangle def) -> rectangle
-{
-    return parse(ctx, index, false, std::move(def));
-}
-
-void dukx_push_rect(duk_context* ctx, const rectangle& rect)
-{
-    dukx_stack_assert sa(ctx, 1);
-
-    duk_push_object(ctx);
-    dukx_put_rect(ctx, rect);
-}
-
-void dukx_put_rect(duk_context* ctx, const rectangle& rect)
-{
-    assert(duk_is_object(ctx, -1));
-
-    dukx_stack_assert sa(ctx);
-
-    duk_push_int(ctx, rect.x);
-    duk_put_prop_string(ctx, -2, "x");
-    duk_push_int(ctx, rect.y);
-    duk_put_prop_string(ctx, -2, "y");
-    duk_push_uint(ctx, rect.width);
-    duk_put_prop_string(ctx, -2, "width");
-    duk_push_uint(ctx, rect.height);
-    duk_put_prop_string(ctx, -2, "height");
-}
-
-void dukx_load_rect(duk_context* ctx)
-{
-    dukx_stack_assert sa(ctx, 0);
-
-    duk_get_global_string(ctx, "Malikania");
-    duk_push_c_function(ctx, constructor, DUK_VARARGS);
-    duk_put_prop_string(ctx, -2, "Rectangle");
-    duk_pop(ctx);
-}
-
-} // !mlk::client
--- a/libclient-js/malikania/js_rectangle.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/*
- * js_rectangle.hpp -- rectangle description (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.
- */
-
-#ifndef MALIKANIA_JS_RECTANGLE_HPP
-#define MALIKANIA_JS_RECTANGLE_HPP
-
-/**
- * \file js_rectangle.hpp
- * \brief JavaScript binding for rectangle.
- *
- * rectangles are plain objects.
- *
- * ````
- * {
- *   x: 10,
- *   y: 20,
- *   width: 100,
- *   height: 200
- * }
- * ````
- */
-
-#include <malikania/client/rectangle.hpp>
-#include <malikania/duktape.hpp>
-
-namespace mlk::client {
-
-/**
- * Get a rectangle.
- *
- * The rectangle may be adjusted if any values are incorrect.
- *
- * \param ctx the context
- * \param index the value index
- * \return the rectangle
- */
-auto dukx_get_rect(duk_context* ctx, duk_idx_t index) -> rectangle;
-
-/**
- * Require a rectangle.
- *
- * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error.
- *
- * \param ctx the context
- * \param index the index
- * \return the rectangle
- */
-auto dukx_require_rect(duk_context* ctx, duk_idx_t index) -> rectangle;
-
-/**
- * Like get but return the default value if the value at the given index is not an object or invalid
- *
- * \param ctx the context
- * \param index the idnex
- * \param def the default value
- * \return the rectangle
- */
-auto dukx_optional_rect(duk_context* ctx, duk_idx_t index, rectangle def) -> rectangle;
-
-/**
- * Push the rectangle as object.
- *
- * \param ctx the context
- * \param rect the rectangle
- */
-void dukx_push_rect(duk_context* ctx, const rectangle &rect);
-
-/**
- * Put the rectangle properties into the object at the top of the stack.
- *
- * \param ctx the context
- * \param rect the rectangle
- */
-void dukx_put_rect(duk_context* ctx, const rectangle& rect);
-
-void dukx_load_rect(duk_context* ctx);
-
-} // !mlk::client
-
-#endif // !MALIKANIA_JS_RECTANGLE_HPP
--- a/libclient-js/malikania/js_window.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient-js/malikania/js_window.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -144,7 +144,7 @@
 		if (!rect.is_null())
 			win.draw_text(text, font, rect);
 		else
-			win.draw_text(text, font, client::point{rect.x, rect.y});
+			win.draw_text(text, font, point{rect.x, rect.y});
 	} catch (const std::exception &ex) {
 		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
 	}
--- a/libclient/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -33,11 +33,8 @@
 	${libmlk-client_SOURCE_DIR}/malikania/client/image.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/key.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/label.hpp
-	${libmlk-client_SOURCE_DIR}/malikania/client/line.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/loader.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/mouse.hpp
-	${libmlk-client_SOURCE_DIR}/malikania/client/point.hpp
-	${libmlk-client_SOURCE_DIR}/malikania/client/rectangle.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/sdl_util.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/sprite.hpp
 	${libmlk-client_SOURCE_DIR}/malikania/client/state.hpp
--- a/libclient/malikania/client/animator.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient/malikania/client/animator.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -26,10 +26,13 @@
  * \brief Draw animations.
  */
 
-namespace mlk::client {
+namespace mlk {
+
+struct point;
+
+namespace client {
 
 struct animation;
-struct point;
 
 class window;
 
@@ -75,6 +78,8 @@
 	void draw(window& window, const point& position);
 };
 
-} // !mlk::client
+} // !client
+
+} // !mlk
 
 #endif // !MALIKANIA_CLIENT_ANIMATOR_HPP
--- a/libclient/malikania/client/line.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * line.hpp -- line description
- *
- * 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.
- */
-
-#ifndef MALIKANIA_CLIENT_LINE_HPP
-#define MALIKANIA_CLIENT_LINE_HPP
-
-/**
- * \file line.hpp
- * \brief line description.
- */
-
-namespace mlk::client {
-
-/**
- * \brief line description.
- *
- * A line has an origin (x, y) and a destination (x, y).
- */
-struct line {
-	int x1{0};
-	int y1{0};
-	int x2{0};
-	int y2{0};
-};
-
-/**
- * Compare equality.
- *
- * \param l1 the first line
- * \param l2 the second line
- * \return true if they equal
- */
-inline auto operator==(const line& l1, const line& l2) noexcept -> bool
-{
-	return l1.x1 == l2.x1 && l1.x2 == l2.x2 &&
-	       l1.y1 == l2.y1 && l1.y2 == l2.y2;
-}
-
-/**
- * Compare equality.
- *
- * \param l1 the first line
- * \param l2 the second line
- * \return false if they equal
- */
-inline auto operator!=(const line& l1, const line& l2) noexcept -> bool
-{
-	return !(l1 == l2);
-}
-
-} // !mlk::client
-
-#endif // !MALIKANIA_CLIENT_LINE_HPP
--- a/libclient/malikania/client/point.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * point.hpp -- point description
- *
- * 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.
- */
-
-#ifndef MALIKANIA_CLIENT_POINT_HPP
-#define MALIKANIA_CLIENT_POINT_HPP
-
-/**
- * \file point.hpp
- * \brief point description.
- */
-
-namespace mlk::client {
-
-/**
- * \brief point coordinate.
- */
-struct point {
-    int x{0};
-    int y{0};
-};
-
-/**
- * Compare equality.
- *
- * \param p1 the first point
- * \param p2 the second point
- * \return true if they equal
- */
-inline bool operator==(const point& p1, const point& p2) noexcept
-{
-    return p1.x == p2.x && p1.y == p2.y;
-}
-
-/**
- * Compare equality.
- *
- * \param p1 the first point
- * \param p2 the second point
- * \return false if they equal
- */
-inline bool operator!=(const point& p1, const point& p2) noexcept
-{
-    return !(p1 == p2);
-}
-
-} // !mlk::client
-
-#endif // !MALIKANIA_CLIENT_POINT_HPP
--- a/libclient/malikania/client/rectangle.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * rectangle.hpp -- rectangle description
- *
- * 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.
- */
-
-#ifndef MALIKANIA_CLIENT_RECTANGLE_HPP
-#define MALIKANIA_CLIENT_RECTANGLE_HPP
-
-/**
- * \file rectangle.hpp
- * \brief rectangle description.
- */
-
-namespace mlk::client {
-
-/**
- * \brief rectangle description.
- *
- * A rectangle has coordinates (x, y) and dimensions (width, height).
- *
- * They are commonly used for clipping images into the window.
- */
-struct rectangle {
-	int x{0};                       //!< x coordinate
-	int y{0};                       //!< y coordinate
-	unsigned width{0};              //!< width
-	unsigned height{0};             //!< height
-
-	/**
-	 * Check if the rectangle has null dimensions.
-	 *
-	 * \return true if weight and height are 0
-	 */
-	inline auto is_null() const noexcept -> bool
-	{
-		return width == 0 && height == 0;
-	}
-};
-
-/**
- * Compare equality.
- *
- * \param r1 the first rectangle
- * \param r2 the second rectangle
- * \return true if they equal
- */
-inline auto operator==(const rectangle& r1, const rectangle& r2) noexcept -> bool
-{
-	return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height;
-}
-
-/**
- * Compare equality.
- *
- * \param r1 the first rectangle
- * \param r2 the second rectangle
- * \return false if they equal
- */
-inline auto operator!=(const rectangle& r1, const rectangle& r2) noexcept -> bool
-{
-	return !(r1 == r2);
-}
-
-} // !mlk::client
-
-#endif // !MALIKANIA_CLIENT_RECTANGLE_HPP
--- a/libclient/malikania/client/sprite.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient/malikania/client/sprite.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -26,7 +26,11 @@
 
 #include "image.hpp"
 
-namespace mlk::client {
+namespace mlk {
+
+struct point;
+
+namespace client {
 
 /**
  * \brief A Sprite is an image divided into cells.
@@ -125,6 +129,8 @@
 	void draw(window& window, unsigned cell, const point& position);
 };
 
-} // !mlk::client
+} // !client
+
+} // !mlk
 
 #endif // !MALIKANIA_CLIENT_SPRITE_HPP
--- a/libclient/malikania/client/theme.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient/malikania/client/theme.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -33,7 +33,6 @@
 namespace mlk {
 
 struct rectangle;
-struct point;
 
 namespace client {
 
--- a/libclient/malikania/client/window.hpp	Sat Oct 20 20:38:43 2018 +0200
+++ b/libclient/malikania/client/window.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -34,6 +34,7 @@
 namespace mlk {
 
 struct line;
+struct point;
 struct rectangle;
 
 namespace client {
@@ -50,7 +51,6 @@
 	std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> window_{nullptr, nullptr};
 	std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer *)> renderer_{nullptr, nullptr};
 
-
 	bool is_open_{true};
 	bool is_editing_{false};
 
--- a/libcommon-js/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/libcommon-js/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -22,6 +22,9 @@
     HEADERS
     ${libmlk-common-js_SOURCE_DIR}/malikania/duktape.hpp
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_elapsed_timer.hpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_line.hpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_point.hpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_rectangle.hpp
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_resources_loader.hpp
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_size.hpp
 )
@@ -29,6 +32,9 @@
 set(
     SOURCES
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_elapsed_timer.cpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_line.cpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_point.cpp
+    ${libmlk-common-js_SOURCE_DIR}/malikania/js_rectangle.cpp
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_resources_loader.cpp
     ${libmlk-common-js_SOURCE_DIR}/malikania/js_size.cpp
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_line.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,135 @@
+/*
+ * js_line.cpp -- line description (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 <cassert>
+
+#include "js_line.hpp"
+
+namespace mlk {
+
+namespace {
+
+auto constructor(duk_context* ctx) -> duk_ret_t
+{
+	line obj;
+
+	if (duk_get_top(ctx) == 4) {
+		obj = line{
+			duk_get_int(ctx, 0),
+			duk_get_int(ctx, 1),
+			duk_get_int(ctx, 2),
+			duk_get_int(ctx, 3)
+		};
+	} else if (duk_get_top(ctx) == 1)
+		obj = dukx_require_line(ctx, 0);
+
+	duk_ret_t ret;
+
+	// Allow both constructor and non constructor calls.
+	if (duk_is_constructor_call(ctx)) {
+		duk_push_this(ctx);
+		dukx_put_line(ctx, obj);
+		ret = 0;
+	} else {
+		dukx_push_line(ctx, obj);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+} // !namespace
+
+auto dukx_get_line(duk_context* ctx, duk_idx_t index) -> line
+{
+	const auto get = [&] (auto name) {
+		dukx_stack_assert sa(ctx);
+
+		duk_get_prop_string(ctx, index, name);
+		auto v = duk_get_int(ctx, -1);
+		duk_pop(ctx);
+
+		return v;
+	};
+
+	return line{get("x1"), get("y1"), get("x2"), get("y2")};
+}
+
+auto dukx_require_line(duk_context* ctx, duk_idx_t index) -> line
+{
+	auto get = [&] (auto prop) {
+		if (!duk_has_prop_string(ctx, index, prop))
+			duk_error(ctx, DUK_ERR_ERROR, "missing %s property in line description", prop);
+
+		duk_get_prop_string(ctx, index, prop);
+
+		if (!duk_is_number(ctx, -1)) {
+			duk_pop(ctx);
+			duk_error(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", prop);
+		}
+
+		auto value = duk_to_int(ctx, -1);
+
+		duk_pop(ctx);
+
+		return value;
+	};
+
+	return line{get("x1"), get("y1"), get("x2"), get("y2")};
+}
+
+auto dukx_optional_line(duk_context* ctx, duk_idx_t index, line def) -> line
+{
+	return duk_is_object(ctx, index) ? dukx_get_line(ctx, index) : def;
+}
+
+void dukx_push_line(duk_context* ctx, const line& line)
+{
+	dukx_stack_assert sa(ctx, 1);
+
+	duk_push_object(ctx);
+	dukx_put_line(ctx, line);
+}
+
+void dukx_put_line(duk_context* ctx, const line& line)
+{
+	assert(duk_is_object(ctx, -1));
+
+	dukx_stack_assert sa(ctx);
+
+	duk_push_int(ctx, line.x1);
+	duk_put_prop_string(ctx, -2, "x1");
+	duk_push_int(ctx, line.y1);
+	duk_put_prop_string(ctx, -2, "y1");
+	duk_push_int(ctx, line.x2);
+	duk_put_prop_string(ctx, -2, "x2");
+	duk_push_int(ctx, line.y2);
+	duk_put_prop_string(ctx, -2, "y2");
+}
+
+void dukx_load_line(duk_context* ctx)
+{
+	dukx_stack_assert sa(ctx, 0);
+
+	duk_get_global_string(ctx, "Malikania");
+	duk_push_c_function(ctx, constructor, DUK_VARARGS);
+	duk_put_prop_string(ctx, -2, "Line");
+	duk_pop(ctx);
+}
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_line.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * js_line.hpp -- line description (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.
+ */
+
+#ifndef MALIKANIA_JS_LINE_HPP
+#define MALIKANIA_JS_LINE_HPP
+
+/**
+ * \file js_line.hpp
+ * \brief JavaScript binding for line.
+ *
+ * lines are plain objects.
+ *
+ * ````
+ * {
+ *   x1: 10,
+ *   y1: 10,
+ *   x2: 50,
+ *   y2: 50
+ * }
+ * ````
+ */
+
+#include <malikania/duktape.hpp>
+#include <malikania/line.hpp>
+
+namespace mlk {
+
+/**
+ * Get a line.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the line
+ */
+auto dukx_get_line(duk_context* ctx, duk_idx_t index) -> line;
+
+/**
+ * Require a line.
+ *
+ * If value is not an object or any property is invalid, raise a JavaScript error.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the line
+ */
+auto dukx_require_line(duk_context* ctx, duk_idx_t index) -> line;
+
+/**
+ * Like get but return def if the value at the given index is not an object.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param def the default value
+ * \return the line
+ */
+auto dukx_optional_line(duk_context* ctx, duk_idx_t index, line def) -> line;
+
+/**
+ * Push the line as object.
+ *
+ * \param ctx the context
+ * \param line the line
+ */
+void dukx_push_line(duk_context* ctx, const line &line);
+
+/**
+ * Put the line properties into the object at the top of the stack.
+ *
+ * \param ctx the context
+ * \param line the line
+ */
+void dukx_put_line(duk_context* ctx, const line &line);
+
+void dukx_load_line(duk_context* ctx);
+
+} // !mlk
+
+#endif // !MALIKANIA_JS_LINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_point.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,126 @@
+/*
+ * js_point.cpp -- point description (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 <cassert>
+
+#include "js_point.hpp"
+
+namespace mlk {
+
+namespace {
+
+auto parse(duk_context* ctx, duk_idx_t index, bool required, point ret = {}) -> point
+{
+	dukx_stack_assert sa(ctx);
+
+	if (duk_is_object(ctx, index)) {
+		if (required && !duk_has_prop_string(ctx, index, "x"))
+			duk_error(ctx, DUK_ERR_ERROR, "missing x property in point description");
+		else if (required && !duk_has_prop_string(ctx, index, "y"))
+			duk_error(ctx, DUK_ERR_ERROR, "missing y property in point description");
+
+		int x;
+		int y;
+
+		duk_get_prop_string(ctx, index, "x");
+		x = duk_to_int(ctx, -1);
+		duk_pop(ctx);
+		duk_get_prop_string(ctx, index, "y");
+		y = duk_to_int(ctx, -1);
+		duk_pop(ctx);
+
+		ret = point{x, y};
+	} else if (required)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "point object expected");
+
+	return ret;
+}
+
+auto constructor(duk_context* ctx) -> duk_ret_t
+{
+	point obj;
+
+	if (duk_get_top(ctx) == 2)
+		obj = point{duk_require_int(ctx, 0), duk_require_int(ctx, 1)};
+	else if (duk_get_top(ctx) == 1)
+		obj = parse(ctx, 0, true);
+
+	duk_ret_t ret;
+
+	// Allow both constructor and non constructor calls.
+	if (duk_is_constructor_call(ctx)) {
+		duk_push_this(ctx);
+		dukx_put_point(ctx, obj);
+		duk_pop(ctx);
+		ret = 0;
+	} else {
+		dukx_push_point(ctx, obj);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+} // !namespace
+
+auto dukx_get_point(duk_context* ctx, duk_idx_t index) -> point
+{
+	return parse(ctx, index, false);
+}
+
+auto dukx_require_point(duk_context* ctx, duk_idx_t index) -> point
+{
+	return parse(ctx, index, true);
+}
+
+auto dukx_optional_point(duk_context* ctx, duk_idx_t index, point def) -> point
+{
+	return parse(ctx, index, false, std::move(def));
+}
+
+void dukx_push_point(duk_context* ctx, const point &point)
+{
+	dukx_stack_assert sa(ctx, 1);
+
+	duk_push_object(ctx);
+	dukx_put_point(ctx, point);
+}
+
+void dukx_put_point(duk_context* ctx, const point& point)
+{
+	assert(duk_is_object(ctx, -1));
+
+	dukx_stack_assert sa(ctx);
+
+	duk_push_int(ctx, point.x);
+	duk_put_prop_string(ctx, -2, "x");
+	duk_push_int(ctx, point.y);
+	duk_put_prop_string(ctx, -2, "y");
+}
+
+void dukx_load_point(duk_context* ctx)
+{
+	dukx_stack_assert sa(ctx, 0);
+
+	duk_get_global_string(ctx, "Malikania");
+	duk_push_c_function(ctx, constructor, DUK_VARARGS);
+	duk_put_prop_string(ctx, -2, "Point");
+	duk_pop(ctx);
+}
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_point.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,39 @@
+/*
+ * js_point.hpp -- point description (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.
+ */
+
+#ifndef MALIKANIA_JS_POINT_HPP
+#define MALIKANIA_JS_POINT_HPP
+
+#include <malikania/point.hpp>
+#include <malikania/duktape.hpp>
+
+namespace mlk {
+
+auto dukx_require_point(duk_context* ctx, duk_idx_t index) -> point;
+
+auto dukx_get_point(duk_context* ctx, duk_idx_t index) -> point;
+
+void dukx_push_point(duk_context* ctx, const point& point);
+
+void dukx_put_point(duk_context* ctx, const point& point);
+
+void dukx_load_point(duk_context* ctx);
+
+} // !mlk
+
+#endif // !MALIKANIA_JS_POINT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_rectangle.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,151 @@
+/*
+ * js_rectangle.cpp -- rectangle description (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 <cassert>
+
+#include "js_rectangle.hpp"
+
+namespace mlk {
+
+namespace {
+
+auto clamp(duk_context* ctx, int value, bool required) -> unsigned
+{
+    if (value < 0) {
+        if (required)
+            duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d can not be negative", value);
+        else
+            value = 0;
+    }
+
+    return static_cast<unsigned>(value);
+}
+
+auto parse(duk_context* ctx, duk_idx_t index, bool required, rectangle rect = {}) -> rectangle
+{
+    dukx_stack_assert sa(ctx);
+
+    if (duk_is_object(ctx, index)) {
+        auto get = [&] (auto prop) {
+            if (required && !duk_has_prop_string(ctx, index, prop))
+                duk_error(ctx, DUK_ERR_ERROR, "missing '%s' property", prop);
+
+            duk_get_prop_string(ctx, index, prop);
+
+            if (required && !duk_is_number(ctx, -1)) {
+                duk_pop(ctx);
+                duk_error(ctx, DUK_ERR_ERROR, "invalid '%s' property (number expected)", prop);
+            }
+
+            auto value = duk_to_int(ctx, -1);
+
+            duk_pop(ctx);
+
+            return value;
+        };
+
+        rect = rectangle{get("x"), get("y"),
+            clamp(ctx, get("width"), required), clamp(ctx, get("height"), required)};
+    } else if (required)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "rectangle object expected");
+
+    return rect;
+}
+
+auto constructor(duk_context* ctx) -> duk_ret_t
+{
+    rectangle rect;
+
+    if (duk_get_top(ctx) == 4) {
+        rect = rectangle{
+            duk_require_int(ctx, 0),
+            duk_require_int(ctx, 1),
+            clamp(ctx, duk_require_int(ctx, 2), true),
+            clamp(ctx, duk_require_int(ctx, 3), true)
+        };
+    } else if (duk_get_top(ctx) == 1)
+        rect = parse(ctx, 0, true);
+
+    duk_ret_t ret;
+
+    // Allow both constructor and non constructor calls.
+    if (duk_is_constructor_call(ctx)) {
+        duk_push_this(ctx);
+        dukx_put_rect(ctx, rect);
+        duk_pop(ctx);
+        ret = 0;
+    } else {
+        dukx_push_rect(ctx, rect);
+        ret = 1;
+    }
+
+    return ret;
+}
+
+} // !namespace
+
+auto dukx_get_rect(duk_context* ctx, duk_idx_t index) -> rectangle
+{
+    return parse(ctx, index, false);
+}
+
+auto dukx_require_rect(duk_context* ctx, duk_idx_t index) -> rectangle
+{
+    return parse(ctx, index, true);
+}
+
+auto dukx_optional_rect(duk_context* ctx, duk_idx_t index, rectangle def) -> rectangle
+{
+    return parse(ctx, index, false, std::move(def));
+}
+
+void dukx_push_rect(duk_context* ctx, const rectangle& rect)
+{
+    dukx_stack_assert sa(ctx, 1);
+
+    duk_push_object(ctx);
+    dukx_put_rect(ctx, rect);
+}
+
+void dukx_put_rect(duk_context* ctx, const rectangle& rect)
+{
+    assert(duk_is_object(ctx, -1));
+
+    dukx_stack_assert sa(ctx);
+
+    duk_push_int(ctx, rect.x);
+    duk_put_prop_string(ctx, -2, "x");
+    duk_push_int(ctx, rect.y);
+    duk_put_prop_string(ctx, -2, "y");
+    duk_push_uint(ctx, rect.width);
+    duk_put_prop_string(ctx, -2, "width");
+    duk_push_uint(ctx, rect.height);
+    duk_put_prop_string(ctx, -2, "height");
+}
+
+void dukx_load_rect(duk_context* ctx)
+{
+    dukx_stack_assert sa(ctx, 0);
+
+    duk_get_global_string(ctx, "Malikania");
+    duk_push_c_function(ctx, constructor, DUK_VARARGS);
+    duk_put_prop_string(ctx, -2, "Rectangle");
+    duk_pop(ctx);
+}
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon-js/malikania/js_rectangle.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * js_rectangle.hpp -- rectangle description (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.
+ */
+
+#ifndef MALIKANIA_JS_RECTANGLE_HPP
+#define MALIKANIA_JS_RECTANGLE_HPP
+
+/**
+ * \file js_rectangle.hpp
+ * \brief JavaScript binding for rectangle.
+ *
+ * rectangles are plain objects.
+ *
+ * ````
+ * {
+ *   x: 10,
+ *   y: 20,
+ *   width: 100,
+ *   height: 200
+ * }
+ * ````
+ */
+
+#include <malikania/rectangle.hpp>
+#include <malikania/duktape.hpp>
+
+namespace mlk {
+
+/**
+ * Get a rectangle.
+ *
+ * The rectangle may be adjusted if any values are incorrect.
+ *
+ * \param ctx the context
+ * \param index the value index
+ * \return the rectangle
+ */
+auto dukx_get_rect(duk_context* ctx, duk_idx_t index) -> rectangle;
+
+/**
+ * Require a rectangle.
+ *
+ * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the rectangle
+ */
+auto dukx_require_rect(duk_context* ctx, duk_idx_t index) -> rectangle;
+
+/**
+ * Like get but return the default value if the value at the given index is not an object or invalid
+ *
+ * \param ctx the context
+ * \param index the idnex
+ * \param def the default value
+ * \return the rectangle
+ */
+auto dukx_optional_rect(duk_context* ctx, duk_idx_t index, rectangle def) -> rectangle;
+
+/**
+ * Push the rectangle as object.
+ *
+ * \param ctx the context
+ * \param rect the rectangle
+ */
+void dukx_push_rect(duk_context* ctx, const rectangle &rect);
+
+/**
+ * Put the rectangle properties into the object at the top of the stack.
+ *
+ * \param ctx the context
+ * \param rect the rectangle
+ */
+void dukx_put_rect(duk_context* ctx, const rectangle& rect);
+
+void dukx_load_rect(duk_context* ctx);
+
+} // !mlk
+
+#endif // !MALIKANIA_JS_RECTANGLE_HPP
--- a/libcommon/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/libcommon/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -22,44 +22,46 @@
 find_package(OpenSSL REQUIRED)
 
 set(
-    HEADERS
-    ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/error/error.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/game.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/loader.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/locator.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/size.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/socket.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/tileset.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/unicode.hpp
-    ${libmlk-common_SOURCE_DIR}/malikania/util.hpp
+	HEADERS
+	${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/error/error.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/game.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/line.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/loader.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/locator.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/point.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/rectangle.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/size.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/socket.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/tileset.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/unicode.hpp
+	${libmlk-common_SOURCE_DIR}/malikania/util.hpp
 )
 
 set(
-    SOURCES
-    ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.cpp
-    ${libmlk-common_SOURCE_DIR}/malikania/loader.cpp
-    ${libmlk-common_SOURCE_DIR}/malikania/locator.cpp
-    ${libmlk-common_SOURCE_DIR}/malikania/socket.cpp
-    ${libmlk-common_SOURCE_DIR}/malikania/unicode.cpp
-    ${libmlk-common_SOURCE_DIR}/malikania/util.cpp
+	SOURCES
+	${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.cpp
+	${libmlk-common_SOURCE_DIR}/malikania/loader.cpp
+	${libmlk-common_SOURCE_DIR}/malikania/locator.cpp
+	${libmlk-common_SOURCE_DIR}/malikania/socket.cpp
+	${libmlk-common_SOURCE_DIR}/malikania/unicode.cpp
+	${libmlk-common_SOURCE_DIR}/malikania/util.cpp
 )
 
 malikania_define_library(
-    PROJECT libmlk-common
-    TARGET libmlk-common
-    SOURCES ${HEADERS} ${SOURCES}
-    FLAGS "MALIKANIA_COMMON_BUILD"
-    PUBLIC_INCLUDES
-        ${INCLUDES}
-        $<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}/malikania>
-        $<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}>
-    LIBRARIES
-        Boost::boost
-        Boost::filesystem
-        Boost::system
-        OpenSSL::Crypto
-        OpenSSL::SSL
-        json
-        ${LIBRARIES}
+	PROJECT libmlk-common
+	TARGET libmlk-common
+	SOURCES ${HEADERS} ${SOURCES}
+	PUBLIC_INCLUDES
+		${INCLUDES}
+		$<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}/malikania>
+		$<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}>
+	LIBRARIES
+		Boost::boost
+		Boost::filesystem
+		Boost::system
+		OpenSSL::Crypto
+		OpenSSL::SSL
+		json
+		${LIBRARIES}
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/line.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * line.hpp -- line description
+ *
+ * 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.
+ */
+
+#ifndef MALIKANIA_LINE_HPP
+#define MALIKANIA_LINE_HPP
+
+/**
+ * \file line.hpp
+ * \brief line description.
+ */
+
+namespace mlk {
+
+/**
+ * \brief line description.
+ *
+ * A line has an origin (x, y) and a destination (x, y).
+ */
+struct line {
+	int x1{0};
+	int y1{0};
+	int x2{0};
+	int y2{0};
+};
+
+/**
+ * Compare equality.
+ *
+ * \param l1 the first line
+ * \param l2 the second line
+ * \return true if they equal
+ */
+inline auto operator==(const line& l1, const line& l2) noexcept -> bool
+{
+	return l1.x1 == l2.x1 && l1.x2 == l2.x2 &&
+	       l1.y1 == l2.y1 && l1.y2 == l2.y2;
+}
+
+/**
+ * Compare equality.
+ *
+ * \param l1 the first line
+ * \param l2 the second line
+ * \return false if they equal
+ */
+inline auto operator!=(const line& l1, const line& l2) noexcept -> bool
+{
+	return !(l1 == l2);
+}
+
+} // !mlk
+
+#endif // !MALIKANIA_LINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/point.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * point.hpp -- point description
+ *
+ * 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.
+ */
+
+#ifndef MALIKANIA_POINT_HPP
+#define MALIKANIA_POINT_HPP
+
+/**
+ * \file point.hpp
+ * \brief point description.
+ */
+
+namespace mlk {
+
+/**
+ * \brief point coordinate.
+ */
+struct point {
+    int x{0};
+    int y{0};
+};
+
+/**
+ * Compare equality.
+ *
+ * \param p1 the first point
+ * \param p2 the second point
+ * \return true if they equal
+ */
+inline auto operator==(const point& p1, const point& p2) noexcept -> bool
+{
+    return p1.x == p2.x && p1.y == p2.y;
+}
+
+/**
+ * Compare equality.
+ *
+ * \param p1 the first point
+ * \param p2 the second point
+ * \return false if they equal
+ */
+inline auto operator!=(const point& p1, const point& p2) noexcept -> bool
+{
+    return !(p1 == p2);
+}
+
+} // !mlk
+
+#endif // !MALIKANIA_POINT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/rectangle.hpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * rectangle.hpp -- rectangle description
+ *
+ * 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.
+ */
+
+#ifndef MALIKANIA_RECTANGLE_HPP
+#define MALIKANIA_RECTANGLE_HPP
+
+/**
+ * \file rectangle.hpp
+ * \brief rectangle description.
+ */
+
+namespace mlk {
+
+/**
+ * \brief rectangle description.
+ *
+ * A rectangle has coordinates (x, y) and dimensions (width, height).
+ *
+ * They are commonly used for clipping images into the window.
+ */
+struct rectangle {
+	int x{0};                       //!< x coordinate
+	int y{0};                       //!< y coordinate
+	unsigned width{0};              //!< width
+	unsigned height{0};             //!< height
+
+	/**
+	 * Check if the rectangle has null dimensions.
+	 *
+	 * \return true if weight and height are 0
+	 */
+	inline auto is_null() const noexcept -> bool
+	{
+		return width == 0 && height == 0;
+	}
+};
+
+/**
+ * Compare equality.
+ *
+ * \param r1 the first rectangle
+ * \param r2 the second rectangle
+ * \return true if they equal
+ */
+inline auto operator==(const rectangle& r1, const rectangle& r2) noexcept -> bool
+{
+	return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height;
+}
+
+/**
+ * Compare equality.
+ *
+ * \param r1 the first rectangle
+ * \param r2 the second rectangle
+ * \return false if they equal
+ */
+inline auto operator!=(const rectangle& r1, const rectangle& r2) noexcept -> bool
+{
+	return !(r1 == r2);
+}
+
+} // !mlk
+
+#endif // !MALIKANIA_RECTANGLE_HPP
--- a/tests/libclient/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/tests/libclient/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -17,12 +17,6 @@
 #
 
 add_subdirectory(color)
-add_subdirectory(line)
-add_subdirectory(point)
-add_subdirectory(rectangle)
 
 # JavaScript bindings
 add_subdirectory(js-color)
-add_subdirectory(js-line)
-add_subdirectory(js-point)
-add_subdirectory(js-rectangle)
--- a/tests/libclient/js-line/CMakeLists.txt	Sat Oct 20 20:38:43 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-client-js
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libclient/js-line/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,348 +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/js_line.hpp>
-
-namespace mlk::client {
-
-namespace {
-
-class test_line {
-protected:
-	dukx_context m_ctx;
-
-public:
-	test_line()
-	{
-		duk_push_object(m_ctx);
-		duk_put_global_string(m_ctx, "Malikania");
-		dukx_load_line(m_ctx);
-	}
-};
-
-BOOST_FIXTURE_TEST_SUITE(test_line_suite, test_line)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"r = Malikania.Line();"
-			"x1 = r.x1;"
-			"y1 = r.y1;"
-			"x2 = r.x2;"
-			"y2 = r.y2;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_4_args)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"r = Malikania.Line(10, 20, 30, 40);"
-			"x1 = r.x1;"
-			"y1 = r.y1;"
-			"x2 = r.x2;"
-			"y2 = r.y2;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	try {
-		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	try {
-		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(arg_1)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  Malikania.Line(null);"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof TypeError);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto line = dukx_require_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(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(50, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(80, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			dukx_require_line(ctx, 0);
-
-			return 0;
-		}, 1);
-		duk_put_global_string(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  build({});"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof Error);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto line = dukx_get_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(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx, "build({});");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x1");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y1");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "x2");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y2");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libclient/js-point/CMakeLists.txt	Sat Oct 20 20:38:43 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-client-js
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libclient/js-point/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +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/js_point.hpp>
-
-namespace mlk::client {
-
-namespace {
-
-class test_point {
-protected:
-	dukx_context m_ctx;
-
-public:
-	test_point()
-	{
-		duk_push_object(m_ctx);
-		duk_put_global_string(m_ctx, "Malikania");
-		dukx_load_point(m_ctx);
-	}
-};
-
-BOOST_FIXTURE_TEST_SUITE(test_point_suite, test_point)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"p = Malikania.Point();"
-			"x = p.x;"
-			"y = p.y;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_2_args)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"p = Malikania.Point(-10, -20);"
-			"x = p.x;"
-			"y = p.y;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(-10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(-20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"p = Malikania.Point({ x: 100, y: 200 });"
-			"x = p.x;"
-			"y = p.y;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"p = new Malikania.Point({ x: 100, y: 200 });"
-			"x = p.x;"
-			"y = p.y;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  Malikania.Point(null);"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof TypeError);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto point = dukx_require_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(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx, "build({ x: 100, y: 200 });");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			dukx_require_point(ctx, 0);
-
-			return 0;
-		}, 1);
-		duk_put_global_string(m_ctx, "build");
-
-		auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  build({});"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof Error);"
-			"}"
-		);
-
-		if (ret != 0) {
-			throw dukx_get_exception(m_ctx, -1);
-		}
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto point = dukx_get_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(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx, "build({});");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libclient/js-rectangle/CMakeLists.txt	Sat Oct 20 20:38:43 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-client-js
-	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-)
--- a/tests/libclient/js-rectangle/main.cpp	Sat Oct 20 20:38:43 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,373 +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/js_rectangle.hpp>
-
-namespace mlk::client {
-
-namespace {
-
-class test_rectangle {
-protected:
-	dukx_context m_ctx;
-
-public:
-	test_rectangle()
-	{
-		duk_push_object(m_ctx);
-		duk_put_global_string(m_ctx, "Malikania");
-		dukx_load_rect(m_ctx);
-	}
-};
-
-BOOST_FIXTURE_TEST_SUITE(test_rectangle_suite, test_rectangle)
-
-/*
- * Valid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_default)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"r = Malikania.Rectangle();"
-			"x = r.x;"
-			"y = r.y;"
-			"w = r.width;"
-			"h = r.height;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_4_args)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"r = Malikania.Rectangle(10, 20, 30, 40);"
-			"x = r.x;"
-			"y = r.y;"
-			"w = r.width;"
-			"h = r.height;"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_object)
-{
-	try {
-		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_new)
-{
-	try {
-		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Invalid constructors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(invalid_constructors)
-
-BOOST_AUTO_TEST_CASE(constructor_arg_1)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  Malikania.Rectangle(null);"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof TypeError);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(constructor_range_1)
-{
-	try {
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  Malikania.Rectangle(0, 0, -10, -10);"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof RangeError);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("RangeError", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(require)
-
-BOOST_AUTO_TEST_CASE(success)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto rect = dukx_require_rect(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(m_ctx, "build");
-
-		auto ret = duk_peval_string(m_ctx, "build({ x: 50, y: 80, width: 100, height: 200 });");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(50, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(80, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(100U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(200U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_CASE(fail)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			dukx_require_rect(ctx, 0);
-
-			return 0;
-		}, 1);
-		duk_put_global_string(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx,
-			"try {"
-			"  build({});"
-			"} catch (e) {"
-			"  name = e.name;"
-			"  correct = (e instanceof Error);"
-			"}"
-		);
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "name");
-		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "correct");
-		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Get.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(get)
-
-BOOST_AUTO_TEST_CASE(adjust_all)
-{
-	try {
-		duk_push_c_function(m_ctx, [] (auto ctx) {
-			const auto rect = dukx_get_rect(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(m_ctx, "build");
-
-		const auto ret = duk_peval_string(m_ctx, "build({});");
-
-		if (ret != 0)
-			throw dukx_get_exception(m_ctx, -1);
-
-		duk_get_global_string(m_ctx, "x");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "y");
-		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "w");
-		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-		duk_get_global_string(m_ctx, "h");
-		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
-		duk_pop(m_ctx);
-	} catch (const std::exception &ex) {
-		BOOST_FAIL(ex.what());
-	}
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !mlk::client
--- a/tests/libclient/line/CMakeLists.txt	Sat Oct 20 20:38:43 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/libclient/line/main.cpp	Sat Oct 20 20:38:43 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/client/line.hpp>
-
-namespace mlk::client {
-
-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_REQUIRE_EQUAL(line1, line2);
-}
-
-BOOST_AUTO_TEST_CASE(operator_eq1)
-{
-	line line1{10, 20, 30, 40};
-	line line2{10, 20, 30, 40};
-
-	BOOST_REQUIRE_EQUAL(line1, line2);
-}
-
-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/libclient/point/CMakeLists.txt	Sat Oct 20 20:38:43 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/libclient/point/main.cpp	Sat Oct 20 20:38:43 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/client/point.hpp>
-
-namespace mlk::client {
-
-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/libclient/rectangle/CMakeLists.txt	Sat Oct 20 20:38:43 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/libclient/rectangle/main.cpp	Sat Oct 20 20:38:43 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/client/rectangle.hpp>
-
-namespace mlk::client {
-
-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/CMakeLists.txt	Sat Oct 20 20:38:43 2018 +0200
+++ b/tests/libcommon/CMakeLists.txt	Sat Oct 20 21:12:20 2018 +0200
@@ -16,9 +16,15 @@
 # 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(size)
 
 # 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/libcommon/js-line/CMakeLists.txt	Sat Oct 20 21:12:20 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-common-js
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/js-line/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,348 @@
+/*
+ * 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/js_line.hpp>
+
+namespace mlk {
+
+namespace {
+
+class test_line {
+protected:
+	dukx_context m_ctx;
+
+public:
+	test_line()
+	{
+		duk_push_object(m_ctx);
+		duk_put_global_string(m_ctx, "Malikania");
+		dukx_load_line(m_ctx);
+	}
+};
+
+BOOST_FIXTURE_TEST_SUITE(test_line_suite, test_line)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"r = Malikania.Line();"
+			"x1 = r.x1;"
+			"y1 = r.y1;"
+			"x2 = r.x2;"
+			"y2 = r.y2;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_4_args)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"r = Malikania.Line(10, 20, 30, 40);"
+			"x1 = r.x1;"
+			"y1 = r.y1;"
+			"x2 = r.x2;"
+			"y2 = r.y2;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	try {
+		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	try {
+		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(30, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(40, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(arg_1)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  Malikania.Line(null);"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof TypeError);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto line = dukx_require_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(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(50, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(80, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			dukx_require_line(ctx, 0);
+
+			return 0;
+		}, 1);
+		duk_put_global_string(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  build({});"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof Error);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto line = dukx_get_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(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx, "build({});");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x1");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y1");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "x2");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y2");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/js-point/CMakeLists.txt	Sat Oct 20 21:12:20 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-common-js
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/js-point/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,297 @@
+/*
+ * 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/js_point.hpp>
+
+namespace mlk {
+
+namespace {
+
+class test_point {
+protected:
+	dukx_context m_ctx;
+
+public:
+	test_point()
+	{
+		duk_push_object(m_ctx);
+		duk_put_global_string(m_ctx, "Malikania");
+		dukx_load_point(m_ctx);
+	}
+};
+
+BOOST_FIXTURE_TEST_SUITE(test_point_suite, test_point)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"p = Malikania.Point();"
+			"x = p.x;"
+			"y = p.y;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_2_args)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"p = Malikania.Point(-10, -20);"
+			"x = p.x;"
+			"y = p.y;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(-10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(-20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"p = Malikania.Point({ x: 100, y: 200 });"
+			"x = p.x;"
+			"y = p.y;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"p = new Malikania.Point({ x: 100, y: 200 });"
+			"x = p.x;"
+			"y = p.y;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  Malikania.Point(null);"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof TypeError);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto point = dukx_require_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(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx, "build({ x: 100, y: 200 });");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(100, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(200, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			dukx_require_point(ctx, 0);
+
+			return 0;
+		}, 1);
+		duk_put_global_string(m_ctx, "build");
+
+		auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  build({});"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof Error);"
+			"}"
+		);
+
+		if (ret != 0) {
+			throw dukx_get_exception(m_ctx, -1);
+		}
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto point = dukx_get_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(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx, "build({});");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/js-rectangle/CMakeLists.txt	Sat Oct 20 21:12:20 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-common-js
+	SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/js-rectangle/main.cpp	Sat Oct 20 21:12:20 2018 +0200
@@ -0,0 +1,373 @@
+/*
+ * 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/js_rectangle.hpp>
+
+namespace mlk {
+
+namespace {
+
+class test_rectangle {
+protected:
+	dukx_context m_ctx;
+
+public:
+	test_rectangle()
+	{
+		duk_push_object(m_ctx);
+		duk_put_global_string(m_ctx, "Malikania");
+		dukx_load_rect(m_ctx);
+	}
+};
+
+BOOST_FIXTURE_TEST_SUITE(test_rectangle_suite, test_rectangle)
+
+/*
+ * Valid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_default)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"r = Malikania.Rectangle();"
+			"x = r.x;"
+			"y = r.y;"
+			"w = r.width;"
+			"h = r.height;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_4_args)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"r = Malikania.Rectangle(10, 20, 30, 40);"
+			"x = r.x;"
+			"y = r.y;"
+			"w = r.width;"
+			"h = r.height;"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_object)
+{
+	try {
+		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_new)
+{
+	try {
+		const auto ret = duk_peval_string(m_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 dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(10, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(20, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(30U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(40U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Invalid constructors.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(invalid_constructors)
+
+BOOST_AUTO_TEST_CASE(constructor_arg_1)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  Malikania.Rectangle(null);"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof TypeError);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("TypeError", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(constructor_range_1)
+{
+	try {
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  Malikania.Rectangle(0, 0, -10, -10);"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof RangeError);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("RangeError", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Require.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(require)
+
+BOOST_AUTO_TEST_CASE(success)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto rect = dukx_require_rect(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(m_ctx, "build");
+
+		auto ret = duk_peval_string(m_ctx, "build({ x: 50, y: 80, width: 100, height: 200 });");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(50, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(80, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(100U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(200U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_CASE(fail)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			dukx_require_rect(ctx, 0);
+
+			return 0;
+		}, 1);
+		duk_put_global_string(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx,
+			"try {"
+			"  build({});"
+			"} catch (e) {"
+			"  name = e.name;"
+			"  correct = (e instanceof Error);"
+			"}"
+		);
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "name");
+		BOOST_REQUIRE_EQUAL("Error", duk_to_string(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "correct");
+		BOOST_REQUIRE(duk_to_boolean(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * Get.
+ * ------------------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(get)
+
+BOOST_AUTO_TEST_CASE(adjust_all)
+{
+	try {
+		duk_push_c_function(m_ctx, [] (auto ctx) {
+			const auto rect = dukx_get_rect(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(m_ctx, "build");
+
+		const auto ret = duk_peval_string(m_ctx, "build({});");
+
+		if (ret != 0)
+			throw dukx_get_exception(m_ctx, -1);
+
+		duk_get_global_string(m_ctx, "x");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "y");
+		BOOST_REQUIRE_EQUAL(0, duk_to_int(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "w");
+		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+		duk_get_global_string(m_ctx, "h");
+		BOOST_REQUIRE_EQUAL(0U, duk_to_uint(m_ctx, -1));
+		duk_pop(m_ctx);
+	} catch (const std::exception &ex) {
+		BOOST_FAIL(ex.what());
+	}
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libcommon/line/CMakeLists.txt	Sat Oct 20 21:12:20 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/libcommon/line/main.cpp	Sat Oct 20 21:12:20 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_REQUIRE_EQUAL(line1, line2);
+}
+
+BOOST_AUTO_TEST_CASE(operator_eq1)
+{
+	line line1{10, 20, 30, 40};
+	line line2{10, 20, 30, 40};
+
+	BOOST_REQUIRE_EQUAL(line1, line2);
+}
+
+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/libcommon/point/CMakeLists.txt	Sat Oct 20 21:12:20 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/libcommon/point/main.cpp	Sat Oct 20 21:12:20 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/libcommon/rectangle/CMakeLists.txt	Sat Oct 20 21:12:20 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/libcommon/rectangle/main.cpp	Sat Oct 20 21:12:20 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