changeset 846:dcef68d82fd3

irccd: rework Irccd.ElapsedTimer -> Irccd.Chrono API, closes #1667 - Add new start function to restart a paused timer (closes #1669), - Rename restart function to resume (closes #1668),
author David Demelier <markand@malikania.fr>
date Wed, 10 Jul 2019 13:39:20 +0200
parents 00a4720c4874
children a23b7b574ed2
files MIGRATING.md libirccd-js/CMakeLists.txt libirccd-js/irccd/js.hpp libirccd-js/irccd/js/api.cpp libirccd-js/irccd/js/chrono_api.cpp libirccd-js/irccd/js/chrono_api.hpp libirccd-js/irccd/js/elapsed_timer_api.cpp libirccd-js/irccd/js/elapsed_timer_api.hpp tests/src/libirccd-js/CMakeLists.txt tests/src/libirccd-js/js-api-chrono/CMakeLists.txt tests/src/libirccd-js/js-api-chrono/main.cpp tests/src/libirccd-js/js-api-elapsedtimer/CMakeLists.txt tests/src/libirccd-js/js-api-elapsedtimer/main.cpp
diffstat 13 files changed, 417 insertions(+), 328 deletions(-) [+]
line wrap: on
line diff
--- a/MIGRATING.md	Mon Jul 08 16:15:57 2019 +0200
+++ b/MIGRATING.md	Wed Jul 10 13:39:20 2019 +0200
@@ -70,6 +70,18 @@
 - The object information in `onWhois` event now has `hostname` property instead
   of `host`.
 
+### Module Chrono
+
+- The module `ElapsedTimer` has been renamed to `Chrono`,
+- The method `Chrono.restart` has been renamed to `Chrono.resume` to reduce
+  ambiguity,
+- The method `Chrono.reset` has been removed, just use `Chrono.start` instead
+  when you want to start accumulate time again.
+
+### Module Directory
+
+- The property `Directory.count` has been removed.
+
 ### Module Server
 
 - The methods `Server.cmode` and `Server.cnotice` have been removed, use
@@ -81,15 +93,6 @@
   `hostname`,
 - The property `sslVerify` in `Server` constructor has been removed.
 
-### Module ElapsedTimer
-
-- The method ElapsedTimer.reset has been removed, just use `start` instead
-  when you want to accumulate time.
-
-### Module Directory
-
-- The property `Directory.count` has been removed.
-
 ### Module Plugin
 
 The following properties in `Irccd.Plugin` has been renamed:
--- a/libirccd-js/CMakeLists.txt	Mon Jul 08 16:15:57 2019 +0200
+++ b/libirccd-js/CMakeLists.txt	Wed Jul 10 13:39:20 2019 +0200
@@ -25,20 +25,20 @@
 	${PROJECT_SOURCE_DIR}/irccd/js.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/api.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/api.hpp
+	${PROJECT_SOURCE_DIR}/irccd/js/chrono_api.cpp
+	${PROJECT_SOURCE_DIR}/irccd/js/chrono_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/directory_api.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/directory_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/duk.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/duk.hpp
-	${PROJECT_SOURCE_DIR}/irccd/js/elapsed_timer_api.cpp
-	${PROJECT_SOURCE_DIR}/irccd/js/elapsed_timer_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/file_api.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/file_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/irccd_api.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/irccd_api.hpp
+	${PROJECT_SOURCE_DIR}/irccd/js/logger_api.cpp
+	${PROJECT_SOURCE_DIR}/irccd/js/logger_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/plugin.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/plugin.hpp
-	${PROJECT_SOURCE_DIR}/irccd/js/logger_api.cpp
-	${PROJECT_SOURCE_DIR}/irccd/js/logger_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/plugin_api.cpp
 	${PROJECT_SOURCE_DIR}/irccd/js/plugin_api.hpp
 	${PROJECT_SOURCE_DIR}/irccd/js/server_api.cpp
--- a/libirccd-js/irccd/js.hpp	Mon Jul 08 16:15:57 2019 +0200
+++ b/libirccd-js/irccd/js.hpp	Wed Jul 10 13:39:20 2019 +0200
@@ -27,9 +27,9 @@
 #include "sysconfig.hpp"
 
 #include "js/api.hpp"
+#include "js/chrono_api.hpp"
 #include "js/directory_api.hpp"
 #include "js/duk.hpp"
-#include "js/elapsed_timer_api.hpp"
 #include "js/file_api.hpp"
 #include "js/irccd_api.hpp"
 #include "js/logger_api.hpp"
