changeset 609:168c0e191eea

Irccd: add more error properties, closes #754 Add two new properties in error messages: - errorMessage: the string message as-is, - errorCategory: the error category (e.g. server, rule). Adapt tests to test against the category.
author David Demelier <markand@malikania.fr>
date Thu, 14 Dec 2017 21:45:32 +0100
parents 5ee406d8dbe8
children 22b3cd6f991f
files libirccd/irccd/daemon/transport_client.cpp tests/src/plugin-config-command/main.cpp tests/src/plugin-info-command/main.cpp tests/src/plugin-load-command/main.cpp tests/src/plugin-reload-command/main.cpp tests/src/plugin-unload-command/main.cpp tests/src/rule-add-command/main.cpp tests/src/rule-edit-command/main.cpp tests/src/rule-info-command/main.cpp tests/src/rule-move-command/main.cpp tests/src/rule-remove-command/main.cpp tests/src/server-connect-command/main.cpp tests/src/server-disconnect-command/main.cpp tests/src/server-info-command/main.cpp tests/src/server-invite-command/main.cpp tests/src/server-join-command/main.cpp tests/src/server-kick-command/main.cpp tests/src/server-me-command/main.cpp tests/src/server-message-command/main.cpp tests/src/server-mode-command/main.cpp tests/src/server-nick-command/main.cpp tests/src/server-notice-command/main.cpp tests/src/server-part-command/main.cpp tests/src/server-reconnect-command/main.cpp tests/src/server-topic-command/main.cpp
diffstat 25 files changed, 585 insertions(+), 195 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd/irccd/daemon/transport_client.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/libirccd/irccd/daemon/transport_client.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -54,7 +54,9 @@
     assert(code);
 
     auto json = nlohmann::json::object({
-        { "error", code.value() }
+        { "error",          code.value()            },
+        { "errorCategory",  code.category().name()  },
+        { "errorMessage",   code.message()          }
     });
 
     if (!cname.empty())
--- a/tests/src/plugin-config-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/plugin-config-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -134,13 +134,15 @@
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-config" },
         { "plugin",     "unknown"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -148,6 +150,8 @@
     });
 
     BOOST_ASSERT(result == plugin_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/plugin-info-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/plugin-info-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -63,13 +63,15 @@
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-info"   },
         { "plugin",     "unknown"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -77,6 +79,8 @@
     });
 
     BOOST_ASSERT(result == plugin_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/plugin-load-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/plugin-load-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -118,13 +118,15 @@
 BOOST_AUTO_TEST_CASE(already_exists)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-load"   },
         { "plugin",     "already"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -132,18 +134,22 @@
     });
 
     BOOST_ASSERT(result == plugin_error::already_exists);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::already_exists);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_CASE(exec_error)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-load"   },
         { "plugin",     "broken"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -151,6 +157,8 @@
     });
 
     BOOST_ASSERT(result == plugin_error::exec_error);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::exec_error);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/plugin-reload-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/plugin-reload-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -88,13 +88,15 @@
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-reload" },
         { "plugin",     "unknown"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -102,18 +104,22 @@
     });
 
     BOOST_ASSERT(result == plugin_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_CASE(exec_error)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-reload" },
         { "plugin",     "broken"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -121,6 +127,8 @@
     });
 
     BOOST_ASSERT(result == plugin_error::exec_error);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::exec_error);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/plugin-unload-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/plugin-unload-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -88,13 +88,15 @@
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-unload" },
         { "plugin",     "unknown"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -102,18 +104,22 @@
     });
 
     BOOST_ASSERT(result == plugin_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
 }
 
 BOOST_AUTO_TEST_CASE(exec_error)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "plugin-unload" },
         { "plugin",     "broken"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -121,6 +127,8 @@
     });
 
     BOOST_ASSERT(result == plugin_error::exec_error);
+    BOOST_ASSERT(message["error"].template get<int>() == plugin_error::exec_error);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "plugin");
     BOOST_ASSERT(!daemon_->plugins().has("broken"));
 }
 
