dev: Add RecentMessages benchmark (#5071)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix 2024-01-07 13:15:36 +01:00 committed by GitHub
parent 78a7ebb9f9
commit f42ae07408
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 446 additions and 119 deletions

View file

@ -65,5 +65,11 @@ CheckOptions:
- key: readability-identifier-naming.LocalPointerIgnoredRegexp - key: readability-identifier-naming.LocalPointerIgnoredRegexp
value: ^L$ value: ^L$
# Benchmarks
- key: readability-identifier-naming.FunctionIgnoredRegexp
value: ^BM_[^_]+$
- key: readability-identifier-naming.ClassIgnoredRegexp
value: ^BM_[^_]+$
- key: misc-const-correctness.AnalyzeValues - key: misc-const-correctness.AnalyzeValues
value: false value: false

View file

@ -1,5 +1,7 @@
# JSON resources should not be prettified... # JSON resources should not be prettified...
resources/*.json resources/*.json
benchmarks/resources/*.json
tests/resources/*.json
# ...themes should be prettified for readability. # ...themes should be prettified for readability.
!resources/themes/*.json !resources/themes/*.json
@ -7,6 +9,7 @@ resources/*.json
lib/*/ lib/*/
conan-pkgs/*/ conan-pkgs/*/
cmake/sanitizers-cmake/ cmake/sanitizers-cmake/
tools/crash-handler
# Build folders # Build folders
*build-*/ *build-*/

View file

@ -112,6 +112,7 @@
- Dev: Autogenerate docs/plugin-meta.lua. (#5055) - Dev: Autogenerate docs/plugin-meta.lua. (#5055)
- Dev: Removed duplicate scale in settings dialog. (#5069) - Dev: Removed duplicate scale in settings dialog. (#5069)
- Dev: Fix `NotebookTab` emitting updates for every message. (#5068) - Dev: Fix `NotebookTab` emitting updates for every message. (#5068)
- Dev: Added benchmark for parsing and building recent messages. (#5071)
## 2.4.6 ## 2.4.6

View file

@ -1,13 +1,16 @@
project(chatterino-benchmark) project(chatterino-benchmark)
set(benchmark_SOURCES set(benchmark_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/main.cpp src/main.cpp
${CMAKE_CURRENT_LIST_DIR}/src/Emojis.cpp resources/bench.qrc
${CMAKE_CURRENT_LIST_DIR}/src/Highlights.cpp
${CMAKE_CURRENT_LIST_DIR}/src/FormatTime.cpp src/Emojis.cpp
${CMAKE_CURRENT_LIST_DIR}/src/Helpers.cpp src/Highlights.cpp
${CMAKE_CURRENT_LIST_DIR}/src/LimitedQueue.cpp src/FormatTime.cpp
${CMAKE_CURRENT_LIST_DIR}/src/LinkParser.cpp src/Helpers.cpp
src/LimitedQueue.cpp
src/LinkParser.cpp
src/RecentMessages.cpp
# Add your new file above this line! # Add your new file above this line!
) )
@ -27,4 +30,5 @@ set_target_properties(${PROJECT_NAME}
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin"
AUTORCC ON
) )

View file

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/bench">
<file>recentmessages-nymn.json</file>
<file>seventvemotes-nymn.json</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -145,16 +145,13 @@ static void BM_EmojiParsing(benchmark::State &state)
BENCHMARK(BM_EmojiParsing); BENCHMARK(BM_EmojiParsing);
template <class... Args> static void BM_EmojiParsing2(benchmark::State &state, const QString &input,
static void BM_EmojiParsing2(benchmark::State &state, Args &&...args) int expectedNumEmojis)
{ {
Emojis emojis; Emojis emojis;
emojis.load(); emojis.load();
auto argsTuple = std::make_tuple(std::move(args)...);
auto input = std::get<0>(argsTuple);
auto expectedNumEmojis = std::get<1>(argsTuple);
for (auto _ : state) for (auto _ : state)
{ {
auto output = emojis.parse(input); auto output = emojis.parse(input);

View file

@ -4,35 +4,41 @@
using namespace chatterino; using namespace chatterino;
template <class... Args> void BM_TimeFormattingQString(benchmark::State &state, const QString &v)
void BM_TimeFormatting(benchmark::State &state, Args &&...args)
{ {
auto args_tuple = std::make_tuple(std::move(args)...);
for (auto _ : state) for (auto _ : state)
{ {
formatTime(std::get<0>(args_tuple)); formatTime(v);
} }
} }
BENCHMARK_CAPTURE(BM_TimeFormatting, 0, 0); void BM_TimeFormattingInt(benchmark::State &state, int v)
BENCHMARK_CAPTURE(BM_TimeFormatting, qs0, "0"); {
BENCHMARK_CAPTURE(BM_TimeFormatting, 1337, 1337); for (auto _ : state)
BENCHMARK_CAPTURE(BM_TimeFormatting, qs1337, "1337"); {
BENCHMARK_CAPTURE(BM_TimeFormatting, 623452, 623452); formatTime(v);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs623452, "623452"); }
BENCHMARK_CAPTURE(BM_TimeFormatting, 8345, 8345); }
BENCHMARK_CAPTURE(BM_TimeFormatting, qs8345, "8345");
BENCHMARK_CAPTURE(BM_TimeFormatting, 314034, 314034); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 0, 0);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs314034, "314034"); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 1045345, 1045345);
BENCHMARK_CAPTURE(BM_TimeFormatting, 27, 27); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 1337, 1337);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs27, "27"); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 27, 27);
BENCHMARK_CAPTURE(BM_TimeFormatting, 34589, 34589); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 314034, 314034);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs34589, "34589"); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 34589, 34589);
BENCHMARK_CAPTURE(BM_TimeFormatting, 3659, 3659); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 3659, 3659);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs3659, "3659"); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 623452, 623452);
BENCHMARK_CAPTURE(BM_TimeFormatting, 1045345, 1045345); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 8345, 8345);
BENCHMARK_CAPTURE(BM_TimeFormatting, qs1045345, "1045345"); BENCHMARK_CAPTURE(BM_TimeFormattingInt, 86432, 86432);
BENCHMARK_CAPTURE(BM_TimeFormatting, 86432, 86432); BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs0, "0");
BENCHMARK_CAPTURE(BM_TimeFormatting, qs86432, "86432"); BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs1045345, "1045345");
BENCHMARK_CAPTURE(BM_TimeFormatting, qsempty, ""); BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs1337, "1337");
BENCHMARK_CAPTURE(BM_TimeFormatting, qsinvalid, "asd"); BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs27, "27");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs314034, "314034");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs34589, "34589");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs3659, "3659");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs623452, "623452");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs8345, "8345");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qs86432, "86432");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qsempty, "");
BENCHMARK_CAPTURE(BM_TimeFormattingQString, qsinvalid, "asd");