--- a/libirccd-js/irccd/js/api.cpp	Mon Jul 08 16:15:57 2019 +0200
+++ b/libirccd-js/irccd/js/api.cpp	Wed Jul 10 13:39:20 2019 +0200
@@ -17,7 +17,7 @@
  */
 
 #include "directory_api.hpp"
-#include "elapsed_timer_api.hpp"
+#include "chrono_api.hpp"
 #include "file_api.hpp"
 #include "irccd_api.hpp"
 #include "logger_api.hpp"
@@ -48,7 +48,7 @@
 		// Irccd API must be loaded first.
 		bind<irccd_api>(),
 		bind<directory_api>(),
-		bind<elapsed_timer_api>(),
+		bind<chrono_api>(),
 		bind<file_api>(),
 		bind<logger_api>(),
 		bind<plugin_api>(),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js/chrono_api.cpp	Wed Jul 10 13:39:20 2019 +0200
@@ -0,0 +1,200 @@
+/*
+ * chrono_api.cpp -- Irccd.Chrono API
+ *
+ * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <boost/timer/timer.hpp>
+
+#include "chrono_api.hpp"
+#include "plugin.hpp"
+
+using irccd::daemon::bot;
+
+namespace irccd::js {
+
+namespace {
+
+const std::string_view signature(DUK_HIDDEN_SYMBOL("Irccd.Chrono"));
+
+// {{{ self
+
+auto self(duk_context* ctx) -> boost::timer::cpu_timer*
+{
+	duk::stack_guard sa(ctx);
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, signature.data());
+	const auto ptr = static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
+	duk_pop_2(ctx);
+
+	if (!ptr)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Chrono object");
+
+	return ptr;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono.prototype.pause
+
+/*
+ * Method: Chrono.prototype.pause
+ * ------------------------------------------------------------------
+ *
+ * Pause the timer, without resetting the current elapsed time stored.
+ */
+auto Chrono_prototype_pause(duk_context* ctx) -> duk_ret_t
+{
+	self(ctx)->stop();
+
+	return 0;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono.prototype.resume
+
+/*
+ * Method: Irccd.Chrono.prototype.resume
+ * ------------------------------------------------------------------
+ *
+ * Restart the timer without resetting the current elapsed time.
+ */
+auto Chrono_prototype_resume(duk_context* ctx) -> duk_ret_t
+{
+	self(ctx)->resume();
+
+	return 0;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono.prototype.elapsed
+
+/*
+ * Method: Chrono.prototype.elapsed
+ * ------------------------------------------------------------------
+ *
+ * Get the number of elapsed milliseconds.
+ *
+ * Returns:
+ *   The time elapsed.
+ */
+auto Chrono_prototype_elapsed(duk_context* ctx) -> duk_ret_t
+{
+	duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL);
+
+	return 1;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono.prototype.start
+
+/*
+ * Method: Chrono.prototype.start
+ * ------------------------------------------------------------------
+ *
+ * Starts or restarts accumulating time.
+ */
+auto Chrono_prototype_start(duk_context* ctx) -> duk_ret_t
+{
+	self(ctx)->start();
+
+	return 0;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono [constructor]
+
+/*
+ * Function: Irccd.Chrono [constructor]
+ * ------------------------------------------------------------------
+ *
+ * Construct a new Chrono object.
+ */
+auto Chrono_constructor(duk_context* ctx) -> duk_ret_t
+{
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, new boost::timer::cpu_timer);
+	duk_put_prop_string(ctx, -2, signature.data());
+	duk_pop(ctx);
+
+	return 0;
+}
+
+// }}}
+
+// {{{ Irccd.Chrono [destructor]
+
+/*
+ * Function: Irccd.Chrono [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+auto Chrono_destructor(duk_context* ctx) -> duk_ret_t
+{
+	duk_get_prop_string(ctx, 0, signature.data());
+	delete static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, signature.data());
+
+	return 0;
+}
+
+// }}}
+
+// {{{ definitions
+
+const duk_function_list_entry methods[] = {
+	{ "elapsed",    Chrono_prototype_elapsed,       0 },
+	{ "pause",      Chrono_prototype_pause,         0 },
+	{ "resume",     Chrono_prototype_resume,        0 },
+	{ "start",      Chrono_prototype_start,         0 },
+	{ nullptr,      nullptr,                        0 }
+};
+
+// }}}
+
+} // !namespace
+
+// {{{ chrono_api
+
+auto chrono_api::get_name() const noexcept -> std::string_view
+{
+	return "Irccd.Chrono";
+}
+
+void chrono_api::load(bot&, plugin& plugin)
+{
+	duk::stack_guard sa(plugin.get_context());
+
+	duk_get_global_string(plugin.get_context(), "Irccd");
+	duk_push_c_function(plugin.get_context(), Chrono_constructor, 0);
+	duk_push_object(plugin.get_context());
+	duk_put_function_list(plugin.get_context(), -1, methods);
+	duk_push_c_function(plugin.get_context(), Chrono_destructor, 1);
+	duk_set_finalizer(plugin.get_context(), -2);
+	duk_put_prop_string(plugin.get_context(), -2, "prototype");
+	duk_put_prop_string(plugin.get_context(), -2, "Chrono");
+	duk_pop(plugin.get_context());
+}
+
+// }}}
+
+} // !irccd::js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js/chrono_api.hpp	Wed Jul 10 13:39:20 2019 +0200
@@ -0,0 +1,50 @@
+/*
+ * chrono_api.hpp -- Irccd.Chrono API
+ *
+ * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IRCCD_JS_CHRONO_API_HPP
+#define IRCCD_JS_CHRONO_API_HPP
+
+/**
+ * \file chrono_api.hpp
+ * \brief Irccd.Chrono Javascript API.
+ */
+
+#include "api.hpp"
+
+namespace irccd::js {
+
+/**
+ * \ingroup js-api
+ * \brief Irccd.Chrono Javascript API.
+ */
+class chrono_api : public api {
+public:
+	/**
+	 * \copydoc api::get_name
+	 */
+	auto get_name() const noexcept -> std::string_view override;
+
+	/**
+	 * \copydoc api::load
+	 */
+	void load(daemon::bot& bot, js::plugin& plugin) override;
+};
+
+} // !irccd::js
+
+#endif // !IRCCD_JS_CHRONO_API_HPP
--- a/libirccd-js/irccd/js/elapsed_timer_api.cpp	Mon Jul 08 16:15:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-/*
- * elapsed_timer_api.cpp -- Irccd.ElapsedTimer API
- *
- * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <boost/timer/timer.hpp>
-
-#include "elapsed_timer_api.hpp"
-#include "plugin.hpp"
-
-using irccd::daemon::bot;
-
-namespace irccd::js {
-
-namespace {
-
-const std::string_view signature(DUK_HIDDEN_SYMBOL("Irccd.ElapsedTimer"));
-
-// {{{ self
-
-auto self(duk_context* ctx) -> boost::timer::cpu_timer*
-{
-	duk::stack_guard sa(ctx);
-
-	duk_push_this(ctx);
-	duk_get_prop_string(ctx, -1, signature.data());
-	const auto ptr = static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
-	duk_pop_2(ctx);
-
-	if (!ptr)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
-
-	return ptr;
-}
-
-// }}}
-
-// {{{ Irccd.ElapsedTimer.prototype.pause
-
-/*
- * Method: ElapsedTimer.prototype.pause
- * ------------------------------------------------------------------
- *
- * Pause the timer, without resetting the current elapsed time stored.
- */
-auto ElapsedTimer_prototype_pause(duk_context* ctx) -> duk_ret_t
-{
-	self(ctx)->stop();
-
-	return 0;
-}
-
-// }}}
-
-// {{{ Irccd.ElapsedTimer.prototype.restart
-
-/*
- * Method: Irccd.ElapsedTimer.prototype.restart
- * ------------------------------------------------------------------
- *
- * Restart the timer without resetting the current elapsed time.
- */
-auto ElapsedTimer_prototype_restart(duk_context* ctx) -> duk_ret_t
-{
-	self(ctx)->resume();
-
-	return 0;
-}
-
-// }}}
-
-// {{{ Irccd.ElapsedTimer.prototype.elapsed
-
-/*
- * Method: ElapsedTimer.prototype.elapsed
- * ------------------------------------------------------------------
- *
- * Get the number of elapsed milliseconds.
- *
- * Returns:
- *   The time elapsed.
- */
-auto ElapsedTimer_prototype_elapsed(duk_context* ctx) -> duk_ret_t
-{
-	duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL);
-
-	return 1;
-}
-
-// }}}
-
-// {{{ Irccd.ElapsedTimer [constructor]
-
-/*
- * Function: Irccd.ElapsedTimer [constructor]
- * ------------------------------------------------------------------
- *
- * Construct a new ElapsedTimer object.
- */
-auto ElapsedTimer_constructor(duk_context* ctx) -> duk_ret_t
-{
-	duk_push_this(ctx);
-	duk_push_pointer(ctx, new boost::timer::cpu_timer);
-	duk_put_prop_string(ctx, -2, signature.data());
-	duk_pop(ctx);
-
-	return 0;
-}
-
-// }}}
-
-// {{{ Irccd.ElapsedTimer [destructor]
-
-/*
- * Function: Irccd.ElapsedTimer [destructor]
- * ------------------------------------------------------------------
- *
- * Delete the property.
- */
-auto ElapsedTimer_destructor(duk_context* ctx) -> duk_ret_t
-{
-	duk_get_prop_string(ctx, 0, signature.data());
-	delete static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1));
-	duk_pop(ctx);
-	duk_del_prop_string(ctx, 0, signature.data());
-
-	return 0;
-}
-
-// }}}
-
-// {{{ definitions
-
-const duk_function_list_entry methods[] = {
-	{ "elapsed",    ElapsedTimer_prototype_elapsed, 0 },
-	{ "pause",      ElapsedTimer_prototype_pause,   0 },
-	{ "restart",    ElapsedTimer_prototype_restart, 0 },
-	{ nullptr,      nullptr,                        0 }
-};
-
-// }}}
-
-} // !namespace
-
-// {{{ elapsed_timer_api
-
-auto elapsed_timer_api::get_name() const noexcept -> std::string_view
-{
-	return "Irccd.ElapsedTimer";
-}
-
-void elapsed_timer_api::load(bot&, plugin& plugin)
-{
-	duk::stack_guard sa(plugin.get_context());
-
-	duk_get_global_string(plugin.get_context(), "Irccd");
-	duk_push_c_function(plugin.get_context(), ElapsedTimer_constructor, 0);
-	duk_push_object(plugin.get_context());
-	duk_put_function_list(plugin.get_context(), -1, methods);
-	duk_push_c_function(plugin.get_context(), ElapsedTimer_destructor, 1);
-	duk_set_finalizer(plugin.get_context(), -2);
-	duk_put_prop_string(plugin.get_context(), -2, "prototype");
-	duk_put_prop_string(plugin.get_context(), -2, "ElapsedTimer");
-	duk_pop(plugin.get_context());
-}
-
-// }}}
-
-} // !irccd::js
--- a/libirccd-js/irccd/js/elapsed_timer_api.hpp	Mon Jul 08 16:15:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * elapsed_timer_api.hpp -- Irccd.ElapsedTimer API
- *
- * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_JS_ELAPSED_TIMER_API_HPP
-#define IRCCD_JS_ELAPSED_TIMER_API_HPP
-
-/**
- * \file elapsed_timer_api.hpp
- * \brief Irccd.ElapsedTimer Javascript API.
- */
-
-#include "api.hpp"
-
-namespace irccd::js {
-
-/**
- * \ingroup js-api
- * \brief Irccd.ElapsedTimer Javascript API.
- */
-class elapsed_timer_api : public api {
-public:
-	/**
-	 * \copydoc api::get_name
-	 */
-	auto get_name() const noexcept -> std::string_view override;
-
-	/**
-	 * \copydoc api::load
-	 */
-	void load(daemon::bot& bot, js::plugin& plugin) override;
-};
-
-} // !irccd::js
-
-#endif // !IRCCD_JS_ELAPSED_TIMER_API_HPP
--- a/tests/src/libirccd-js/CMakeLists.txt	Mon Jul 08 16:15:57 2019 +0200
+++ b/tests/src/libirccd-js/CMakeLists.txt	Wed Jul 10 13:39:20 2019 +0200
@@ -17,7 +17,7 @@
 #
 
 add_subdirectory(js-plugin)