--- a/tests/src/rule-add-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/rule-add-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -176,13 +176,15 @@
 BOOST_AUTO_TEST_CASE(invalid_action)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-add"  },
         { "action",     "unknown"   }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -190,6 +192,8 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_action);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_action);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/rule-edit-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/rule-edit-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -546,14 +546,16 @@
 BOOST_AUTO_TEST_CASE(invalid_index_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-edit" },
         { "index",      -100        },
         { "action",     "drop"      }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -561,19 +563,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-edit" },
         { "index",      100         },
         { "action",     "drop"      }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -581,19 +587,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_3)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-edit" },
         { "index",      "notaint"   },
         { "action",     "drop"      }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -601,19 +611,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_action)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-edit" },
         { "index",      0           },
         { "action",     "unknown"   }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -621,6 +635,8 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_action);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_action);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/rule-info-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/rule-info-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -96,13 +96,15 @@
 BOOST_AUTO_TEST_CASE(invalid_index_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-info" },
         { "index",      -100        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -110,18 +112,22 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-info" },
         { "index",      100         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -129,18 +135,22 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_3)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-info" },
         { "index",      "notaint"   }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -148,6 +158,8 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/rule-move-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/rule-move-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -366,14 +366,16 @@
 BOOST_AUTO_TEST_CASE(invalid_index_1_from)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-move" },
         { "from",       -100        },
         { "to",         0           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -381,19 +383,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_1_to)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-move" },
         { "from",       0           },
         { "to",         -100        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -401,19 +407,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_2_from)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-move" },
         { "from",       100         },
         { "to",         0           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -421,19 +431,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_3_from)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-move" },
         { "from",       "notaint"   },
         { "to",         0           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -441,19 +455,23 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_3_to)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-move" },
         { "from",       0           },
         { "to",         "notaint"   }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -461,6 +479,8 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/rule-remove-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/rule-remove-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -131,13 +131,15 @@
 BOOST_AUTO_TEST_CASE(invalid_index_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-remove"   },
         { "index",      -100            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -145,18 +147,22 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-remove"   },
         { "index",      100             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -164,18 +170,22 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_index_3)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "rule-remove"   },
         { "index",      "notaint"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -183,6 +193,8 @@
     });
 
     BOOST_ASSERT(result == rule_error::invalid_index);
+    BOOST_ASSERT(message["error"].template get<int>() == rule_error::invalid_index);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "rule");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-connect-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-connect-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -108,6 +108,7 @@
 BOOST_AUTO_TEST_CASE(already_exists)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     daemon_->servers().add(std::make_unique<journal_server>(service_, "local"));
     ctl_->send({
@@ -115,8 +116,9 @@
         { "name",       "local"             },
         { "host",       "127.0.0.1"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -124,18 +126,22 @@
     });
 
     BOOST_ASSERT(result == server_error::already_exists);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::already_exists);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_hostname_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
         { "name",       "new"               },
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -143,19 +149,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_hostname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_hostname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_hostname_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
         { "name",       "new"               },
         { "host",       123456              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -163,19 +173,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_hostname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_hostname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
         { "name",       ""                  },
         { "host",       "127.0.0.1"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -183,19 +197,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
         { "name",       123456              },
         { "host",       "127.0.0.1"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -203,11 +221,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_port_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
@@ -215,8 +236,9 @@
         { "host",       "127.0.0.1"         },
         { "port",       "notaint"           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -224,11 +246,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_port);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_port);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_port_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
@@ -236,8 +261,9 @@
         { "host",       "127.0.0.1"         },
         { "port",       -123                }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -245,11 +271,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_port);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_port);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_port_3)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
@@ -257,8 +286,9 @@
         { "host",       "127.0.0.1"         },
         { "port",       1000000             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -266,6 +296,8 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_port);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_port);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 #if !defined(HAVE_SSL)
@@ -273,6 +305,7 @@
 BOOST_AUTO_TEST_CASE(ssl_disabled)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-connect"    },
@@ -280,8 +313,9 @@
         { "host",       "127.0.0.1"         },
         { "ssl",        true                }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -289,6 +323,8 @@
     });
 
     BOOST_ASSERT(result == server_error::ssl_disabled);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::ssl_disabled);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 #endif
