diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 8e3a7b3277..cf160f7756 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -510,13 +510,14 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b bot.on_voice_receive_combined([&](auto& event) { }); - + std::promise ready_promise; + std::future ready_future = ready_promise.get_future(); bot.on_ready([&](const dpp::ready_t & event) { - set_test("CONNECTION", true); + ready_promise.set_value(); + set_test("APPCOMMAND", false); set_test("LOGGER", false); - bot.log(dpp::ll_info, "Test log message"); bot.guild_command_create(dpp::slashcommand().set_name("testcommand") @@ -567,7 +568,248 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b }); } }); + }); + + std::mutex loglock; + bot.on_log([&](const dpp::log_t & event) { + std::lock_guard locker(loglock); + if (event.severity > dpp::ll_trace) { + std::cout << "[" << std::fixed << std::setprecision(3) << (dpp::utility::time_f() - get_start_time()) << "]: [\u001b[36m" << dpp::utility::loglevel(event.severity) << "\u001b[0m] " << event.message << "\n"; + } + if (event.message == "Test log message") { + set_test("LOGGER", true); + } + }); + + set_test("RUNONCE", false); + uint8_t runs = 0; + for (int x = 0; x < 10; ++x) { + if (dpp::run_once()) { + runs++; + } + } + set_test("RUNONCE", (runs == 1)); + + bot.on_message_reaction_add([&](const dpp::message_reaction_add_t & event) { + if (event.reacting_user.id == bot.me.id && event.reacting_emoji.name == "😄") { + set_test("REACTEVENT", true); + } + }); + + bool message_edit_tested = false; + bot.on_message_update([&](const dpp::message_update_t & event) { + if (!message_edit_tested && event.msg.author == bot.me.id && event.msg.content == "test edit") { + message_edit_tested = true; + set_test("EDITEVENT", true); + } + }); + + bot.on_voice_ready([&](const dpp::voice_ready_t & event) { + set_test("VOICECONN", true); + dpp::discord_voice_client* v = event.voice_client; + set_test("VOICESEND", false); + if (v && v->is_ready()) { + v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); + } else { + set_test("VOICESEND", false); + } + }); + + bot.on_voice_buffer_send([&](const dpp::voice_buffer_send_t & event) { + if (event.buffer_size == 0) { + set_test("VOICESEND", true); + } + }); + + set_test("SYNC", false); + if (!offline) { + dpp::message m = dpp::sync(&bot, &dpp::cluster::message_create, dpp::message(TEST_TEXT_CHANNEL_ID, "TEST")); + set_test("SYNC", m.content == "TEST"); + } + + bot.on_guild_create([&](const dpp::guild_create_t & event) { + if (event.created->id == TEST_GUILD_ID) { + set_test("GUILDCREATE", true); + if (event.presences.size() && event.presences.begin()->second.user_id > 0) { + set_test("PRESENCE", true); + } + dpp::guild* g = dpp::find_guild(TEST_GUILD_ID); + set_test("CACHE", false); + if (g) { + set_test("CACHE", true); + set_test("VOICECONN", false); + dpp::discord_client* s = bot.get_shard(0); + s->connect_voice(g->id, TEST_VC_ID, false, false); + } + else { + set_test("CACHE", false); + } + } + }); + + // this helper class contains logic for the message tests, deletes the message when all tests are done + class message_test_helper + { + private: + std::mutex mutex; + bool pin_tested; + std::array files_tested; + std::array files_success; + dpp::snowflake channel_id; + dpp::snowflake message_id; + dpp::cluster ⊥ + + void delete_message_if_done() { + if (files_tested == std::array{true, true, true} && pin_tested) { + set_test("MESSAGEDELETE", false); + bot.message_delete(message_id, channel_id, [](const dpp::confirmation_callback_t &callback) { + if (!callback.is_error()) { + set_test("MESSAGEDELETE", true); + } + }); + } + } + + void set_pin_tested() { + assert(!pin_tested); + pin_tested = true; + delete_message_if_done(); + } + + void set_file_tested(size_t index) { + assert(!files_tested[index]); + files_tested[index] = true; + if (files_tested == std::array{true, true, true}) { + set_test("MESSAGEFILE", files_success == std::array{true, true, true}); + } + delete_message_if_done(); + } + + void test_files(const dpp::message &message) { + set_test("MESSAGEFILE", false); + if (message.attachments.size() == 3) { + static constexpr auto check_mimetype = [](const auto &headers, std::string mimetype) { + if (auto it = headers.find("content-type"); it != headers.end()) { + // check that the mime type starts with what we gave : for example discord will change "text/plain" to "text/plain; charset=UTF-8" + return it->second.size() >= mimetype.size() && std::equal(it->second.begin(), it->second.begin() + mimetype.size(), mimetype.begin()); + } + else { + return false; + } + }; + message.attachments[0].download([&](const dpp::http_request_completion_t &callback) { + std::lock_guard lock(mutex); + if (callback.status == 200 && callback.body == "test") { + files_success[0] = true; + } + set_file_tested(0); + }); + message.attachments[1].download([&](const dpp::http_request_completion_t &callback) { + std::lock_guard lock(mutex); + if (callback.status == 200 && check_mimetype(callback.headers, "text/plain") && callback.body == "test") { + files_success[1] = true; + } + set_file_tested(1); + }); + message.attachments[2].download([&](const dpp::http_request_completion_t &callback) { + std::lock_guard lock(mutex); + // do not check the contents here because discord can change compression + if (callback.status == 200 && check_mimetype(callback.headers, "image/png")) { + files_success[2] = true; + } + set_file_tested(2); + }); + } + else { + set_file_tested(0); + set_file_tested(1); + set_file_tested(2); + } + } + + void test_pin() { + set_test("MESSAGEPIN", false); + set_test("MESSAGEUNPIN", false); + bot.message_pin(channel_id, message_id, [=](const dpp::confirmation_callback_t &callback) { + std::lock_guard lock(mutex); + if (!callback.is_error()) { + set_test("MESSAGEPIN", true); + bot.message_unpin(TEST_TEXT_CHANNEL_ID, message_id, [=](const dpp::confirmation_callback_t &callback) { + std::lock_guard lock(mutex); + if (!callback.is_error()) { + set_test("MESSAGEUNPIN", true); + } + set_pin_tested(); + }); + } + else { + set_pin_tested(); + } + }); + } + + public: + message_test_helper(dpp::cluster &_bot) : bot(_bot) {} + + void run(const dpp::message &message) { + pin_tested = false; + files_tested = {false, false, false}; + files_success = {false, false, false}; + channel_id = message.channel_id; + message_id = message.id; + test_pin(); + test_files(message); + } + }; + + message_test_helper message_helper(bot); + bool message_tested = false; + bot.on_message_create([&](const dpp::message_create_t & event) { + if (event.msg.author.id == bot.me.id && !message_tested) { + message_tested = true; + set_test("MESSAGERECEIVE", true); + message_helper.run(event.msg); + set_test("MESSAGESGET", false); + bot.messages_get(event.msg.channel_id, 0, event.msg.id, 0, 5, [](const dpp::confirmation_callback_t &cc){ + if (!cc.is_error()) { + dpp::message_map mm = std::get(cc.value); + if (mm.size()) { + set_test("MESSAGESGET", true); + set_test("TIMESTAMP", false); + dpp::message m = mm.begin()->second; + if (m.sent > 0) { + set_test("TIMESTAMP", true); + } else { + set_test("TIMESTAMP", false); + } + } else { + set_test("MESSAGESGET", false); + } + } else { + set_test("MESSAGESGET", false); + } + }); + set_test("MSGCREATESEND", false); + event.send("MSGCREATESEND", [&bot, ch_id = event.msg.channel_id] (const auto& cc) { + if (!cc.is_error()) { + dpp::message m = std::get(cc.value); + if (m.channel_id == ch_id) { + set_test("MSGCREATESEND", true); + } else { + bot.log(dpp::ll_debug, cc.http_info.body); + set_test("MSGCREATESEND", false); + } + bot.message_delete(m.id, m.channel_id); + } else { + bot.log(dpp::ll_debug, cc.http_info.body); + set_test("MSGCREATESEND", false); + } + }); + } + }); + // set to execute from this thread (main thread) after on_ready is fired + auto do_online_tests = [&] { set_test("GUILD_BAN_CREATE", false); set_test("GUILD_BAN_GET", false); set_test("GUILD_BANS_GET", false); @@ -957,192 +1199,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test("ROLE_DELETE", false); } } - }); - - std::mutex loglock; - bot.on_log([&](const dpp::log_t & event) { - std::lock_guard locker(loglock); - if (event.severity > dpp::ll_trace) { - std::cout << "[" << std::fixed << std::setprecision(3) << (dpp::utility::time_f() - get_start_time()) << "]: [\u001b[36m" << dpp::utility::loglevel(event.severity) << "\u001b[0m] " << event.message << "\n"; - } - if (event.message == "Test log message") { - set_test("LOGGER", true); - } - }); - - set_test("RUNONCE", false); - uint8_t runs = 0; - for (int x = 0; x < 10; ++x) { - if (dpp::run_once()) { - runs++; - } - } - set_test("RUNONCE", (runs == 1)); - - bot.on_message_reaction_add([&](const dpp::message_reaction_add_t & event) { - if (event.reacting_user.id == bot.me.id && event.reacting_emoji.name == "😄") { - set_test("REACTEVENT", true); - } - }); - - bool message_edit_tested = false; - bot.on_message_update([&](const dpp::message_update_t & event) { - if (!message_edit_tested && event.msg.author == bot.me.id && event.msg.content == "test edit") { - message_edit_tested = true; - set_test("EDITEVENT", true); - } - }); - - bot.on_voice_ready([&](const dpp::voice_ready_t & event) { - set_test("VOICECONN", true); - dpp::discord_voice_client* v = event.voice_client; - set_test("VOICESEND", false); - if (v && v->is_ready()) { - v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); - } else { - set_test("VOICESEND", false); - } - }); - - bot.on_voice_buffer_send([&](const dpp::voice_buffer_send_t & event) { - if (event.buffer_size == 0) { - set_test("VOICESEND", true); - } - }); - - set_test("SYNC", false); - if (!offline) { - dpp::message m = dpp::sync(&bot, &dpp::cluster::message_create, dpp::message(TEST_TEXT_CHANNEL_ID, "TEST")); - set_test("SYNC", m.content == "TEST"); - } - - bot.on_guild_create([&](const dpp::guild_create_t & event) { - if (event.created->id == TEST_GUILD_ID) { - set_test("GUILDCREATE", true); - if (event.presences.size() && event.presences.begin()->second.user_id > 0) { - set_test("PRESENCE", true); - } - dpp::guild* g = dpp::find_guild(TEST_GUILD_ID); - set_test("CACHE", false); - if (g) { - set_test("CACHE", true); - set_test("VOICECONN", false); - dpp::discord_client* s = bot.get_shard(0); - s->connect_voice(g->id, TEST_VC_ID, false, false); - } - else { - set_test("CACHE", false); - } - } - }); - - bool message_tested = false; - bot.on_message_create([&](const dpp::message_create_t & event) { - if (event.msg.author.id == bot.me.id && !message_tested) { - message_tested = true; - set_test("MESSAGERECEIVE", true); - std::promise pin_test_promise; - auto pin_test_future = pin_test_promise.get_future(); - set_test("MESSAGEPIN", false); - set_test("MESSAGEUNPIN", false); - bot.message_pin(event.msg.channel_id, event.msg.id, [&bot, id = event.msg.id, &pin_test_promise](const dpp::confirmation_callback_t &callback) { - if (!callback.is_error()) { - set_test("MESSAGEPIN", true); - bot.message_unpin(TEST_TEXT_CHANNEL_ID, id, [&pin_test_promise](const dpp::confirmation_callback_t &callback) { - if (!callback.is_error()) { - set_test("MESSAGEUNPIN", true); - } - pin_test_promise.set_value(); - }); - } else { - pin_test_promise.set_value(); - } - }); - set_test("MESSAGEFILE", false); - std::promise file_test_promise; - auto file_test_future = file_test_promise.get_future(); - if (event.msg.attachments.size() == 3) - { - constexpr auto check_mimetype = [](const auto &headers, std::string mimetype) { - if (auto it = headers.find("content-type"); it != headers.end()) { - // check that the mime type starts with what we gave : for example discord will change "text/plain" to "text/plain; charset=UTF-8" - return it->second.size() >= mimetype.size() && std::equal(it->second.begin(), it->second.begin() + mimetype.size(), mimetype.begin()); - } - else { - return false; - } - }; - event.msg.attachments[0].download([&](const dpp::http_request_completion_t &callback){ - if (callback.status == 200 && callback.body == "test") { - event.msg.attachments[1].download([&](const dpp::http_request_completion_t &callback){ - if (callback.status == 200 && check_mimetype(callback.headers, "text/plain") && callback.body == "test") { - event.msg.attachments[2].download([&](const dpp::http_request_completion_t &callback){ - // do not check the contents here because discord can change compression - if (callback.status == 200 && check_mimetype(callback.headers, "image/png")) { - set_test("MESSAGEFILE", true); - } - file_test_promise.set_value(); - }); - } - else { - file_test_promise.set_value(); - } - }); - } - else { - file_test_promise.set_value(); - } - }); - } - set_test("MESSAGESGET", false); - bot.messages_get(event.msg.channel_id, 0, event.msg.id, 0, 5, [](const dpp::confirmation_callback_t &cc){ - if (!cc.is_error()) { - dpp::message_map mm = std::get(cc.value); - if (mm.size()) { - set_test("MESSAGESGET", true); - set_test("TIMESTAMP", false); - dpp::message m = mm.begin()->second; - if (m.sent > 0) { - set_test("TIMESTAMP", true); - } else { - set_test("TIMESTAMP", false); - } - } else { - set_test("MESSAGESGET", false); - } - } else { - set_test("MESSAGESGET", false); - } - }); - // wait for tasks with the message to finish before deleting, up to 20 seconds - std::chrono::time_point timeout_point = std::chrono::steady_clock::now() + std::chrono::seconds(20); - pin_test_future.wait_until(timeout_point); - file_test_future.wait_until(timeout_point); - set_test("MESSAGEDELETE", false); - bot.message_delete(event.msg.id, event.msg.channel_id, [](const dpp::confirmation_callback_t &callback) { - - if (!callback.is_error()) { - set_test("MESSAGEDELETE", true); - } - }); - set_test("MSGCREATESEND", false); - event.send("MSGCREATESEND", [&bot, ch_id = event.msg.channel_id] (const auto& cc) { - if (!cc.is_error()) { - dpp::message m = std::get(cc.value); - if (m.channel_id == ch_id) { - set_test("MSGCREATESEND", true); - } else { - bot.log(dpp::ll_debug, cc.http_info.body); - set_test("MSGCREATESEND", false); - } - bot.message_delete(m.id, m.channel_id); - } else { - bot.log(dpp::ll_debug, cc.http_info.body); - set_test("MSGCREATESEND", false); - } - }); - } - }); + }; set_test("BOTSTART", false); try { @@ -1220,6 +1277,12 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b } testcache.remove(found_tco); + if (!offline) { + if (std::future_status status = ready_future.wait_for(std::chrono::seconds(20)); status != std::future_status::timeout) { + do_online_tests(); + } + } + noparam_api_test(current_user_get, dpp::user_identified, "CURRENTUSER"); singleparam_api_test(channel_get, TEST_TEXT_CHANNEL_ID, dpp::channel, "GETCHAN"); singleparam_api_test(guild_get, TEST_GUILD_ID, dpp::guild, "GETGUILD");