diff --git a/.clang-tidy b/.clang-tidy index db94ae838..4fe0bb846 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -36,8 +36,12 @@ CheckOptions: value: CamelCase - key: readability-identifier-naming.EnumCase value: CamelCase + - key: readability-identifier-naming.FunctionCase value: camelBack + - key: readability-identifier-naming.FunctionIgnoredRegexp + value: ^TEST$ + - key: readability-identifier-naming.MemberCase value: camelBack - key: readability-identifier-naming.PrivateMemberIgnoredRegexp diff --git a/.sanitizers/asan-suppressions b/.sanitizers/asan-suppressions new file mode 100644 index 000000000..8361de184 --- /dev/null +++ b/.sanitizers/asan-suppressions @@ -0,0 +1,2 @@ +# Ignore openssl issues +interceptor_via_lib:libcrypto.so.3 diff --git a/.sanitizers/lsan-suppressions b/.sanitizers/lsan-suppressions new file mode 100644 index 000000000..bd4eb5fbf --- /dev/null +++ b/.sanitizers/lsan-suppressions @@ -0,0 +1,3 @@ +# Ignore openssl issues +leak:libcrypto.so.3 +leak:CRYPTO_zalloc diff --git a/.sanitizers/tsan-suppressions b/.sanitizers/tsan-suppressions new file mode 100644 index 000000000..1f9b93e6f --- /dev/null +++ b/.sanitizers/tsan-suppressions @@ -0,0 +1,17 @@ +race:libdbus-1.so.3 +deadlock:libdbus-1.so.3 +race:libglib-2.0.so.0 +race:libgio-2.0.so.0 + +# Not sure about these suppression +# race:qscopedpointer.h +# race:qarraydata.cpp +# race:qarraydata.h +# race:qarraydataops.h +# race:libQt6Core.so.6 +# race:libQt6Gui.so.6 +# race:libQt6XcbQpa.so.6 +# race:libQt6Network.so.6 + +# very not sure about this one +# race:qstring.h diff --git a/.sanitizers/ubsan-suppressions b/.sanitizers/ubsan-suppressions new file mode 100644 index 000000000..4d35c4bef --- /dev/null +++ b/.sanitizers/ubsan-suppressions @@ -0,0 +1,2 @@ +enum:NetworkResult.hpp +enum:gtest.h diff --git a/mocks/include/mocks/EmptyApplication.hpp b/mocks/include/mocks/EmptyApplication.hpp index afb53d5a9..b839d04a4 100644 --- a/mocks/include/mocks/EmptyApplication.hpp +++ b/mocks/include/mocks/EmptyApplication.hpp @@ -7,6 +7,8 @@ namespace chatterino::mock { class EmptyApplication : public IApplication { public: + virtual ~EmptyApplication() = default; + Theme *getThemes() override { return nullptr; diff --git a/src/providers/twitch/PubSubActions.hpp b/src/providers/twitch/PubSubActions.hpp index d698b9aef..89abdb244 100644 --- a/src/providers/twitch/PubSubActions.hpp +++ b/src/providers/twitch/PubSubActions.hpp @@ -33,6 +33,7 @@ inline QDebug operator<<(QDebug dbg, const ActionUser &user) } struct PubSubAction { + PubSubAction() = default; PubSubAction(const QJsonObject &data, const QString &_roomID); ActionUser source; diff --git a/src/providers/twitch/PubSubManager.hpp b/src/providers/twitch/PubSubManager.hpp index ea8138d2d..40f6a44e9 100644 --- a/src/providers/twitch/PubSubManager.hpp +++ b/src/providers/twitch/PubSubManager.hpp @@ -77,8 +77,6 @@ public: void setAccountData(QString token, QString userID); - ~PubSub() = delete; - enum class State { Connected, Disconnected, diff --git a/src/providers/twitch/pubsubmessages/AutoMod.hpp b/src/providers/twitch/pubsubmessages/AutoMod.hpp index d0e520825..400169ac7 100644 --- a/src/providers/twitch/pubsubmessages/AutoMod.hpp +++ b/src/providers/twitch/pubsubmessages/AutoMod.hpp @@ -31,7 +31,8 @@ struct PubSubAutoModQueueMessage { QString senderUserDisplayName; QColor senderUserChatColor; - PubSubAutoModQueueMessage(const QJsonObject &root); + PubSubAutoModQueueMessage() = default; + explicit PubSubAutoModQueueMessage(const QJsonObject &root); }; } // namespace chatterino diff --git a/src/providers/twitch/pubsubmessages/Whisper.hpp b/src/providers/twitch/pubsubmessages/Whisper.hpp index 96179f07f..ef96cd62b 100644 --- a/src/providers/twitch/pubsubmessages/Whisper.hpp +++ b/src/providers/twitch/pubsubmessages/Whisper.hpp @@ -28,7 +28,8 @@ struct PubSubWhisperMessage { QString fromUserDisplayName; QColor fromUserColor; - PubSubWhisperMessage(const QJsonObject &root); + PubSubWhisperMessage() = default; + explicit PubSubWhisperMessage(const QJsonObject &root); }; } // namespace chatterino diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a760c6d87..06b16c8a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ option(CHATTERINO_TEST_USE_PUBLIC_HTTPBIN "Use public httpbin for testing networ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/main.cpp ${CMAKE_CURRENT_LIST_DIR}/resources/test-resources.qrc + ${CMAKE_CURRENT_LIST_DIR}/src/TestHelpers.hpp ${CMAKE_CURRENT_LIST_DIR}/src/ChannelChatters.cpp ${CMAKE_CURRENT_LIST_DIR}/src/AccessGuard.cpp ${CMAKE_CURRENT_LIST_DIR}/src/NetworkCommon.cpp diff --git a/tests/src/BasicPubSub.cpp b/tests/src/BasicPubSub.cpp index d4fc0143b..dc2775220 100644 --- a/tests/src/BasicPubSub.cpp +++ b/tests/src/BasicPubSub.cpp @@ -116,33 +116,33 @@ private: TEST(BasicPubSub, SubscriptionCycle) { const QString host("wss://127.0.0.1:9050/liveupdates/sub-unsub"); - auto *manager = new MyManager(host); - manager->start(); + MyManager manager(host); + manager.start(); std::this_thread::sleep_for(50ms); - manager->sub({1, "foo"}); + manager.sub({1, "foo"}); std::this_thread::sleep_for(500ms); - ASSERT_EQ(manager->diag.connectionsOpened, 1); - ASSERT_EQ(manager->diag.connectionsClosed, 0); - ASSERT_EQ(manager->diag.connectionsFailed, 0); - ASSERT_EQ(manager->messagesReceived, 1); + ASSERT_EQ(manager.diag.connectionsOpened, 1); + ASSERT_EQ(manager.diag.connectionsClosed, 0); + ASSERT_EQ(manager.diag.connectionsFailed, 0); + ASSERT_EQ(manager.messagesReceived, 1); - ASSERT_EQ(manager->popMessage(), QString("ack-sub-1-foo")); + ASSERT_EQ(manager.popMessage(), QString("ack-sub-1-foo")); - manager->unsub({1, "foo"}); + manager.unsub({1, "foo"}); std::this_thread::sleep_for(50ms); - ASSERT_EQ(manager->diag.connectionsOpened, 1); - ASSERT_EQ(manager->diag.connectionsClosed, 0); - ASSERT_EQ(manager->diag.connectionsFailed, 0); - ASSERT_EQ(manager->messagesReceived, 2); - ASSERT_EQ(manager->popMessage(), QString("ack-unsub-1-foo")); + ASSERT_EQ(manager.diag.connectionsOpened, 1); + ASSERT_EQ(manager.diag.connectionsClosed, 0); + ASSERT_EQ(manager.diag.connectionsFailed, 0); + ASSERT_EQ(manager.messagesReceived, 2); + ASSERT_EQ(manager.popMessage(), QString("ack-unsub-1-foo")); - manager->stop(); + manager.stop(); - ASSERT_EQ(manager->diag.connectionsOpened, 1); - ASSERT_EQ(manager->diag.connectionsClosed, 1); - ASSERT_EQ(manager->diag.connectionsFailed, 0); - ASSERT_EQ(manager->messagesReceived, 2); + ASSERT_EQ(manager.diag.connectionsOpened, 1); + ASSERT_EQ(manager.diag.connectionsClosed, 1); + ASSERT_EQ(manager.diag.connectionsFailed, 0); + ASSERT_EQ(manager.messagesReceived, 2); } diff --git a/tests/src/BttvLiveUpdates.cpp b/tests/src/BttvLiveUpdates.cpp index 6c12388d1..5fbe9f581 100644 --- a/tests/src/BttvLiveUpdates.cpp +++ b/tests/src/BttvLiveUpdates.cpp @@ -4,6 +4,8 @@ #include #include +#include + using namespace chatterino; using namespace std::chrono_literals; @@ -13,30 +15,30 @@ const QString TARGET_USER_NAME = "Alien"; TEST(BttvLiveUpdates, AllEvents) { const QString host("wss://127.0.0.1:9050/liveupdates/bttv/all-events"); - auto *liveUpdates = new BttvLiveUpdates(host); - liveUpdates->start(); + chatterino::BttvLiveUpdates liveUpdates(host); + liveUpdates.start(); boost::optional addMessage; boost::optional updateMessage; boost::optional removeMessage; - liveUpdates->signals_.emoteAdded.connect([&](const auto &m) { + std::ignore = liveUpdates.signals_.emoteAdded.connect([&](const auto &m) { addMessage = m; }); - liveUpdates->signals_.emoteUpdated.connect([&](const auto &m) { + std::ignore = liveUpdates.signals_.emoteUpdated.connect([&](const auto &m) { updateMessage = m; }); - liveUpdates->signals_.emoteRemoved.connect([&](const auto &m) { + std::ignore = liveUpdates.signals_.emoteRemoved.connect([&](const auto &m) { removeMessage = m; }); std::this_thread::sleep_for(50ms); - liveUpdates->joinChannel(TARGET_USER_ID, TARGET_USER_NAME); + liveUpdates.joinChannel(TARGET_USER_ID, TARGET_USER_NAME); std::this_thread::sleep_for(500ms); - ASSERT_EQ(liveUpdates->diag.connectionsOpened, 1); - ASSERT_EQ(liveUpdates->diag.connectionsClosed, 0); - ASSERT_EQ(liveUpdates->diag.connectionsFailed, 0); + ASSERT_EQ(liveUpdates.diag.connectionsOpened, 1); + ASSERT_EQ(liveUpdates.diag.connectionsClosed, 0); + ASSERT_EQ(liveUpdates.diag.connectionsFailed, 0); auto add = *addMessage; ASSERT_EQ(add.channelID, TARGET_USER_ID); @@ -52,8 +54,8 @@ TEST(BttvLiveUpdates, AllEvents) ASSERT_EQ(rem.channelID, TARGET_USER_ID); ASSERT_EQ(rem.emoteID, QString("55898e122612142e6aaa935b")); - liveUpdates->stop(); - ASSERT_EQ(liveUpdates->diag.connectionsOpened, 1); - ASSERT_EQ(liveUpdates->diag.connectionsClosed, 1); - ASSERT_EQ(liveUpdates->diag.connectionsFailed, 0); + liveUpdates.stop(); + ASSERT_EQ(liveUpdates.diag.connectionsOpened, 1); + ASSERT_EQ(liveUpdates.diag.connectionsClosed, 1); + ASSERT_EQ(liveUpdates.diag.connectionsFailed, 0); } diff --git a/tests/src/Emojis.cpp b/tests/src/Emojis.cpp index ce6896d69..ed303ab29 100644 --- a/tests/src/Emojis.cpp +++ b/tests/src/Emojis.cpp @@ -17,7 +17,7 @@ TEST(Emojis, ShortcodeParsing) QString expectedOutput; }; - std::vector tests{ + const std::vector tests{ { // input "foo :penguin: bar", diff --git a/tests/src/SeventvEventAPI.cpp b/tests/src/SeventvEventAPI.cpp index 4c47e34c3..cbdadfb61 100644 --- a/tests/src/SeventvEventAPI.cpp +++ b/tests/src/SeventvEventAPI.cpp @@ -19,34 +19,34 @@ const QString TARGET_USER_ID = "60b39e943e203cc169dfc106"; TEST(SeventvEventAPI, AllEvents) { const QString host("wss://127.0.0.1:9050/liveupdates/seventv/all-events"); - auto *eventAPI = new SeventvEventAPI(host, std::chrono::milliseconds(1000)); - eventAPI->start(); + SeventvEventAPI eventAPI(host, std::chrono::milliseconds(1000)); + eventAPI.start(); boost::optional addDispatch; boost::optional updateDispatch; boost::optional removeDispatch; boost::optional userDispatch; - eventAPI->signals_.emoteAdded.connect([&](const auto &d) { + eventAPI.signals_.emoteAdded.connect([&](const auto &d) { addDispatch = d; }); - eventAPI->signals_.emoteUpdated.connect([&](const auto &d) { + eventAPI.signals_.emoteUpdated.connect([&](const auto &d) { updateDispatch = d; }); - eventAPI->signals_.emoteRemoved.connect([&](const auto &d) { + eventAPI.signals_.emoteRemoved.connect([&](const auto &d) { removeDispatch = d; }); - eventAPI->signals_.userUpdated.connect([&](const auto &d) { + eventAPI.signals_.userUpdated.connect([&](const auto &d) { userDispatch = d; }); std::this_thread::sleep_for(50ms); - eventAPI->subscribeUser("", EMOTE_SET_A); + eventAPI.subscribeUser("", EMOTE_SET_A); std::this_thread::sleep_for(500ms); - ASSERT_EQ(eventAPI->diag.connectionsOpened, 1); - ASSERT_EQ(eventAPI->diag.connectionsClosed, 0); - ASSERT_EQ(eventAPI->diag.connectionsFailed, 0); + ASSERT_EQ(eventAPI.diag.connectionsOpened, 1); + ASSERT_EQ(eventAPI.diag.connectionsClosed, 0); + ASSERT_EQ(eventAPI.diag.connectionsFailed, 0); auto add = *addDispatch; ASSERT_EQ(add.emoteSetID, EMOTE_SET_A); @@ -71,7 +71,7 @@ TEST(SeventvEventAPI, AllEvents) updateDispatch = boost::none; removeDispatch = boost::none; - eventAPI->subscribeUser(TARGET_USER_ID, ""); + eventAPI.subscribeUser(TARGET_USER_ID, ""); std::this_thread::sleep_for(50ms); ASSERT_EQ(addDispatch.has_value(), false); @@ -85,24 +85,24 @@ TEST(SeventvEventAPI, AllEvents) ASSERT_EQ(user.emoteSetID, EMOTE_SET_B); ASSERT_EQ(user.connectionIndex, 0); - eventAPI->stop(); - ASSERT_EQ(eventAPI->diag.connectionsOpened, 1); - ASSERT_EQ(eventAPI->diag.connectionsClosed, 1); - ASSERT_EQ(eventAPI->diag.connectionsFailed, 0); + eventAPI.stop(); + ASSERT_EQ(eventAPI.diag.connectionsOpened, 1); + ASSERT_EQ(eventAPI.diag.connectionsClosed, 1); + ASSERT_EQ(eventAPI.diag.connectionsFailed, 0); } TEST(SeventvEventAPI, NoHeartbeat) { const QString host("wss://127.0.0.1:9050/liveupdates/seventv/no-heartbeat"); - auto *eventApi = new SeventvEventAPI(host, std::chrono::milliseconds(1000)); - eventApi->start(); + SeventvEventAPI eventApi(host, std::chrono::milliseconds(1000)); + eventApi.start(); std::this_thread::sleep_for(50ms); - eventApi->subscribeUser("", EMOTE_SET_A); + eventApi.subscribeUser("", EMOTE_SET_A); std::this_thread::sleep_for(1250ms); - ASSERT_EQ(eventApi->diag.connectionsOpened, 2); - ASSERT_EQ(eventApi->diag.connectionsClosed, 1); - ASSERT_EQ(eventApi->diag.connectionsFailed, 0); + ASSERT_EQ(eventApi.diag.connectionsOpened, 2); + ASSERT_EQ(eventApi.diag.connectionsClosed, 1); + ASSERT_EQ(eventApi.diag.connectionsFailed, 0); - eventApi->stop(); + eventApi.stop(); } diff --git a/tests/src/TestHelpers.hpp b/tests/src/TestHelpers.hpp new file mode 100644 index 000000000..05190e0da --- /dev/null +++ b/tests/src/TestHelpers.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +template +class ReceivedMessage +{ + mutable std::mutex mutex; + + bool isSet{false}; + T t; + +public: + ReceivedMessage() = default; + + explicit operator bool() const + { + std::unique_lock lock(this->mutex); + + return this->isSet; + } + + ReceivedMessage &operator=(const T &newT) + { + std::unique_lock lock(this->mutex); + + this->isSet = true; + this->t = newT; + + return *this; + } + + bool operator==(const T &otherT) const + { + std::unique_lock lock(this->mutex); + + return this->t == otherT; + } + + const T *operator->() const + { + return &this->t; + } +}; diff --git a/tests/src/TwitchMessageBuilder.cpp b/tests/src/TwitchMessageBuilder.cpp index db8675ca1..f07b35af2 100644 --- a/tests/src/TwitchMessageBuilder.cpp +++ b/tests/src/TwitchMessageBuilder.cpp @@ -154,7 +154,7 @@ TEST(TwitchMessageBuilder, BadgeInfoParsing) for (const auto &test : testCases) { - auto privmsg = + auto *privmsg = Communi::IrcPrivateMessage::fromData(test.input, nullptr); auto outputBadgeInfo = @@ -166,6 +166,8 @@ TEST(TwitchMessageBuilder, BadgeInfoParsing) SharedMessageBuilder::parseBadgeTag(privmsg->tags()); EXPECT_EQ(outputBadges, test.expectedBadges) << "Input for badges " << test.input.toStdString() << " failed"; + + delete privmsg; } } @@ -343,5 +345,7 @@ TEST_F(TestTwitchMessageBuilder, ParseTwitchEmotes) EXPECT_EQ(actualTwitchEmotes, test.expectedTwitchEmotes) << "Input for twitch emotes " << test.input.toStdString() << " failed"; + + delete privmsg; } } diff --git a/tests/src/TwitchPubSubClient.cpp b/tests/src/TwitchPubSubClient.cpp index 9684fd248..6e1a12897 100644 --- a/tests/src/TwitchPubSubClient.cpp +++ b/tests/src/TwitchPubSubClient.cpp @@ -3,11 +3,13 @@ #include "providers/twitch/PubSubManager.hpp" #include "providers/twitch/pubsubmessages/AutoMod.hpp" #include "providers/twitch/pubsubmessages/Whisper.hpp" +#include "TestHelpers.hpp" #include #include #include +#include using namespace chatterino; using namespace std::chrono_literals; @@ -30,415 +32,395 @@ using namespace std::chrono_literals; #ifdef RUN_PUBSUB_TESTS +class FTest : public PubSub +{ +public: + explicit FTest(const char *path, std::chrono::seconds pingInterval) + : PubSub(QString("wss://127.0.0.1:9050%1").arg(path), pingInterval) + { + } +}; + TEST(TwitchPubSubClient, ServerRespondsToPings) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050"); + FTest pubSub("", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 0); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 0); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 0); - pubSub->listenToTopic("test"); + pubSub.listenToTopic("test"); std::this_thread::sleep_for(150ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); - ASSERT_EQ(pubSub->diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.listenResponses, 1); std::this_thread::sleep_for(2s); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 4); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 4); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 4); - ASSERT_EQ(pubSub->diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 4); + ASSERT_EQ(pubSub.diag.listenResponses, 1); } TEST(TwitchPubSubClient, ServerDoesntRespondToPings) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050/dont-respond-to-ping"); + FTest pubSub("/dont-respond-to-ping", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); - pubSub->listenToTopic("test"); + pubSub.setAccountData("token", "123456"); + pubSub.start(); + pubSub.listenToTopic("test"); std::this_thread::sleep_for(750ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 1); std::this_thread::sleep_for(500ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 2); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 2); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); } TEST(TwitchPubSubClient, DisconnectedAfter1s) { - auto pingInterval = std::chrono::seconds(10); - const QString host("wss://127.0.0.1:9050/disconnect-client-after-1s"); + FTest pubSub("/disconnect-client-after-1s", 10s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 0); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 0); - ASSERT_EQ(pubSub->diag.listenResponses, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 0); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 0); + ASSERT_EQ(pubSub.diag.listenResponses, 0); - pubSub->listenToTopic("test"); + pubSub.listenToTopic("test"); std::this_thread::sleep_for(500ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); // Listen RESPONSE & Pong - ASSERT_EQ(pubSub->diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); // Listen RESPONSE & Pong + ASSERT_EQ(pubSub.diag.listenResponses, 1); std::this_thread::sleep_for(350ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); std::this_thread::sleep_for(600ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.listenResponses, 2); - ASSERT_EQ(pubSub->diag.messagesReceived, 4); // new listen & new pong + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.listenResponses, 2); + ASSERT_EQ(pubSub.diag.messagesReceived, 4); // new listen & new pong - pubSub->stop(); + pubSub.stop(); } TEST(TwitchPubSubClient, ExceedTopicLimit) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050"); + FTest pubSub("", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 0); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 0); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 0); for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i) { - pubSub->listenToTopic(QString("test-1.%1").arg(i)); + pubSub.listenToTopic(QString("test-1.%1").arg(i)); } std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i) { - pubSub->listenToTopic(QString("test-2.%1").arg(i)); + pubSub.listenToTopic(QString("test-2.%1").arg(i)); } std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 2); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 2); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, ExceedTopicLimitSingleStep) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050"); + FTest pubSub("", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 0); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 0); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 0); for (auto i = 0; i < PubSubClient::MAX_LISTENS * 2; ++i) { - pubSub->listenToTopic("test"); + pubSub.listenToTopic("test"); } std::this_thread::sleep_for(150ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 2); - ASSERT_EQ(pubSub->diag.connectionsClosed, 2); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 2); + ASSERT_EQ(pubSub.diag.connectionsClosed, 2); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, ReceivedWhisper) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050/receive-whisper"); + FTest pubSub("/receive-whisper", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); - boost::optional oReceivedWhisper; + ReceivedMessage aReceivedWhisper; - pubSub->signals_.whisper.received.connect( - [&oReceivedWhisper](const auto &whisperMessage) { - oReceivedWhisper = whisperMessage; + pubSub.signals_.whisper.received.connect( + [&aReceivedWhisper](const auto &whisperMessage) { + aReceivedWhisper = whisperMessage; }); - pubSub->listenToTopic("whispers.123456"); + pubSub.listenToTopic("whispers.123456"); std::this_thread::sleep_for(150ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 3); - ASSERT_EQ(pubSub->diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 3); + ASSERT_EQ(pubSub.diag.listenResponses, 1); - ASSERT_TRUE(oReceivedWhisper); + ASSERT_TRUE(aReceivedWhisper); - auto receivedWhisper = *oReceivedWhisper; + ASSERT_EQ(aReceivedWhisper->body, QString("me Kappa")); + ASSERT_EQ(aReceivedWhisper->fromUserLogin, QString("pajbot")); + ASSERT_EQ(aReceivedWhisper->fromUserID, QString("82008718")); - ASSERT_EQ(receivedWhisper.body, QString("me Kappa")); - ASSERT_EQ(receivedWhisper.fromUserLogin, QString("pajbot")); - ASSERT_EQ(receivedWhisper.fromUserID, QString("82008718")); + pubSub.stop(); - pubSub->stop(); - - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, ModeratorActionsUserBanned) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050/moderator-actions-user-banned"); + FTest pubSub("/moderator-actions-user-banned", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("token", "123456"); - pubSub->start(); + pubSub.setAccountData("token", "123456"); + pubSub.start(); - boost::optional oReceivedAction; + ReceivedMessage received; - pubSub->signals_.moderation.userBanned.connect( - [&oReceivedAction](const auto &action) { - oReceivedAction = action; + pubSub.signals_.moderation.userBanned.connect( + [&received](const auto &action) { + received = action; }); - ASSERT_EQ(pubSub->diag.listenResponses, 0); + ASSERT_EQ(pubSub.diag.listenResponses, 0); - pubSub->listenToTopic("chat_moderator_actions.123456.123456"); + pubSub.listenToTopic("chat_moderator_actions.123456.123456"); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 3); - ASSERT_EQ(pubSub->diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 3); + ASSERT_EQ(pubSub.diag.listenResponses, 1); - ASSERT_TRUE(oReceivedAction); - - auto receivedAction = *oReceivedAction; + ASSERT_TRUE(received); ActionUser expectedTarget{"140114344", "1xelerate", "", QColor()}; ActionUser expectedSource{"117691339", "mm2pl", "", QColor()}; - ASSERT_EQ(receivedAction.reason, QString()); - ASSERT_EQ(receivedAction.duration, 0); - ASSERT_EQ(receivedAction.target, expectedTarget); - ASSERT_EQ(receivedAction.source, expectedSource); + ASSERT_EQ(received->reason, QString()); + ASSERT_EQ(received->duration, 0); + ASSERT_EQ(received->target, expectedTarget); + ASSERT_EQ(received->source, expectedSource); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, MissingToken) { - auto pingInterval = std::chrono::seconds(1); // The token that's required is "xD" - const QString host("wss://127.0.0.1:9050/authentication-required"); + FTest pubSub("/authentication-required", 1s); - auto *pubSub = new PubSub(host, pingInterval); - // pubSub->setAccountData("", "123456"); - pubSub->start(); + // pubSub.setAccountData("", "123456"); + pubSub.start(); - pubSub->listenToTopic("chat_moderator_actions.123456.123456"); + pubSub.listenToTopic("chat_moderator_actions.123456.123456"); std::this_thread::sleep_for(150ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); - ASSERT_EQ(pubSub->diag.listenResponses, 0); - ASSERT_EQ(pubSub->diag.failedListenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.listenResponses, 0); + ASSERT_EQ(pubSub.diag.failedListenResponses, 1); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, WrongToken) { - auto pingInterval = std::chrono::seconds(1); // The token that's required is "xD" - const QString host("wss://127.0.0.1:9050/authentication-required"); + FTest pubSub("/authentication-required", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("wrongtoken", "123456"); - pubSub->start(); + pubSub.setAccountData("wrongtoken", "123456"); + pubSub.start(); - pubSub->listenToTopic("chat_moderator_actions.123456.123456"); + pubSub.listenToTopic("chat_moderator_actions.123456.123456"); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); - ASSERT_EQ(pubSub->diag.listenResponses, 0); - ASSERT_EQ(pubSub->diag.failedListenResponses, 1); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.listenResponses, 0); + ASSERT_EQ(pubSub.diag.failedListenResponses, 1); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, CorrectToken) { - auto pingInterval = std::chrono::seconds(1); // The token that's required is "xD" - const QString host("wss://127.0.0.1:9050/authentication-required"); + FTest pubSub("/authentication-required", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("xD", "123456"); - pubSub->start(); + pubSub.setAccountData("xD", "123456"); + pubSub.start(); - pubSub->listenToTopic("chat_moderator_actions.123456.123456"); + pubSub.listenToTopic("chat_moderator_actions.123456.123456"); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 2); - ASSERT_EQ(pubSub->diag.listenResponses, 1); - ASSERT_EQ(pubSub->diag.failedListenResponses, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 2); + ASSERT_EQ(pubSub.diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.failedListenResponses, 0); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } TEST(TwitchPubSubClient, AutoModMessageHeld) { - auto pingInterval = std::chrono::seconds(1); - const QString host("wss://127.0.0.1:9050/automod-held"); + FTest pubSub("/automod-held", 1s); - auto *pubSub = new PubSub(host, pingInterval); - pubSub->setAccountData("xD", "123456"); - pubSub->start(); + pubSub.setAccountData("xD", "123456"); + pubSub.start(); - boost::optional oReceived; - boost::optional oChannelID; + ReceivedMessage received; + ReceivedMessage channelID; - pubSub->signals_.moderation.autoModMessageCaught.connect( - [&](const auto &msg, const QString &channelID) { - oReceived = msg; - oChannelID = channelID; + pubSub.signals_.moderation.autoModMessageCaught.connect( + [&](const auto &msg, const QString &incomingChannelID) { + received = msg; + channelID = incomingChannelID; }); - pubSub->listenToTopic("automod-queue.117166826.117166826"); + pubSub.listenToTopic("automod-queue.117166826.117166826"); std::this_thread::sleep_for(50ms); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 0); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); - ASSERT_EQ(pubSub->diag.messagesReceived, 3); - ASSERT_EQ(pubSub->diag.listenResponses, 1); - ASSERT_EQ(pubSub->diag.failedListenResponses, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 0); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.messagesReceived, 3); + ASSERT_EQ(pubSub.diag.listenResponses, 1); + ASSERT_EQ(pubSub.diag.failedListenResponses, 0); - ASSERT_TRUE(oReceived); - ASSERT_TRUE(oChannelID); - - auto received = *oReceived; - auto channelID = *oChannelID; + ASSERT_TRUE(received); + ASSERT_TRUE(channelID); ASSERT_EQ(channelID, "117166826"); - ASSERT_EQ(received.messageText, "kurwa"); + ASSERT_EQ(received->messageText, "kurwa"); - pubSub->stop(); + pubSub.stop(); - ASSERT_EQ(pubSub->diag.connectionsOpened, 1); - ASSERT_EQ(pubSub->diag.connectionsClosed, 1); - ASSERT_EQ(pubSub->diag.connectionsFailed, 0); + ASSERT_EQ(pubSub.diag.connectionsOpened, 1); + ASSERT_EQ(pubSub.diag.connectionsClosed, 1); + ASSERT_EQ(pubSub.diag.connectionsFailed, 0); } #endif