-add_subdirectory(js-api-elapsedtimer)
+add_subdirectory(js-api-chrono)
 add_subdirectory(js-api-directory)
 add_subdirectory(js-api-file)
 add_subdirectory(js-api-irccd)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-js/js-api-chrono/CMakeLists.txt	Wed Jul 10 13:39:20 2019 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME js-api-chrono
+	SOURCES main.cpp
+	LIBRARIES libirccd-js
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-js/js-api-chrono/main.cpp	Wed Jul 10 13:39:20 2019 +0200
@@ -0,0 +1,124 @@
+/*
+ * main.cpp -- test Irccd.Chrono API
+ *
+ * Copyright (c) 2013-2019 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 "Chrono Javascript API"
+#include <boost/test/unit_test.hpp>
+
+#include <thread>
+
+#include <irccd/test/js_fixture.hpp>
+
+using namespace std::chrono_literals;
+
+using namespace irccd::js;
+using namespace irccd::test;
+
+namespace irccd {
+
+namespace {
+
+BOOST_FIXTURE_TEST_SUITE(chrono_js_api_suite, js_fixture)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+	if (duk_peval_string(plugin_->get_context(), "timer = new Irccd.Chrono();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(300ms);
+
+	if (duk_peval_string(plugin_->get_context(), "result = timer.elapsed();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	BOOST_REQUIRE(duk_get_global_string(plugin_->get_context(), "result"));
+	BOOST_REQUIRE_GE(duk_get_int(plugin_->get_context(), -1), 250);
+	BOOST_REQUIRE_LE(duk_get_int(plugin_->get_context(), -1), 350);
+}
+
+BOOST_AUTO_TEST_CASE(pause)
+{
+	/*
+	 * Create a time and stop it immediately. Then wait for 1 seconds,
+	 * the time must still be near 0.
+	 */
+	if (duk_peval_string(plugin_->get_context(), "timer = new Irccd.Chrono(); timer.pause();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(1s);
+
+	if (duk_peval_string(plugin_->get_context(), "result = timer.elapsed();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	BOOST_REQUIRE(duk_get_global_string(plugin_->get_context(), "result"));
+	BOOST_REQUIRE_LE(duk_get_int(plugin_->get_context(), -1), 50);
+}
+
+BOOST_AUTO_TEST_CASE(resume)
+{
+	/*
+	 * Create a time and stop it immediately. Then wait for 1 seconds,
+	 * resume it and wait for 1 second more. The elapsed time must not be
+	 * greater than 1s.
+	 */
+	if (duk_peval_string(plugin_->get_context(), "timer = new Irccd.Chrono(); timer.pause();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(1s);
+
+	if (duk_peval_string(plugin_->get_context(), "timer.resume();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(1s);
+
+	if (duk_peval_string(plugin_->get_context(), "result = timer.elapsed();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	BOOST_REQUIRE(duk_get_global_string(plugin_->get_context(), "result"));
+	BOOST_REQUIRE_GE(duk_get_int(plugin_->get_context(), -1), 950);
+	BOOST_REQUIRE_LE(duk_get_int(plugin_->get_context(), -1), 1050);
+}
+
+BOOST_AUTO_TEST_CASE(start)
+{
+	/*
+	 * Create a timer and wait for it to accumulate some time. Then use
+	 * start to reset its value and wait for 1s. The elapsed time must not
+	 * be greater than 1s.
+	 */
+	if (duk_peval_string(plugin_->get_context(), "timer = new Irccd.Chrono(); timer.start();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(1s);
+
+	if (duk_peval_string(plugin_->get_context(), "timer.start();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	std::this_thread::sleep_for(1s);
+
+	if (duk_peval_string(plugin_->get_context(), "result = timer.elapsed();") != 0)
+		throw duk::get_stack(plugin_->get_context(), -1);
+
+	BOOST_REQUIRE(duk_get_global_string(plugin_->get_context(), "result"));
+	BOOST_REQUIRE_GE(duk_get_int(plugin_->get_context(), -1), 950);
+	BOOST_REQUIRE_LE(duk_get_int(plugin_->get_context(), -1), 1050);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd
--- a/tests/src/libirccd-js/js-api-elapsedtimer/CMakeLists.txt	Mon Jul 08 16:15:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for irccd
-#
-# Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-irccd_define_test(
-	NAME js-api-elapsedtimer
-	SOURCES main.cpp
-	LIBRARIES libirccd-js
-)
--- a/tests/src/libirccd-js/js-api-elapsedtimer/main.cpp	Mon Jul 08 16:15:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * main.cpp -- test Irccd.ElapsedTimer API
- *
- * Copyright (c) 2013-2019 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 "ElapsedTimer Javascript API"
-#include <boost/test/unit_test.hpp>
-
-#include <thread>
-
-#include <irccd/test/js_fixture.hpp>
-
-using namespace std::chrono_literals;
-
-using namespace irccd::js;
-using namespace irccd::test;
-
-namespace irccd {
-
-namespace {
-
-BOOST_FIXTURE_TEST_SUITE(elapsed_timer_js_api_suite, js_fixture)
-
-BOOST_AUTO_TEST_CASE(standard)
-{
-	if (duk_peval_string(plugin_->get_context(), "timer = new Irccd.ElapsedTimer();") != 0)
-		throw duk::get_stack(plugin_->get_context(), -1);
-
-	std::this_thread::sleep_for(300ms);
-
-	if (duk_peval_string(plugin_->get_context(), "result = timer.elapsed();") != 0)
-		throw duk::get_stack(plugin_->get_context(), -1);
-
-	BOOST_REQUIRE(duk_get_global_string(plugin_->get_context(), "result"));
-	BOOST_REQUIRE_GE(duk_get_int(plugin_->get_context(), -1), 250);
-	BOOST_REQUIRE_LE(duk_get_int(plugin_->get_context(), -1), 350);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // !namespace
-
-} // !irccd