View file

@ -0,0 +1,223 @@
#include "common/Literals.hpp"
#include "controllers/accounts/AccountController.hpp"
#include "controllers/highlights/HighlightController.hpp"
#include "messages/Emote.hpp"
#include "mocks/EmptyApplication.hpp"
#include "mocks/TwitchIrcServer.hpp"
#include "mocks/UserData.hpp"
#include "providers/bttv/BttvEmotes.hpp"
#include "providers/chatterino/ChatterinoBadges.hpp"
#include "providers/ffz/FfzBadges.hpp"
#include "providers/ffz/FfzEmotes.hpp"
#include "providers/recentmessages/Impl.hpp"
#include "providers/seventv/SeventvBadges.hpp"
#include "providers/seventv/SeventvEmotes.hpp"
#include "providers/twitch/TwitchChannel.hpp"
#include "singletons/Emotes.hpp"
#include "singletons/Resources.hpp"
#include <benchmark/benchmark.h>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QString>
#include <optional>
using namespace chatterino;
using namespace literals;
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;
};
std::optional<QJsonDocument> tryReadJsonFile(const QString &path)
{
QFile file(path);
if (!file.open(QFile::ReadOnly))
{
return std::nullopt;
}
QJsonParseError e;
auto doc = QJsonDocument::fromJson(file.readAll(), &e);
if (e.error != QJsonParseError::NoError)
{
return std::nullopt;
}
return doc;
}
QJsonDocument readJsonFile(const QString &path)
{
auto opt = tryReadJsonFile(path);
if (!opt)
{
_exit(1);
}
return *opt;
}
class RecentMessages
{
public:
explicit RecentMessages(const QString &name_)
: name(name_)
, chan(this->name)
{
const auto seventvEmotes =
tryReadJsonFile(u":/bench/seventvemotes-%1.json"_s.arg(this->name));
const auto bttvEmotes =
tryReadJsonFile(u":/bench/bttvemotes-%1.json"_s.arg(this->name));
const auto ffzEmotes =
tryReadJsonFile(u":/bench/ffzemotes-%1.json"_s.arg(this->name));
if (seventvEmotes)
{
this->chan.setSeventvEmotes(
std::make_shared<const EmoteMap>(seventv::detail::parseEmotes(
seventvEmotes->object()["emote_set"_L1]
.toObject()["emotes"_L1]
.toArray(),
false)));
}
if (bttvEmotes)
{
this->chan.setBttvEmotes(std::make_shared<const EmoteMap>(
bttv::detail::parseChannelEmotes(bttvEmotes->object(),
this->name)));
}
if (ffzEmotes)
{
this->chan.setFfzEmotes(std::make_shared<const EmoteMap>(
ffz::detail::parseChannelEmotes(ffzEmotes->object())));
}
this->messages =
readJsonFile(u":/bench/recentmessages-%1.json"_s.arg(this->name));
}
~RecentMessages()
{
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
virtual void run(benchmark::State &state) = 0;
protected:
QString name;
MockApplication app;
TwitchChannel chan;
QJsonDocument messages;
};
class ParseRecentMessages : public RecentMessages
{
public:
explicit ParseRecentMessages(const QString &name_)
: RecentMessages(name_)
{
}
void run(benchmark::State &state)
{
for (auto _ : state)
{
auto parsed = recentmessages::detail::parseRecentMessages(
this->messages.object());
benchmark::DoNotOptimize(parsed);
}
}
};
class BuildRecentMessages : public RecentMessages
{
public:
explicit BuildRecentMessages(const QString &name_)
: RecentMessages(name_)
{
}
void run(benchmark::State &state)
{
auto parsed = recentmessages::detail::parseRecentMessages(
this->messages.object());
for (auto _ : state)
{
auto built = recentmessages::detail::buildRecentMessages(
parsed, &this->chan);
benchmark::DoNotOptimize(built);
}
}
};
void BM_ParseRecentMessages(benchmark::State &state, const QString &name)
{
ParseRecentMessages bench(name);
bench.run(state);
}
void BM_BuildRecentMessages(benchmark::State &state, const QString &name)
{
BuildRecentMessages bench(name);
bench.run(state);
}
} // namespace
BENCHMARK_CAPTURE(BM_ParseRecentMessages, nymn, u"nymn"_s);
BENCHMARK_CAPTURE(BM_BuildRecentMessages, nymn, u"nymn"_s);

