From 9f23c8562a5759358ce20015c8292ff6d37dfc0e Mon Sep 17 00:00:00 2001 From: pajlada Date: Fri, 13 Oct 2023 17:41:23 +0200 Subject: [PATCH] Test filters context map & message builder (#4886) --- .github/workflows/test.yml | 2 +- mocks/include/mocks/Channel.hpp | 16 +++ mocks/include/mocks/EmptyApplication.hpp | 6 + mocks/include/mocks/TwitchIrcServer.hpp | 46 +++++++ src/Application.hpp | 5 + src/controllers/filters/lang/Filter.cpp | 2 +- src/messages/Image.cpp | 3 +- src/messages/SharedMessageBuilder.cpp | 2 - src/providers/twitch/TwitchIrcServer.cpp | 6 + src/providers/twitch/TwitchIrcServer.hpp | 2 + src/providers/twitch/TwitchMessageBuilder.cpp | 29 +++-- src/singletons/Emotes.hpp | 6 + tests/src/ChannelChatters.cpp | 16 +-- tests/src/Filters.cpp | 115 ++++++++++++++++++ tests/src/InputCompletion.cpp | 45 +------ tests/src/TwitchMessageBuilder.cpp | 111 +++++++++++++++++ tests/src/main.cpp | 3 + 17 files changed, 345 insertions(+), 70 deletions(-) create mode 100644 mocks/include/mocks/Channel.hpp create mode 100644 mocks/include/mocks/TwitchIrcServer.hpp diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e73a8cf8b35..b9e490390b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -99,6 +99,6 @@ jobs: docker pull ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }} docker run --network=host --detach ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }} docker run -p 9051:80 --detach kennethreitz/httpbin - ./bin/chatterino-test || ./bin/chatterino-test || ./bin/chatterino-test + ctest --repeat until-pass:4 working-directory: build-test shell: bash diff --git a/mocks/include/mocks/Channel.hpp b/mocks/include/mocks/Channel.hpp new file mode 100644 index 00000000000..0af536e4660 --- /dev/null +++ b/mocks/include/mocks/Channel.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "common/Channel.hpp" + +namespace chatterino::mock { + +class MockChannel : public Channel +{ +public: + MockChannel(const QString &name) + : Channel(name, Channel::Type::Twitch) + { + } +}; + +} // namespace chatterino::mock diff --git a/mocks/include/mocks/EmptyApplication.hpp b/mocks/include/mocks/EmptyApplication.hpp index b839d04a438..16a43db618e 100644 --- a/mocks/include/mocks/EmptyApplication.hpp +++ b/mocks/include/mocks/EmptyApplication.hpp @@ -74,6 +74,12 @@ class EmptyApplication : public IApplication return nullptr; } + SeventvBadges *getSeventvBadges() override + { + assert(!"getSeventvBadges was called without being initialized"); + return nullptr; + } + IUserDataController *getUserData() override { return nullptr; diff --git a/mocks/include/mocks/TwitchIrcServer.hpp b/mocks/include/mocks/TwitchIrcServer.hpp new file mode 100644 index 00000000000..aca17e4b7c1 --- /dev/null +++ b/mocks/include/mocks/TwitchIrcServer.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "mocks/Channel.hpp" +#include "providers/twitch/TwitchIrcServer.hpp" + +namespace chatterino::mock { + +class MockTwitchIrcServer : public ITwitchIrcServer +{ +public: + MockTwitchIrcServer() + : watchingChannelInner( + std::shared_ptr(new MockChannel("testaccount_420"))) + , watchingChannel(this->watchingChannelInner, + Channel::Type::TwitchWatching) + { + } + + const BttvEmotes &getBttvEmotes() const override + { + return this->bttv; + } + + const FfzEmotes &getFfzEmotes() const override + { + return this->ffz; + } + + const SeventvEmotes &getSeventvEmotes() const override + { + return this->seventv; + } + + const IndirectChannel &getWatchingChannel() const override + { + return this->watchingChannel; + } + + BttvEmotes bttv; + FfzEmotes ffz; + SeventvEmotes seventv; + ChannelPtr watchingChannelInner; + IndirectChannel watchingChannel; +}; + +} // namespace chatterino::mock diff --git a/src/Application.hpp b/src/Application.hpp index d926ab44774..af80308f180 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -63,6 +63,7 @@ class IApplication virtual ITwitchIrcServer *getTwitch() = 0; virtual ChatterinoBadges *getChatterinoBadges() = 0; virtual FfzBadges *getFfzBadges() = 0; + virtual SeventvBadges *getSeventvBadges() = 0; virtual IUserDataController *getUserData() = 0; virtual ITwitchLiveController *getTwitchLiveController() = 0; }; @@ -160,6 +161,10 @@ class Application : public IApplication { return this->ffzBadges; } + SeventvBadges *getSeventvBadges() override + { + return this->seventvBadges; + } IUserDataController *getUserData() override; ITwitchLiveController *getTwitchLiveController() override; diff --git a/src/controllers/filters/lang/Filter.cpp b/src/controllers/filters/lang/Filter.cpp index d418907ef7e..9f31ec1e6e3 100644 --- a/src/controllers/filters/lang/Filter.cpp +++ b/src/controllers/filters/lang/Filter.cpp @@ -12,7 +12,7 @@ namespace chatterino::filters { ContextMap buildContextMap(const MessagePtr &m, chatterino::Channel *channel) { - auto watchingChannel = chatterino::getApp()->twitch->watchingChannel.get(); + auto watchingChannel = getIApp()->getTwitch()->getWatchingChannel().get(); /* * Looking to add a new identifier to filters? Here's what to do: diff --git a/src/messages/Image.cpp b/src/messages/Image.cpp index 89f0bd4cc08..0b8e8f9e57d 100644 --- a/src/messages/Image.cpp +++ b/src/messages/Image.cpp @@ -72,7 +72,8 @@ namespace detail { else { this->durationOffset_ = std::min( - int(getApp()->emotes->gifTimer.position() % totalLength), + int(getIApp()->getEmotes()->getGIFTimer().position() % + totalLength), 60000); } this->processOffset(); diff --git a/src/messages/SharedMessageBuilder.cpp b/src/messages/SharedMessageBuilder.cpp index 9f8f3bec8ba..0231f204595 100644 --- a/src/messages/SharedMessageBuilder.cpp +++ b/src/messages/SharedMessageBuilder.cpp @@ -229,8 +229,6 @@ void SharedMessageBuilder::triggerHighlights() QString SharedMessageBuilder::stylizeUsername(const QString &username, const Message &message) { - auto app = getApp(); - const QString &localizedName = message.localizedName; bool hasLocalizedName = !localizedName.isEmpty(); diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index ccef15ba855..3039f7358eb 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -1,6 +1,7 @@ #include "TwitchIrcServer.hpp" #include "Application.hpp" +#include "common/Channel.hpp" #include "common/Env.hpp" #include "common/QLogging.hpp" #include "controllers/accounts/AccountController.hpp" @@ -520,6 +521,11 @@ const SeventvEmotes &TwitchIrcServer::getSeventvEmotes() const return this->seventv_; } +const IndirectChannel &TwitchIrcServer::getWatchingChannel() const +{ + return this->watchingChannel; +} + void TwitchIrcServer::reloadBTTVGlobalEmotes() { this->bttv.loadEmotes(); diff --git a/src/providers/twitch/TwitchIrcServer.hpp b/src/providers/twitch/TwitchIrcServer.hpp index d60554fa33e..42d2c739ae4 100644 --- a/src/providers/twitch/TwitchIrcServer.hpp +++ b/src/providers/twitch/TwitchIrcServer.hpp @@ -31,6 +31,7 @@ class ITwitchIrcServer virtual const BttvEmotes &getBttvEmotes() const = 0; virtual const FfzEmotes &getFfzEmotes() const = 0; virtual const SeventvEmotes &getSeventvEmotes() const = 0; + virtual const IndirectChannel &getWatchingChannel() const = 0; // Update this interface with TwitchIrcServer methods as needed }; @@ -85,6 +86,7 @@ class TwitchIrcServer final : public AbstractIrcServer, const BttvEmotes &getBttvEmotes() const override; const FfzEmotes &getFfzEmotes() const override; const SeventvEmotes &getSeventvEmotes() const override; + const IndirectChannel &getWatchingChannel() const override; protected: virtual void initializeConnection(IrcConnection *connection, diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 70e35112b22..7322f3caa2c 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -205,6 +205,9 @@ void TwitchMessageBuilder::triggerHighlights() MessagePtr TwitchMessageBuilder::build() { + assert(this->ircMessage != nullptr); + assert(this->channel != nullptr); + // PARSE this->userId_ = this->ircMessage->tag("user-id").toString(); @@ -433,7 +436,8 @@ void TwitchMessageBuilder::addWords( // 1. Add text before the emote QString preText = word.left(currentTwitchEmote.start - cursor); - for (auto &variant : getApp()->emotes->emojis.parse(preText)) + for (auto &variant : + getIApp()->getEmotes()->getEmojis()->parse(preText)) { boost::apply_visitor( [&](auto &&arg) { @@ -453,7 +457,7 @@ void TwitchMessageBuilder::addWords( } // split words - for (auto &variant : getApp()->emotes->emojis.parse(word)) + for (auto &variant : getIApp()->getEmotes()->getEmojis()->parse(word)) { boost::apply_visitor( [&](auto &&arg) { @@ -748,7 +752,7 @@ void TwitchMessageBuilder::parseUsername() } // Update current user color if this is our message - auto currentUser = getApp()->accounts->twitch.getCurrent(); + auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (this->ircMessage->nick() == currentUser->getUserName()) { currentUser->setColor(this->usernameColor_); @@ -757,7 +761,7 @@ void TwitchMessageBuilder::parseUsername() void TwitchMessageBuilder::appendUsername() { - auto app = getApp(); + auto *app = getIApp(); QString username = this->userName; this->message().loginName = username; @@ -802,7 +806,7 @@ void TwitchMessageBuilder::appendUsername() FontStyle::ChatMediumBold) ->setLink({Link::UserWhisper, this->message().displayName}); - auto currentUser = app->accounts->twitch.getCurrent(); + auto currentUser = app->getAccounts()->twitch.getCurrent(); // Separator this->emplace("->", MessageElementFlag::Username, @@ -1062,11 +1066,11 @@ void TwitchMessageBuilder::runIgnoreReplaces( Outcome TwitchMessageBuilder::tryAppendEmote(const EmoteName &name) { - auto *app = getApp(); + auto *app = getIApp(); - const auto &globalBttvEmotes = app->twitch->getBttvEmotes(); - const auto &globalFfzEmotes = app->twitch->getFfzEmotes(); - const auto &globalSeventvEmotes = app->twitch->getSeventvEmotes(); + const auto &globalBttvEmotes = app->getTwitch()->getBttvEmotes(); + const auto &globalFfzEmotes = app->getTwitch()->getFfzEmotes(); + const auto &globalSeventvEmotes = app->getTwitch()->getSeventvEmotes(); auto flags = MessageElementFlags(); auto emote = std::optional{}; @@ -1312,7 +1316,8 @@ void TwitchMessageBuilder::appendTwitchBadges() void TwitchMessageBuilder::appendChatterinoBadges() { - if (auto badge = getApp()->chatterinoBadges->getBadge({this->userId_})) + if (auto badge = + getIApp()->getChatterinoBadges()->getBadge({this->userId_})) { this->emplace(*badge, MessageElementFlag::BadgeChatterino); @@ -1322,7 +1327,7 @@ void TwitchMessageBuilder::appendChatterinoBadges() void TwitchMessageBuilder::appendFfzBadges() { for (const auto &badge : - getApp()->ffzBadges->getUserBadges({this->userId_})) + getIApp()->getFfzBadges()->getUserBadges({this->userId_})) { this->emplace( badge.emote, MessageElementFlag::BadgeFfz, badge.color); @@ -1331,7 +1336,7 @@ void TwitchMessageBuilder::appendFfzBadges() void TwitchMessageBuilder::appendSeventvBadges() { - if (auto badge = getApp()->seventvBadges->getBadge({this->userId_})) + if (auto badge = getIApp()->getSeventvBadges()->getBadge({this->userId_})) { this->emplace(*badge, MessageElementFlag::BadgeSevenTV); } diff --git a/src/singletons/Emotes.hpp b/src/singletons/Emotes.hpp index f74dab87335..70c0261ff5f 100644 --- a/src/singletons/Emotes.hpp +++ b/src/singletons/Emotes.hpp @@ -17,6 +17,7 @@ class IEmotes virtual ITwitchEmotes *getTwitchEmotes() = 0; virtual IEmojis *getEmojis() = 0; + virtual GIFTimer &getGIFTimer() = 0; }; class Emotes final : public IEmotes, public Singleton @@ -38,6 +39,11 @@ class Emotes final : public IEmotes, public Singleton return &this->emojis; } + GIFTimer &getGIFTimer() final + { + return this->gifTimer; + } + TwitchEmotes twitch; Emojis emojis; diff --git a/tests/src/ChannelChatters.cpp b/tests/src/ChannelChatters.cpp index 328c50e6c71..c665836bb38 100644 --- a/tests/src/ChannelChatters.cpp +++ b/tests/src/ChannelChatters.cpp @@ -1,25 +1,13 @@ #include "common/ChannelChatters.hpp" -#include "common/Channel.hpp" +#include "mocks/Channel.hpp" #include #include #include -namespace chatterino { - -class MockChannel : public Channel -{ -public: - MockChannel(const QString &name) - : Channel(name, Channel::Type::Twitch) - { - } -}; - -} // namespace chatterino - using namespace chatterino; +using chatterino::mock::MockChannel; // Ensure inserting the same user does not increase the size of the stored colors TEST(ChatterChatters, insertSameUser) diff --git a/tests/src/Filters.cpp b/tests/src/Filters.cpp index 97763dc1dce..87f95c7860a 100644 --- a/tests/src/Filters.cpp +++ b/tests/src/Filters.cpp @@ -1,5 +1,17 @@ +#include "controllers/accounts/AccountController.hpp" #include "controllers/filters/lang/Filter.hpp" #include "controllers/filters/lang/Types.hpp" +#include "controllers/highlights/HighlightController.hpp" +#include "mocks/Channel.hpp" +#include "mocks/EmptyApplication.hpp" +#include "mocks/TwitchIrcServer.hpp" +#include "mocks/UserData.hpp" +#include "providers/chatterino/ChatterinoBadges.hpp" +#include "providers/ffz/FfzBadges.hpp" +#include "providers/seventv/SeventvBadges.hpp" +#include "providers/twitch/TwitchBadge.hpp" +#include "providers/twitch/TwitchMessageBuilder.hpp" +#include "singletons/Emotes.hpp" #include #include @@ -7,9 +19,83 @@ using namespace chatterino; using namespace chatterino::filters; +using chatterino::mock::MockChannel; TypingContext typingContext = MESSAGE_TYPING_CONTEXT; +namespace { + +class MockApplication : mock::EmptyApplication +{ +public: + IEmotes *getEmotes() override + { + return &this->emotes; + } + + IUserDataController *getUserData() override + { + return &this->userData; + } + + AccountController *getAccounts() override + { + return &this->accounts; + } + + ITwitchIrcServer *getTwitch() override + { + return &this->twitch; + } + + ChatterinoBadges *getChatterinoBadges() override + { + return &this->chatterinoBadges; + } + + FfzBadges *getFfzBadges() override + { + return &this->ffzBadges; + } + + SeventvBadges *getSeventvBadges() override + { + return &this->seventvBadges; + } + + HighlightController *getHighlights() override + { + return &this->highlights; + } + + AccountController accounts; + Emotes emotes; + mock::UserDataController userData; + mock::MockTwitchIrcServer twitch; + ChatterinoBadges chatterinoBadges; + FfzBadges ffzBadges; + SeventvBadges seventvBadges; + HighlightController highlights; +}; + +class FiltersF : public ::testing::Test +{ +protected: + void SetUp() override + { + this->mockApplication = std::make_unique(); + } + + void TearDown() override + { + this->mockApplication.reset(); + } + + std::unique_ptr mockApplication; +}; + +} // namespace + namespace chatterino::filters { std::ostream &operator<<(std::ostream &os, Type t) @@ -170,3 +256,32 @@ TEST(Filters, Evaluation) << qUtf8Printable(filter.debugString(typingContext)); } } + +TEST_F(FiltersF, TypingContextChecks) +{ + MockChannel channel("pajlada"); + + QByteArray message = + R"(@badge-info=subscriber/80;badges=broadcaster/1,subscriber/3072,partner/1;color=#CC44FF;display-name=pajlada;emote-only=1;emotes=25:0-4;first-msg=0;flags=;id=90ef1e46-8baa-4bf2-9c54-272f39d6fa11;mod=0;returning-chatter=0;room-id=11148817;subscriber=1;tmi-sent-ts=1662206235860;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada :ACTION Kappa)"; + + struct TestCase { + QByteArray input; + }; + + auto *privmsg = dynamic_cast( + Communi::IrcPrivateMessage::fromData(message, nullptr)); + EXPECT_NE(privmsg, nullptr); + + QString originalMessage = privmsg->content(); + + TwitchMessageBuilder builder(&channel, privmsg, MessageParseArgs{}); + + auto msg = builder.build(); + EXPECT_NE(msg.get(), nullptr); + + auto contextMap = buildContextMap(msg, &channel); + + EXPECT_EQ(contextMap.size(), MESSAGE_TYPING_CONTEXT.size()); + + delete privmsg; +} diff --git a/tests/src/InputCompletion.cpp b/tests/src/InputCompletion.cpp index b31aef64582..623d3a79934 100644 --- a/tests/src/InputCompletion.cpp +++ b/tests/src/InputCompletion.cpp @@ -5,9 +5,10 @@ #include "controllers/completion/strategies/ClassicUserStrategy.hpp" #include "controllers/completion/strategies/Strategy.hpp" #include "messages/Emote.hpp" +#include "mocks/Channel.hpp" #include "mocks/EmptyApplication.hpp" #include "mocks/Helix.hpp" -#include "providers/twitch/TwitchIrcServer.hpp" +#include "mocks/TwitchIrcServer.hpp" #include "singletons/Emotes.hpp" #include "singletons/Paths.hpp" #include "singletons/Settings.hpp" @@ -22,35 +23,14 @@ #include +using namespace chatterino; +using chatterino::mock::MockChannel; + namespace { -using namespace chatterino; using namespace chatterino::completion; using ::testing::Exactly; -class MockTwitchIrcServer : public ITwitchIrcServer -{ -public: - const BttvEmotes &getBttvEmotes() const override - { - return this->bttv; - } - - const FfzEmotes &getFfzEmotes() const override - { - return this->ffz; - } - - const SeventvEmotes &getSeventvEmotes() const override - { - return this->seventv; - } - - BttvEmotes bttv; - FfzEmotes ffz; - SeventvEmotes seventv; -}; - class MockApplication : mock::EmptyApplication { public: @@ -70,25 +50,12 @@ class MockApplication : mock::EmptyApplication } AccountController accounts; - MockTwitchIrcServer twitch; + mock::MockTwitchIrcServer twitch; Emotes emotes; }; } // namespace -namespace chatterino { - -class MockChannel : public Channel -{ -public: - MockChannel(const QString &name) - : Channel(name, Channel::Type::Twitch) - { - } -}; - -} // namespace chatterino - EmotePtr namedEmote(const EmoteName &name) { return std::shared_ptr(new Emote{ diff --git a/tests/src/TwitchMessageBuilder.cpp b/tests/src/TwitchMessageBuilder.cpp index f07b35af29c..b11e480e871 100644 --- a/tests/src/TwitchMessageBuilder.cpp +++ b/tests/src/TwitchMessageBuilder.cpp @@ -1,9 +1,16 @@ #include "providers/twitch/TwitchMessageBuilder.hpp" #include "common/Channel.hpp" +#include "controllers/accounts/AccountController.hpp" +#include "controllers/highlights/HighlightController.hpp" #include "messages/MessageBuilder.hpp" +#include "mocks/Channel.hpp" #include "mocks/EmptyApplication.hpp" +#include "mocks/TwitchIrcServer.hpp" #include "mocks/UserData.hpp" +#include "providers/chatterino/ChatterinoBadges.hpp" +#include "providers/ffz/FfzBadges.hpp" +#include "providers/seventv/SeventvBadges.hpp" #include "providers/twitch/TwitchBadge.hpp" #include "singletons/Emotes.hpp" @@ -16,6 +23,7 @@ #include using namespace chatterino; +using chatterino::mock::MockChannel; namespace { @@ -32,8 +40,44 @@ class MockApplication : mock::EmptyApplication return &this->userData; } + AccountController *getAccounts() override + { + return &this->accounts; + } + + ITwitchIrcServer *getTwitch() override + { + return &this->twitch; + } + + ChatterinoBadges *getChatterinoBadges() override + { + return &this->chatterinoBadges; + } + + FfzBadges *getFfzBadges() override + { + return &this->ffzBadges; + } + + SeventvBadges *getSeventvBadges() override + { + return &this->seventvBadges; + } + + HighlightController *getHighlights() override + { + return &this->highlights; + } + + AccountController accounts; Emotes emotes; mock::UserDataController userData; + mock::MockTwitchIrcServer twitch; + ChatterinoBadges chatterinoBadges; + FfzBadges ffzBadges; + SeventvBadges seventvBadges; + HighlightController highlights; }; } // namespace @@ -349,3 +393,70 @@ TEST_F(TestTwitchMessageBuilder, ParseTwitchEmotes) delete privmsg; } } + +TEST_F(TestTwitchMessageBuilder, ParseMessage) +{ + MockChannel channel("pajlada"); + + struct TestCase { + QByteArray input; + }; + + std::vector testCases{ + { + // action /me message + R"(@badge-info=subscriber/80;badges=broadcaster/1,subscriber/3072,partner/1;color=#CC44FF;display-name=pajlada;emote-only=1;emotes=25:0-4;first-msg=0;flags=;id=90ef1e46-8baa-4bf2-9c54-272f39d6fa11;mod=0;returning-chatter=0;room-id=11148817;subscriber=1;tmi-sent-ts=1662206235860;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada :ACTION Kappa)", + }, + { + R"(@badge-info=subscriber/17;badges=subscriber/12,no_audio/1;color=#EBA2C0;display-name=jammehcow;emote-only=1;emotes=25:0-4;first-msg=0;flags=;id=9c2dd916-5a6d-4c1f-9fe7-a081b62a9c6b;mod=0;returning-chatter=0;room-id=11148817;subscriber=1;tmi-sent-ts=1662201093248;turbo=0;user-id=82674227;user-type= :jammehcow!jammehcow@jammehcow.tmi.twitch.tv PRIVMSG #pajlada :Kappa)", + }, + { + R"(@badge-info=;badges=no_audio/1;color=#DAA520;display-name=Mm2PL;emote-only=1;emotes=1902:0-4;first-msg=0;flags=;id=9b1c3cb9-7817-47ea-add1-f9d4a9b4f846;mod=0;returning-chatter=0;room-id=11148817;subscriber=0;tmi-sent-ts=1662201095690;turbo=0;user-id=117691339;user-type= :mm2pl!mm2pl@mm2pl.tmi.twitch.tv PRIVMSG #pajlada :Keepo)", + }, + { + R"(@badge-info=;badges=no_audio/1;color=#DAA520;display-name=Mm2PL;emote-only=1;emotes=25:0-4/1902:6-10/305954156:12-19;first-msg=0;flags=;id=7be87072-bf24-4fa3-b3df-0ea6fa5f1474;mod=0;returning-chatter=0;room-id=11148817;subscriber=0;tmi-sent-ts=1662201102276;turbo=0;user-id=117691339;user-type= :mm2pl!mm2pl@mm2pl.tmi.twitch.tv PRIVMSG #pajlada :Kappa Keepo PogChamp)", + }, + { + R"(@badge-info=subscriber/80;badges=broadcaster/1,subscriber/3072,partner/1;color=#CC44FF;display-name=pajlada;emote-only=1;emotes=25:0-4,6-10;first-msg=0;flags=;id=f7516287-e5d1-43ca-974e-fe0cff84400b;mod=0;returning-chatter=0;room-id=11148817;subscriber=1;tmi-sent-ts=1662204375009;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada :Kappa Kappa)", + }, + { + R"(@badge-info=subscriber/80;badges=broadcaster/1,subscriber/3072,partner/1;color=#CC44FF;display-name=pajlada;emotes=25:0-4,8-12;first-msg=0;flags=;id=44f85d39-b5fb-475d-8555-f4244f2f7e82;mod=0;returning-chatter=0;room-id=11148817;subscriber=1;tmi-sent-ts=1662204423418;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada :Kappa 😂 Kappa)", + }, + { + // start out of range + R"(@emotes=84608:9-10 :test!test@test.tmi.twitch.tv PRIVMSG #pajlada :foo bar)", + }, + { + // one character emote + R"(@emotes=84608:0-0 :test!test@test.tmi.twitch.tv PRIVMSG #pajlada :foo bar)", + }, + { + // two character emote + R"(@emotes=84609:0-1 :test!test@test.tmi.twitch.tv PRIVMSG #pajlada :foo bar)", + }, + { + // end out of range + R"(@emotes=84608:0-15 :test!test@test.tmi.twitch.tv PRIVMSG #pajlada :foo bar)", + }, + { + // range bad (end character before start) + R"(@emotes=84608:15-2 :test!test@test.tmi.twitch.tv PRIVMSG #pajlada :foo bar)", + }, + }; + + for (const auto &test : testCases) + { + auto *privmsg = dynamic_cast( + Communi::IrcPrivateMessage::fromData(test.input, nullptr)); + EXPECT_NE(privmsg, nullptr); + + QString originalMessage = privmsg->content(); + + TwitchMessageBuilder builder(&channel, privmsg, MessageParseArgs{}); + + auto msg = builder.build(); + EXPECT_NE(msg.get(), nullptr); + + delete privmsg; + } +} diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 91f4b8b8862..8a8fbc26d5d 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -1,4 +1,5 @@ #include "common/NetworkManager.hpp" +#include "singletons/Resources.hpp" #include "singletons/Settings.hpp" #include @@ -24,6 +25,8 @@ int main(int argc, char **argv) // make sure to always debug-log QLoggingCategory::setFilterRules("*.debug=true"); + initResources(); + chatterino::NetworkManager::init(); // Ensure settings are initialized before any tests are run