--- a/tests/src/server-disconnect-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-disconnect-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -85,13 +85,15 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-disconnect" },
         { "server",     123456              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -99,18 +101,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-disconnect" },
         { "server",     "unknown"           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -118,6 +124,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-info-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-info-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -72,13 +72,15 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-info"   },
         { "server",     123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -86,18 +88,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-info"   },
         { "server",     ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -105,18 +111,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-info"   },
         { "server",     "unknown"       }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -124,6 +134,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-invite-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-invite-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -74,8 +75,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -95,8 +100,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -116,8 +125,9 @@
         { "target",     ""              },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -137,8 +150,9 @@
         { "target",     123456          },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -158,8 +175,9 @@
         { "target",     "jean"          },
         { "channel",    ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,11 +185,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -179,8 +200,9 @@
         { "target",     "jean"          },
         { "channel",    123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -188,11 +210,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-invite" },
@@ -200,8 +225,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -209,6 +235,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-join-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-join-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -86,14 +86,16 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-join"   },
         { "server",     123456          },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -101,19 +103,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-join"   },
         { "server",     ""              },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -121,19 +127,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-join"   },
         { "server",     "test"          },
         { "channel",    ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -141,19 +151,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-join"   },
         { "server",     "test"          },
         { "channel",    123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -161,19 +175,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-join"   },
         { "server",     "unknown"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -181,6 +199,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-kick-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-kick-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -90,6 +90,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -97,8 +98,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -106,11 +108,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -118,8 +123,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -127,11 +133,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -139,8 +148,9 @@
         { "target",     ""              },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -148,11 +158,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -160,8 +173,9 @@
         { "target",     123456          },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -169,11 +183,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -181,8 +198,9 @@
         { "target",     "jean"          },
         { "channel",    ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -190,11 +208,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -202,8 +223,9 @@
         { "target",     "jean"          },
         { "channel",    123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -211,11 +233,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-kick"   },
@@ -223,8 +248,9 @@
         { "target",     "francis"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -232,6 +258,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-me-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-me-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-me" },
@@ -74,8 +75,9 @@
         { "target",     "#music"    },
         { "message",    "hello!"    }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-me" },
@@ -95,8 +100,9 @@
         { "target",     "#music"    },
         { "message",    "hello!"    }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-me" },
@@ -116,8 +125,9 @@
         { "target",     ""          },
         { "message",    "hello!"    }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-me" },
@@ -137,8 +150,9 @@
         { "target",     123456      },
         { "message",    "hello!"    }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-me" },
@@ -158,8 +175,9 @@
         { "target",     "#music"    },
         { "message",    "hello!"    }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,6 +185,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-message-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-message-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-message"    },
@@ -74,8 +75,9 @@
         { "target",     "#music"            },
         { "message",    "plop!"             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-message"    },
@@ -95,8 +100,9 @@
         { "target",     "#music"            },
         { "message",    "plop!"             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-message"    },
@@ -116,8 +125,9 @@
         { "target",     ""                  },
         { "message",    "plop!"             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-message"    },
@@ -137,8 +150,9 @@
         { "target",     123456              },
         { "message",    "plop!"             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-message"    },
@@ -158,8 +175,9 @@
         { "target",     "#music"            },
         { "message",    "plop!"             }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,6 +185,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-mode-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-mode-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -74,8 +75,9 @@
         { "channel",    "#music"        },
         { "mode",       "+i"            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -95,8 +100,9 @@
         { "channel",    "#music"        },
         { "mode",       "+i"            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -116,8 +125,9 @@
         { "channel",    ""              },
         { "mode",       "+i"            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -137,8 +150,9 @@
         { "channel",    123456          },
         { "mode",       "+i"            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_mode_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -158,8 +175,9 @@
         { "channel",    "#music"        },
         { "mode",       ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,11 +185,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_mode);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_mode);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_mode_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -179,8 +200,9 @@
         { "channel",    "#music"        },
         { "mode",       123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -188,10 +210,13 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_mode);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_mode);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-mode"   },
@@ -199,8 +224,9 @@
         { "channel",    "#music"        },
         { "mode",       "+i"            }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -208,6 +234,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-nick-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-nick-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -68,14 +68,16 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-nick"   },
         { "server",     123456          },
         { "nickname",   "chris"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,19 +85,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-nick"   },
         { "server",     ""              },
         { "nickname",   "chris"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -103,19 +109,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-nick"   },
         { "server",     "test"          },
         { "nickname",   ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -123,19 +133,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_nickname_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-nick"   },
         { "server",     "test"          },
         { "nickname",   123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -143,18 +157,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_nickname);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_nickname);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-nick"   },
         { "server",     "unknown"       },
         { "nickname",   "chris"         }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -162,6 +180,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-notice-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-notice-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-notice" },
@@ -74,8 +75,9 @@
         { "target",     "#music"        },
         { "message",    "quiet!"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-notice" },
@@ -95,8 +100,9 @@
         { "target",     "#music"        },
         { "message",    "quiet!"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-notice" },
@@ -116,8 +125,9 @@
         { "target",     ""              },
         { "message",    "quiet!"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-notice" },
@@ -137,8 +150,9 @@
         { "target",     123456          },
         { "message",    "quiet!"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-notice" },
@@ -158,8 +175,9 @@
         { "target",     "#music"        },
         { "message",    "quiet!"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,6 +185,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-part-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-part-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -86,14 +86,16 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-part"   },
         { "server",     123456          },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -101,19 +103,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-part"   },
         { "server",     ""              },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -121,19 +127,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-part"   },
         { "server",     "test"          },
         { "channel",    ""              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -141,19 +151,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-part"   },
         { "server",     "test"          },
         { "channel",    123456          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -161,19 +175,23 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-part"   },
         { "server",     "unknown"       },
         { "channel",    "#music"        }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -181,6 +199,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-reconnect-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-reconnect-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -81,13 +81,15 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-reconnect"  },
         { "server",     123456              }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -95,18 +97,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-reconnect"  },
         { "server",     ""                  }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -114,18 +120,22 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-reconnect"  },
         { "server",     "unknown"           }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -133,6 +143,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/server-topic-command/main.cpp	Mon Dec 11 15:00:36 2017 +0100
+++ b/tests/src/server-topic-command/main.cpp	Thu Dec 14 21:45:32 2017 +0100
@@ -67,6 +67,7 @@
 BOOST_AUTO_TEST_CASE(invalid_identifier_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-topic"  },
@@ -74,8 +75,9 @@
         { "channel",    "#music"        },
         { "topic",      "plop"          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -83,11 +85,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_identifier_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-topic"  },
@@ -95,8 +100,9 @@
         { "channel",    "#music"        },
         { "topic",      "plop"          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -104,11 +110,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_identifier);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_identifier);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_1)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-topic"  },
@@ -116,8 +125,9 @@
         { "channel",    ""              },
         { "topic",      "plop"          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -125,11 +135,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(invalid_channel_2)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-topic"  },
@@ -137,8 +150,9 @@
         { "channel",    123456          },
         { "topic",      "plop"          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -146,11 +160,14 @@
     });
 
     BOOST_ASSERT(result == server_error::invalid_channel);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::invalid_channel);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_CASE(not_found)
 {
     boost::system::error_code result;
+    nlohmann::json message;
 
     ctl_->send({
         { "command",    "server-topic"  },
@@ -158,8 +175,9 @@
         { "channel",    "#music"        },
         { "topic",      "plop"          }
     });
-    ctl_->recv([&] (auto code, auto) {
-        result = code;
+    ctl_->recv([&] (auto rresult, auto rmessage) {
+        result = rresult;
+        message = rmessage;
     });
 
     wait_for([&] {
@@ -167,6 +185,8 @@
     });
 
     BOOST_ASSERT(result == server_error::not_found);
+    BOOST_ASSERT(message["error"].template get<int>() == server_error::not_found);
+    BOOST_ASSERT(message["errorCategory"].template get<std::string>() == "server");
 }
 
 BOOST_AUTO_TEST_SUITE_END()