View file

@ -1,3 +1,4 @@
#include "singletons/Resources.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
@ -11,6 +12,8 @@ int main(int argc, char **argv)
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
initResources();
::benchmark::Initialize(&argc, argv); ::benchmark::Initialize(&argc, argv);
// Ensure settings are initialized before any benchmarks are run // Ensure settings are initialized before any benchmarks are run

View file

@ -32,9 +32,11 @@ bool isIgnoredMessage(IgnoredMessageParameters &&params)
{ {
auto sourceUserID = params.twitchUserID; auto sourceUserID = params.twitchUserID;
bool isBlocked = bool isBlocked = getIApp()
getApp()->accounts->twitch.getCurrent()->blockedUserIds().contains( ->getAccounts()
sourceUserID); ->twitch.getCurrent()
->blockedUserIds()
.contains(sourceUserID);
if (isBlocked) if (isBlocked)
{ {
switch (static_cast<ShowIgnoredUsersMessages>( switch (static_cast<ShowIgnoredUsersMessages>(

View file

@ -142,31 +142,33 @@ namespace {
return anyModifications; return anyModifications;
} }
std::pair<Outcome, EmoteMap> parseChannelEmotes(
const QJsonObject &jsonRoot, const QString &channelDisplayName)
{
auto emotes = EmoteMap();
auto innerParse = [&jsonRoot, &emotes,
&channelDisplayName](const char *key) {
auto jsonEmotes = jsonRoot.value(key).toArray();
for (auto jsonEmote_ : jsonEmotes)
{
auto emote = createChannelEmote(channelDisplayName,
jsonEmote_.toObject());
emotes[emote.name] =
cachedOrMake(std::move(emote.emote), emote.id);
}
};
innerParse("channelEmotes");
innerParse("sharedEmotes");
return {Success, std::move(emotes)};
}
} // namespace } // namespace
using namespace bttv::detail;
EmoteMap bttv::detail::parseChannelEmotes(const QJsonObject &jsonRoot,
const QString &channelDisplayName)
{
auto emotes = EmoteMap();
auto innerParse = [&jsonRoot, &emotes,
&channelDisplayName](const char *key) {
auto jsonEmotes = jsonRoot.value(key).toArray();
for (auto jsonEmote_ : jsonEmotes)
{
auto emote =
createChannelEmote(channelDisplayName, jsonEmote_.toObject());
emotes[emote.name] = cachedOrMake(std::move(emote.emote), emote.id);
}
};
innerParse("channelEmotes");
innerParse("sharedEmotes");
return emotes;
}
// //
// BttvEmotes // BttvEmotes
// //
@ -230,14 +232,11 @@ void BttvEmotes::loadChannel(std::weak_ptr<Channel> channel,
.timeout(20000) .timeout(20000)
.onSuccess([callback = std::move(callback), channel, channelDisplayName, .onSuccess([callback = std::move(callback), channel, channelDisplayName,
manualRefresh](auto result) { manualRefresh](auto result) {
auto pair = auto emotes =
parseChannelEmotes(result.parseJson(), channelDisplayName); parseChannelEmotes(result.parseJson(), channelDisplayName);
bool hasEmotes = false; bool hasEmotes = !emotes.empty();
if (pair.first) callback(std::move(emotes));
{
hasEmotes = !pair.second.empty();
callback(std::move(pair.second));
}
if (auto shared = channel.lock(); manualRefresh) if (auto shared = channel.lock(); manualRefresh)
{ {
if (hasEmotes) if (hasEmotes)

View file

@ -3,6 +3,8 @@
#include "common/Aliases.hpp" #include "common/Aliases.hpp"
#include "common/Atomic.hpp" #include "common/Atomic.hpp"
#include <QJsonObject>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -15,6 +17,13 @@ class Channel;
struct BttvLiveUpdateEmoteUpdateAddMessage; struct BttvLiveUpdateEmoteUpdateAddMessage;
struct BttvLiveUpdateEmoteRemoveMessage; struct BttvLiveUpdateEmoteRemoveMessage;
namespace bttv::detail {
EmoteMap parseChannelEmotes(const QJsonObject &jsonRoot,
const QString &channelDisplayName);
} // namespace bttv::detail
class BttvEmotes final class BttvEmotes final
{ {
static constexpr const char *globalEmoteApiUrl = static constexpr const char *globalEmoteApiUrl =

View file

@ -149,19 +149,22 @@ namespace {
return authorityBadge; return authorityBadge;
} }
EmoteMap parseChannelEmotes(const QJsonObject &jsonRoot)
{
auto emotes = EmoteMap();
for (const auto emoteSetRef : jsonRoot["sets"].toObject())
{
parseEmoteSetInto(emoteSetRef.toObject(), "Channel", emotes);
}
return emotes;
}
} // namespace } // namespace
using namespace ffz::detail;
EmoteMap ffz::detail::parseChannelEmotes(const QJsonObject &jsonRoot)
{
auto emotes = EmoteMap();
for (const auto emoteSetRef : jsonRoot["sets"].toObject())
{
parseEmoteSetInto(emoteSetRef.toObject(), "Channel", emotes);
}
return emotes;
}
FfzEmotes::FfzEmotes() FfzEmotes::FfzEmotes()
: global_(std::make_shared<EmoteMap>()) : global_(std::make_shared<EmoteMap>())
{ {

View file

@ -3,6 +3,8 @@
#include "common/Aliases.hpp" #include "common/Aliases.hpp"
#include "common/Atomic.hpp" #include "common/Atomic.hpp"
#include <QJsonObject>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -13,6 +15,12 @@ using EmotePtr = std::shared_ptr<const Emote>;
class EmoteMap; class EmoteMap;
class Channel; class Channel;
namespace ffz::detail {
EmoteMap parseChannelEmotes(const QJsonObject &jsonRoot);
} // namespace ffz::detail
class FfzEmotes final class FfzEmotes final
{ {
public: public:

View file

@ -128,7 +128,34 @@ bool checkEmoteVisibility(const QJsonObject &emoteData)
return !flags.has(SeventvEmoteFlag::ContentTwitchDisallowed); return !flags.has(SeventvEmoteFlag::ContentTwitchDisallowed);
} }
EmoteMap parseEmotes(const QJsonArray &emoteSetEmotes, bool isGlobal) EmotePtr createUpdatedEmote(const EmotePtr &oldEmote,
const EmoteUpdateDispatch &dispatch)
{
bool toNonAliased = oldEmote->baseName.has_value() &&
dispatch.emoteName == oldEmote->baseName->string;
auto baseName = oldEmote->baseName.value_or(oldEmote->name);
auto emote = std::make_shared<const Emote>(Emote(
{EmoteName{dispatch.emoteName}, oldEmote->images,
toNonAliased
? createTooltip(dispatch.emoteName, oldEmote->author.string, false)
: createAliasedTooltip(dispatch.emoteName, baseName.string,
oldEmote->author.string, false),
oldEmote->homePage, oldEmote->zeroWidth, oldEmote->id,
oldEmote->author, makeConditionedOptional(!toNonAliased, baseName)}));
return emote;
}
} // namespace
namespace chatterino {
using namespace seventv::eventapi;
using namespace seventv::detail;
using namespace literals;
EmoteMap seventv::detail::parseEmotes(const QJsonArray &emoteSetEmotes,
bool isGlobal)
{ {
auto emotes = EmoteMap(); auto emotes = EmoteMap();
@ -158,31 +185,6 @@ EmoteMap parseEmotes(const QJsonArray &emoteSetEmotes, bool isGlobal)
return emotes; return emotes;
} }
EmotePtr createUpdatedEmote(const EmotePtr &oldEmote,
const EmoteUpdateDispatch &dispatch)
{
bool toNonAliased = oldEmote->baseName.has_value() &&
dispatch.emoteName == oldEmote->baseName->string;
auto baseName = oldEmote->baseName.value_or(oldEmote->name);
auto emote = std::make_shared<const Emote>(Emote(
{EmoteName{dispatch.emoteName}, oldEmote->images,
toNonAliased
? createTooltip(dispatch.emoteName, oldEmote->author.string, false)
: createAliasedTooltip(dispatch.emoteName, baseName.string,
oldEmote->author.string, false),
oldEmote->homePage, oldEmote->zeroWidth, oldEmote->id,
oldEmote->author, makeConditionedOptional(!toNonAliased, baseName)}));
return emote;
}
} // namespace
namespace chatterino {
using namespace seventv::eventapi;
using namespace literals;
SeventvEmotes::SeventvEmotes() SeventvEmotes::SeventvEmotes()
: global_(std::make_shared<EmoteMap>()) : global_(std::make_shared<EmoteMap>())
{ {

View file

@ -4,6 +4,7 @@
#include "common/Atomic.hpp" #include "common/Atomic.hpp"
#include "common/FlagsEnum.hpp" #include "common/FlagsEnum.hpp"
#include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <memory> #include <memory>
@ -77,6 +78,12 @@ enum class SeventvEmoteSetFlag : uint32_t {
}; };
using SeventvEmoteSetFlags = FlagsEnum<SeventvEmoteSetFlag>; using SeventvEmoteSetFlags = FlagsEnum<SeventvEmoteSetFlag>;
namespace seventv::detail {
EmoteMap parseEmotes(const QJsonArray &emoteSetEmotes, bool isGlobal);
} // namespace seventv::detail
class SeventvEmotes final class SeventvEmotes final
{ {
public: public:

View file

@ -128,7 +128,7 @@ void updateReplyParticipatedStatus(const QVariantMap &tags,
bool isNew) bool isNew)
{ {
const auto &currentLogin = const auto &currentLogin =
getApp()->accounts->twitch.getCurrent()->getUserName(); getIApp()->getAccounts()->twitch.getCurrent()->getUserName();
if (thread->subscribed()) if (thread->subscribed())
{ {

View file

@ -29,6 +29,12 @@ void TwitchBadges::loadTwitchBadges()
{ {
assert(this->loaded_ == false); assert(this->loaded_ == false);
if (!getHelix())
{
// This is intended for tests and benchmarks.
return;
}
getHelix()->getGlobalBadges( getHelix()->getGlobalBadges(
[this](auto globalBadges) { [this](auto globalBadges) {
auto badgeSets = this->badgeSets_.access(); auto badgeSets = this->badgeSets_.access();

View file

@ -87,6 +87,13 @@ TwitchChannel::TwitchChannel(const QString &name)
{ {
qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened"; qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened";
if (!getApp())
{
// This is intended for tests and benchmarks.
// Irc, Pubsub, live-updates, and live-notifications aren't mocked there.
return;
}
this->bSignals_.emplace_back( this->bSignals_.emplace_back(
getApp()->accounts->twitch.currentUserChanged.connect([this] { getApp()->accounts->twitch.currentUserChanged.connect([this] {
this->setMod(false); this->setMod(false);
@ -219,6 +226,13 @@ TwitchChannel::TwitchChannel(const QString &name)
TwitchChannel::~TwitchChannel() TwitchChannel::~TwitchChannel()
{ {
if (!getApp())
{
// This is for tests and benchmarks, where live-updates aren't mocked
// see comment in constructor.
return;
}
getApp()->twitch->dropSeventvChannel(this->seventvUserID_, getApp()->twitch->dropSeventvChannel(this->seventvUserID_,
this->seventvEmoteSetID_); this->seventvEmoteSetID_);
@ -282,8 +296,9 @@ void TwitchChannel::refreshBTTVChannelEmotes(bool manualRefresh)
weakOf<Channel>(this), this->roomId(), this->getLocalizedName(), weakOf<Channel>(this), this->roomId(), this->getLocalizedName(),
[this, weak = weakOf<Channel>(this)](auto &&emoteMap) { [this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
if (auto shared = weak.lock()) if (auto shared = weak.lock())
this->bttvEmotes_.set( {
std::make_shared<EmoteMap>(std::move(emoteMap))); this->setBttvEmotes(std::make_shared<const EmoteMap>(emoteMap));
}
}, },
manualRefresh); manualRefresh);
} }
@ -300,8 +315,9 @@ void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh)
weakOf<Channel>(this), this->roomId(), weakOf<Channel>(this), this->roomId(),
[this, weak = weakOf<Channel>(this)](auto &&emoteMap) { [this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
if (auto shared = weak.lock()) if (auto shared = weak.lock())
this->ffzEmotes_.set( {
std::make_shared<EmoteMap>(std::move(emoteMap))); this->setFfzEmotes(std::make_shared<const EmoteMap>(emoteMap));
}
}, },
[this, weak = weakOf<Channel>(this)](auto &&modBadge) { [this, weak = weakOf<Channel>(this)](auto &&modBadge) {
if (auto shared = weak.lock()) if (auto shared = weak.lock())
@ -332,8 +348,8 @@ void TwitchChannel::refreshSevenTVChannelEmotes(bool manualRefresh)
auto channelInfo) { auto channelInfo) {
if (auto shared = weak.lock()) if (auto shared = weak.lock())
{ {
this->seventvEmotes_.set(std::make_shared<EmoteMap>( this->setSeventvEmotes(
std::forward<decltype(emoteMap)>(emoteMap))); std::make_shared<const EmoteMap>(emoteMap));
this->updateSeventvData(channelInfo.userID, this->updateSeventvData(channelInfo.userID,
channelInfo.emoteSetID); channelInfo.emoteSetID);
this->seventvUserTwitchConnectionIndex_ = this->seventvUserTwitchConnectionIndex_ =
@ -343,6 +359,21 @@ void TwitchChannel::refreshSevenTVChannelEmotes(bool manualRefresh)
manualRefresh); manualRefresh);
} }
void TwitchChannel::setBttvEmotes(std::shared_ptr<const EmoteMap> &&map)
{
this->bttvEmotes_.set(std::move(map));
}
void TwitchChannel::setFfzEmotes(std::shared_ptr<const EmoteMap> &&map)
{
this->ffzEmotes_.set(std::move(map));
}
void TwitchChannel::setSeventvEmotes(std::shared_ptr<const EmoteMap> &&map)
{
this->seventvEmotes_.set(std::move(map));
}
void TwitchChannel::addQueuedRedemption(const QString &rewardId, void TwitchChannel::addQueuedRedemption(const QString &rewardId,
const QString &originalContent, const QString &originalContent,
Communi::IrcMessage *message) Communi::IrcMessage *message)
@ -700,9 +731,10 @@ void TwitchChannel::setStaff(bool value)
bool TwitchChannel::isBroadcaster() const bool TwitchChannel::isBroadcaster() const
{ {
auto app = getApp(); auto *app = getIApp();
return this->getName() == app->accounts->twitch.getCurrent()->getUserName(); return this->getName() ==
app->getAccounts()->twitch.getCurrent()->getUserName();
} }
bool TwitchChannel::hasHighRateLimit() const bool TwitchChannel::hasHighRateLimit() const
@ -730,8 +762,12 @@ void TwitchChannel::setRoomId(const QString &id)
if (*this->roomID_.accessConst() != id) if (*this->roomID_.accessConst() != id)
{ {
*this->roomID_.access() = id; *this->roomID_.access() = id;
this->roomIdChanged(); // This is intended for tests and benchmarks. See comment in constructor.
this->loadRecentMessages(); if (getApp())
{
this->roomIdChanged();
this->loadRecentMessages();
}
this->disconnected_ = false; this->disconnected_ = false;
this->lastConnectedAt_ = std::chrono::system_clock::now(); this->lastConnectedAt_ = std::chrono::system_clock::now();
} }

View file

@ -158,6 +158,10 @@ public:
void refreshFFZChannelEmotes(bool manualRefresh); void refreshFFZChannelEmotes(bool manualRefresh);
void refreshSevenTVChannelEmotes(bool manualRefresh); void refreshSevenTVChannelEmotes(bool manualRefresh);
void setBttvEmotes(std::shared_ptr<const EmoteMap> &&map);
void setFfzEmotes(std::shared_ptr<const EmoteMap> &&map);
void setSeventvEmotes(std::shared_ptr<const EmoteMap> &&map);
const QString &seventvUserID() const; const QString &seventvUserID() const;
const QString &seventvEmoteSetID() const; const QString &seventvEmoteSetID() const;