diff --git a/.CI/chatterino-installer.iss b/.CI/chatterino-installer.iss
index fddd668f98c..1f9816a2978 100644
--- a/.CI/chatterino-installer.iss
+++ b/.CI/chatterino-installer.iss
@@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Chatterino"
-#define MyAppVersion "2.5.0"
+#define MyAppVersion "2.5.1"
#define MyAppPublisher "Chatterino Team"
#define MyAppURL "https://www.chatterino.com"
#define MyAppExeName "chatterino.exe"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7c21b747e22..614cf3ba05c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -126,7 +126,7 @@ jobs:
skip-artifact: false
skip-crashpad: false
# macOS
- - os: macos-latest
+ - os: macos-13
qt-version: 5.15.2
force-lto: false
plugins: true
@@ -222,7 +222,7 @@ jobs:
- name: Setup sccache (Windows)
# sccache v0.7.4
- uses: hendrikmuhs/ccache-action@v1.2.12
+ uses: hendrikmuhs/ccache-action@v1.2.13
if: startsWith(matrix.os, 'windows')
with:
variant: sccache
diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml
index f1c76e8cbb1..0b73ee84f30 100644
--- a/.github/workflows/test-windows.yml
+++ b/.github/workflows/test-windows.yml
@@ -69,7 +69,7 @@ jobs:
- name: Setup sccache
# sccache v0.7.4
- uses: hendrikmuhs/ccache-action@v1.2.12
+ uses: hendrikmuhs/ccache-action@v1.2.13
with:
variant: sccache
# only save on the default (master) branch
diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml
new file mode 100644
index 00000000000..7e8a5091a70
--- /dev/null
+++ b/.github/workflows/winget.yml
@@ -0,0 +1,14 @@
+name: Publish to WinGet
+on:
+ release:
+ types: [released]
+jobs:
+ publish:
+ runs-on: windows-latest
+ if: ${{ startsWith(github.event.release.tag_name, 'v') }}
+ steps:
+ - uses: vedantmgoyal2009/winget-releaser@v2
+ with:
+ identifier: ChatterinoTeam.Chatterino
+ installers-regex: ^Chatterino.Installer.exe$
+ token: ${{ secrets.WINGET_TOKEN }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f9d0c2a4ff5..d661e61d8e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
## Unversioned
+- Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378)
+- Dev: Add doxygen build target. (#5377)
+- Dev: Make printing of strings in tests easier. (#5379)
+
+## 2.5.1
+
+- Bugfix: Fixed links without a protocol not being clickable. (#5345)
+
## 2.5.0
### Dankerino
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3a08cf79ee1..eec6b7e1c8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,7 +41,7 @@ if(BUILD_BENCHMARKS)
endif()
project(chatterino
- VERSION 2.5.0
+ VERSION 2.5.1
DESCRIPTION "Chat client for twitch.tv"
HOMEPAGE_URL "https://chatterino.com/"
)
@@ -197,6 +197,7 @@ find_package(PajladaSerialize REQUIRED)
find_package(PajladaSignals REQUIRED)
find_package(LRUCache REQUIRED)
find_package(MagicEnum REQUIRED)
+find_package(Doxygen)
if (USE_SYSTEM_PAJLADA_SETTINGS)
find_package(PajladaSettings REQUIRED)
diff --git a/lib/settings b/lib/settings
index 70fbc7236aa..03e8af1934e 160000
--- a/lib/settings
+++ b/lib/settings
@@ -1 +1 @@
-Subproject commit 70fbc7236aa8bcf5db4748e7f56dad132d6fd402
+Subproject commit 03e8af1934e6151edfe8a44dfb025b747a31acdf
diff --git a/resources/com.chatterino.chatterino.appdata.xml b/resources/com.chatterino.chatterino.appdata.xml
index 69d1b9289d6..a2d09fecbdc 100644
--- a/resources/com.chatterino.chatterino.appdata.xml
+++ b/resources/com.chatterino.chatterino.appdata.xml
@@ -34,6 +34,9 @@
chatterino
+
+ https://github.com/Chatterino/chatterino2/releases/tag/v2.5.1
+
https://github.com/Chatterino/chatterino2/releases/tag/v2.5.0
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9e112f754c6..3fab4b6a36f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1153,3 +1153,14 @@ if(NOT CHATTERINO_UPDATER)
message(STATUS "Disabling the updater.")
target_compile_definitions(${LIBRARY_PROJECT} PUBLIC CHATTERINO_DISABLE_UPDATER)
endif()
+
+if (DOXYGEN_FOUND)
+ message(STATUS "Doxygen found, adding doxygen target")
+ # output will be in docs/html
+ set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/docs")
+
+ doxygen_add_docs(
+ doxygen
+ ${CMAKE_CURRENT_LIST_DIR}
+ )
+endif ()
diff --git a/src/common/Version.hpp b/src/common/Version.hpp
index 07a23a0acde..687f3094e00 100644
--- a/src/common/Version.hpp
+++ b/src/common/Version.hpp
@@ -24,7 +24,7 @@
* - 2.4.0-alpha.2
* - 2.4.0-alpha
**/
-#define CHATTERINO_VERSION "2.5.0"
+#define CHATTERINO_VERSION "2.5.1"
#if defined(Q_OS_WIN)
# define CHATTERINO_OS "win"
diff --git a/src/common/network/NetworkResult.cpp b/src/common/network/NetworkResult.cpp
index 177d2ae6f97..c6544eaad80 100644
--- a/src/common/network/NetworkResult.cpp
+++ b/src/common/network/NetworkResult.cpp
@@ -67,7 +67,9 @@ const QByteArray &NetworkResult::getData() const
QString NetworkResult::formatError() const
{
- if (this->status_)
+ // Print the status for errors that mirror HTTP status codes (=0 || >99)
+ if (this->status_ && (this->error_ == QNetworkReply::NoError ||
+ this->error_ > QNetworkReply::UnknownNetworkError))
{
return QString::number(*this->status_);
}
@@ -77,6 +79,13 @@ QString NetworkResult::formatError() const
this->error_);
if (name == nullptr)
{
+ if (this->status_)
+ {
+ return QStringLiteral("unknown error (status: %1, error: %2)")
+ .arg(QString::number(*this->status_),
+ QString::number(this->error_));
+ }
+
return QStringLiteral("unknown error (%1)").arg(this->error_);
}
return name;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index fb5730048b8..bd35b79dee9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -5,7 +5,8 @@ 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/Test.hpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/Test.cpp
${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/README.md b/tests/README.md
index f9bc5798a9a..47ac1b202ae 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -7,4 +7,4 @@ docker run --network=host --detach ghcr.io/chatterino/twitch-pubsub-server-test:
docker run -p 9051:80 --detach kennethreitz/httpbin
```
-If you're unable to use docker, you can use [httpbox](github.com/kevinastone/httpbox) (`httpbox --port 9051`) and [Chatterino/twitch-pubsub-server-test](https://github.com/Chatterino/twitch-pubsub-server-test/releases/latest) manually.
+If you're unable to use docker, you can use [httpbox](https://github.com/kevinastone/httpbox) (`httpbox --port 9051`) and [Chatterino/twitch-pubsub-server-test](https://github.com/Chatterino/twitch-pubsub-server-test/releases/latest) manually.
diff --git a/tests/src/AccessGuard.cpp b/tests/src/AccessGuard.cpp
index a0d1c6d3199..56cbc727fea 100644
--- a/tests/src/AccessGuard.cpp
+++ b/tests/src/AccessGuard.cpp
@@ -1,6 +1,6 @@
#include "common/UniqueAccess.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/BasicPubSub.cpp b/tests/src/BasicPubSub.cpp
index dc277522028..6315970ff06 100644
--- a/tests/src/BasicPubSub.cpp
+++ b/tests/src/BasicPubSub.cpp
@@ -1,7 +1,7 @@
#include "providers/liveupdates/BasicPubSubClient.hpp"
#include "providers/liveupdates/BasicPubSubManager.hpp"
+#include "Test.hpp"
-#include
#include
#include
#include
diff --git a/tests/src/BttvLiveUpdates.cpp b/tests/src/BttvLiveUpdates.cpp
index 580f2e61f96..2d238f9b0b8 100644
--- a/tests/src/BttvLiveUpdates.cpp
+++ b/tests/src/BttvLiveUpdates.cpp
@@ -1,6 +1,7 @@
#include "providers/bttv/BttvLiveUpdates.hpp"
-#include
+#include "Test.hpp"
+
#include
#include
diff --git a/tests/src/ChannelChatters.cpp b/tests/src/ChannelChatters.cpp
index c665836bb38..79711ce15af 100644
--- a/tests/src/ChannelChatters.cpp
+++ b/tests/src/ChannelChatters.cpp
@@ -1,8 +1,8 @@
#include "common/ChannelChatters.hpp"
#include "mocks/Channel.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/ChatterSet.cpp b/tests/src/ChatterSet.cpp
index ac5b81ee926..57a67a77113 100644
--- a/tests/src/ChatterSet.cpp
+++ b/tests/src/ChatterSet.cpp
@@ -1,6 +1,7 @@
#include "common/ChatterSet.hpp"
-#include
+#include "Test.hpp"
+
#include
TEST(ChatterSet, insert)
diff --git a/tests/src/Emojis.cpp b/tests/src/Emojis.cpp
index 141a64afbf7..42df110a426 100644
--- a/tests/src/Emojis.cpp
+++ b/tests/src/Emojis.cpp
@@ -1,9 +1,8 @@
#include "providers/emoji/Emojis.hpp"
#include "common/Literals.hpp"
-#include "TestHelpers.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/ExponentialBackoff.cpp b/tests/src/ExponentialBackoff.cpp
index 2a4259744a1..7099ea08a17 100644
--- a/tests/src/ExponentialBackoff.cpp
+++ b/tests/src/ExponentialBackoff.cpp
@@ -1,6 +1,6 @@
#include "util/ExponentialBackoff.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
diff --git a/tests/src/Filters.cpp b/tests/src/Filters.cpp
index ff1b0590212..89c0a510f88 100644
--- a/tests/src/Filters.cpp
+++ b/tests/src/Filters.cpp
@@ -13,8 +13,8 @@
#include "providers/twitch/TwitchBadge.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "singletons/Emotes.hpp"
+#include "Test.hpp"
-#include
#include
#include
@@ -101,7 +101,7 @@ namespace chatterino::filters {
std::ostream &operator<<(std::ostream &os, Type t)
{
- os << qUtf8Printable(typeToString(t));
+ os << typeToString(t);
return os;
}
@@ -138,8 +138,8 @@ TEST(Filters, Validity)
auto filterResult = Filter::fromString(input);
bool isValid = std::holds_alternative(filterResult);
EXPECT_EQ(isValid, expected)
- << "Filter::fromString( " << qUtf8Printable(input)
- << " ) should be " << (expected ? "valid" : "invalid");
+ << "Filter::fromString( " << input << " ) should be "
+ << (expected ? "valid" : "invalid");
}
}
@@ -168,15 +168,14 @@ TEST(Filters, TypeSynthesis)
{
auto filterResult = Filter::fromString(input);
bool isValid = std::holds_alternative(filterResult);
- ASSERT_TRUE(isValid) << "Filter::fromString( " << qUtf8Printable(input)
- << " ) is invalid";
+ ASSERT_TRUE(isValid)
+ << "Filter::fromString( " << input << " ) is invalid";
auto filter = std::move(std::get(filterResult));
T type = filter.returnType();
EXPECT_EQ(type, expected)
- << "Filter{ " << qUtf8Printable(input) << " } has type " << type
- << " instead of " << expected << ".\nDebug: "
- << qUtf8Printable(filter.debugString(typingContext));
+ << "Filter{ " << input << " } has type " << type << " instead of "
+ << expected << ".\nDebug: " << filter.debugString(typingContext);
}
}
@@ -244,17 +243,16 @@ TEST(Filters, Evaluation)
{
auto filterResult = Filter::fromString(input);
bool isValid = std::holds_alternative(filterResult);
- ASSERT_TRUE(isValid) << "Filter::fromString( " << qUtf8Printable(input)
- << " ) is invalid";
+ ASSERT_TRUE(isValid)
+ << "Filter::fromString( " << input << " ) is invalid";
auto filter = std::move(std::get(filterResult));
auto result = filter.execute(contextMap);
EXPECT_EQ(result, expected)
- << "Filter{ " << qUtf8Printable(input) << " } evaluated to "
- << qUtf8Printable(result.toString()) << " instead of "
- << qUtf8Printable(expected.toString()) << ".\nDebug: "
- << qUtf8Printable(filter.debugString(typingContext));
+ << "Filter{ " << input << " } evaluated to " << result.toString()
+ << " instead of " << expected.toString()
+ << ".\nDebug: " << filter.debugString(typingContext);
}
}
@@ -354,20 +352,17 @@ TEST_F(FiltersF, ExpressionDebug)
{
const auto filterResult = Filter::fromString(input);
const auto *filter = std::get_if(&filterResult);
- EXPECT_NE(filter, nullptr)
- << "Filter::fromString(" << qUtf8Printable(input)
- << ") did not build a proper filter";
+ EXPECT_NE(filter, nullptr) << "Filter::fromString(" << input
+ << ") did not build a proper filter";
const auto actualDebugString = filter->debugString(typingContext);
EXPECT_EQ(actualDebugString, debugString)
- << "filter->debugString() on '" << qUtf8Printable(input)
- << "' should be '" << qUtf8Printable(debugString) << "', but got '"
- << qUtf8Printable(actualDebugString) << "'";
+ << "filter->debugString() on '" << input << "' should be '"
+ << debugString << "', but got '" << actualDebugString << "'";
const auto actualFilterString = filter->filterString();
EXPECT_EQ(actualFilterString, filterString)
- << "filter->filterString() on '" << qUtf8Printable(input)
- << "' should be '" << qUtf8Printable(filterString) << "', but got '"
- << qUtf8Printable(actualFilterString) << "'";
+ << "filter->filterString() on '" << input << "' should be '"
+ << filterString << "', but got '" << actualFilterString << "'";
}
}
diff --git a/tests/src/FormatTime.cpp b/tests/src/FormatTime.cpp
index bc15f44efe6..6fe82ab9a8c 100644
--- a/tests/src/FormatTime.cpp
+++ b/tests/src/FormatTime.cpp
@@ -1,6 +1,6 @@
#include "util/FormatTime.hpp"
-#include
+#include "Test.hpp"
#include
@@ -62,8 +62,8 @@ TEST(FormatTime, Int)
const auto actual = formatTime(input);
EXPECT_EQ(actual, expected)
- << qUtf8Printable(actual) << " (" << input
- << ") did not match expected value " << qUtf8Printable(expected);
+ << actual << " (" << input << ") did not match expected value "
+ << expected;
}
}
@@ -130,8 +130,8 @@ TEST(FormatTime, QString)
const auto actual = formatTime(input);
EXPECT_EQ(actual, expected)
- << qUtf8Printable(actual) << " (" << qUtf8Printable(input)
- << ") did not match expected value " << qUtf8Printable(expected);
+ << actual << " (" << input << ") did not match expected value "
+ << expected;
}
}
@@ -202,7 +202,6 @@ TEST(FormatTime, chrono)
const auto actual = formatTime(input);
EXPECT_EQ(actual, expected)
- << qUtf8Printable(actual) << " did not match expected value "
- << qUtf8Printable(expected);
+ << actual << " did not match expected value " << expected;
}
}
diff --git a/tests/src/Helpers.cpp b/tests/src/Helpers.cpp
index 7fcd02837bc..0783c36e129 100644
--- a/tests/src/Helpers.cpp
+++ b/tests/src/Helpers.cpp
@@ -1,6 +1,6 @@
#include "util/Helpers.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
using namespace _helpers_internal;
@@ -279,8 +279,8 @@ TEST(Helpers, skipSpace)
const auto actual = skipSpace(makeView(c.input), c.startIdx);
EXPECT_EQ(actual, c.expected)
- << actual << " (" << qUtf8Printable(c.input)
- << ") did not match expected value " << c.expected;
+ << actual << " (" << c.input << ") did not match expected value "
+ << c.expected;
}
}
@@ -422,14 +422,13 @@ TEST(Helpers, findUnitMultiplierToSec)
if (c.expectedMultiplier == bad)
{
- EXPECT_FALSE(actual.second) << qUtf8Printable(c.input);
+ EXPECT_FALSE(actual.second) << c.input;
}
else
{
EXPECT_TRUE(pos == c.expectedEndPos && actual.second &&
actual.first == c.expectedMultiplier)
- << qUtf8Printable(c.input)
- << ": Expected(end: " << c.expectedEndPos
+ << c.input << ": Expected(end: " << c.expectedEndPos
<< ", mult: " << c.expectedMultiplier << ") Actual(end: " << pos
<< ", mult: " << actual.first << ")";
}
@@ -507,7 +506,7 @@ TEST(Helpers, parseDurationToSeconds)
const auto actual = parseDurationToSeconds(c.input, c.noUnitMultiplier);
EXPECT_EQ(actual, c.output)
- << actual << " (" << qUtf8Printable(c.input)
- << ") did not match expected value " << c.output;
+ << actual << " (" << c.input << ") did not match expected value "
+ << c.output;
}
}
diff --git a/tests/src/HighlightController.cpp b/tests/src/HighlightController.cpp
index a45bbf98c02..090acf37b15 100644
--- a/tests/src/HighlightController.cpp
+++ b/tests/src/HighlightController.cpp
@@ -10,9 +10,8 @@
#include "providers/twitch/TwitchBadge.hpp" // for Badge
#include "singletons/Paths.hpp"
#include "singletons/Settings.hpp"
+#include "Test.hpp"
-#include
-#include
#include
#include
#include
@@ -216,11 +215,9 @@ class HighlightControllerTest : public ::testing::Test
input.originalMessage, input.flags);
EXPECT_EQ(isMatch, expected.state)
- << qUtf8Printable(input.senderName) << ": "
- << qUtf8Printable(input.originalMessage);
+ << input.senderName << ": " << input.originalMessage;
EXPECT_EQ(matchResult, expected.result)
- << qUtf8Printable(input.senderName) << ": "
- << qUtf8Printable(input.originalMessage);
+ << input.senderName << ": " << input.originalMessage;
}
}
diff --git a/tests/src/HighlightPhrase.cpp b/tests/src/HighlightPhrase.cpp
index 374670b03d3..2ec2530f0f5 100644
--- a/tests/src/HighlightPhrase.cpp
+++ b/tests/src/HighlightPhrase.cpp
@@ -1,6 +1,6 @@
#include "controllers/highlights/HighlightPhrase.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
diff --git a/tests/src/Hotkeys.cpp b/tests/src/Hotkeys.cpp
index ebbfe50297f..7c3d8d10fe6 100644
--- a/tests/src/Hotkeys.cpp
+++ b/tests/src/Hotkeys.cpp
@@ -1,6 +1,5 @@
#include "controllers/hotkeys/HotkeyHelpers.hpp"
-
-#include
+#include "Test.hpp"
#include
diff --git a/tests/src/InputCompletion.cpp b/tests/src/InputCompletion.cpp
index 86003543871..22c42b31cb1 100644
--- a/tests/src/InputCompletion.cpp
+++ b/tests/src/InputCompletion.cpp
@@ -12,9 +12,9 @@
#include "singletons/Emotes.hpp"
#include "singletons/Paths.hpp"
#include "singletons/Settings.hpp"
+#include "Test.hpp"
#include "widgets/splits/InputCompletionPopup.hpp"
-#include
#include
#include
#include
@@ -224,7 +224,7 @@ void containsRoughly(std::span span, std::set values)
}
}
- ASSERT_TRUE(found) << qPrintable(v) << " was not found in the span";
+ ASSERT_TRUE(found) << v << " was not found in the span";
}
}
diff --git a/tests/src/IrcHelpers.cpp b/tests/src/IrcHelpers.cpp
index acae81c3537..d210b14e003 100644
--- a/tests/src/IrcHelpers.cpp
+++ b/tests/src/IrcHelpers.cpp
@@ -1,6 +1,7 @@
#include "util/IrcHelpers.hpp"
-#include
+#include "Test.hpp"
+
#include
#include
#include
@@ -55,7 +56,7 @@ TEST(IrcHelpers, ParseTagString)
const auto actual = parseTagString(input);
EXPECT_EQ(actual, expected)
- << qUtf8Printable(actual) << " (" << qUtf8Printable(input)
- << ") did not match expected value " << qUtf8Printable(expected);
+ << actual << " (" << input << ") did not match expected value "
+ << expected;
}
}
diff --git a/tests/src/LimitedQueue.cpp b/tests/src/LimitedQueue.cpp
index 39a8bba86ac..0a94ea92874 100644
--- a/tests/src/LimitedQueue.cpp
+++ b/tests/src/LimitedQueue.cpp
@@ -1,6 +1,6 @@
#include "messages/LimitedQueue.hpp"
-#include
+#include "Test.hpp"
#include
diff --git a/tests/src/LinkInfo.cpp b/tests/src/LinkInfo.cpp
index 91f065035ce..a06a78c0f9c 100644
--- a/tests/src/LinkInfo.cpp
+++ b/tests/src/LinkInfo.cpp
@@ -2,8 +2,7 @@
#include "common/Literals.hpp"
#include "SignalSpy.hpp"
-
-#include
+#include "Test.hpp"
using namespace chatterino;
using namespace literals;
diff --git a/tests/src/LinkParser.cpp b/tests/src/LinkParser.cpp
index cce5c8c6c52..9d964ce1542 100644
--- a/tests/src/LinkParser.cpp
+++ b/tests/src/LinkParser.cpp
@@ -1,8 +1,7 @@
#include "common/LinkParser.hpp"
-#include "TestHelpers.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/Literals.cpp b/tests/src/Literals.cpp
index 77607b73977..17d459b1431 100644
--- a/tests/src/Literals.cpp
+++ b/tests/src/Literals.cpp
@@ -1,6 +1,6 @@
#include "common/Literals.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino::literals;
diff --git a/tests/src/MessageLayout.cpp b/tests/src/MessageLayout.cpp
index 9ce0c7f21e8..ab9a294c9b8 100644
--- a/tests/src/MessageLayout.cpp
+++ b/tests/src/MessageLayout.cpp
@@ -10,8 +10,8 @@
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/NetworkCommon.cpp b/tests/src/NetworkCommon.cpp
index 481f951aee5..9beab8da68c 100644
--- a/tests/src/NetworkCommon.cpp
+++ b/tests/src/NetworkCommon.cpp
@@ -1,6 +1,6 @@
#include "common/network/NetworkCommon.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
diff --git a/tests/src/NetworkRequest.cpp b/tests/src/NetworkRequest.cpp
index 2f6b8102f96..ca723481efe 100644
--- a/tests/src/NetworkRequest.cpp
+++ b/tests/src/NetworkRequest.cpp
@@ -2,8 +2,8 @@
#include "common/network/NetworkManager.hpp"
#include "common/network/NetworkResult.hpp"
+#include "Test.hpp"
-#include
#include
using namespace chatterino;
diff --git a/tests/src/NetworkResult.cpp b/tests/src/NetworkResult.cpp
index 72a2ca771f0..4d4c574210d 100644
--- a/tests/src/NetworkResult.cpp
+++ b/tests/src/NetworkResult.cpp
@@ -1,6 +1,6 @@
#include "common/network/NetworkResult.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
@@ -37,12 +37,21 @@ TEST(NetworkResult, Errors)
"RemoteHostClosedError");
// status code takes precedence
- checkResult({Error::TimeoutError, 400, {}}, Error::TimeoutError, 400,
- "400");
+ checkResult({Error::InternalServerError, 400, {}},
+ Error::InternalServerError, 400, "400");
+
+ // error takes precedence (1..=99)
+ checkResult({Error::BackgroundRequestNotAllowedError, 400, {}},
+ Error::BackgroundRequestNotAllowedError, 400,
+ "BackgroundRequestNotAllowedError");
+ checkResult({Error::UnknownNetworkError, 400, {}},
+ Error::UnknownNetworkError, 400, "UnknownNetworkError");
}
TEST(NetworkResult, InvalidError)
{
checkResult({static_cast(-1), {}, {}}, static_cast(-1),
std::nullopt, "unknown error (-1)");
+ checkResult({static_cast(-1), 42, {}}, static_cast(-1), 42,
+ "unknown error (status: 42, error: -1)");
}
diff --git a/tests/src/NotebookTab.cpp b/tests/src/NotebookTab.cpp
index 2ac4903f47e..36133b648c8 100644
--- a/tests/src/NotebookTab.cpp
+++ b/tests/src/NotebookTab.cpp
@@ -7,10 +7,9 @@
#include "singletons/Fonts.hpp"
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
+#include "Test.hpp"
#include "widgets/Notebook.hpp"
-#include
-#include
#include
#include
diff --git a/tests/src/QMagicEnum.cpp b/tests/src/QMagicEnum.cpp
index 80c265efe24..6778427fe43 100644
--- a/tests/src/QMagicEnum.cpp
+++ b/tests/src/QMagicEnum.cpp
@@ -2,8 +2,7 @@
#include "common/FlagsEnum.hpp"
#include "common/Literals.hpp"
-
-#include
+#include "Test.hpp"
using namespace chatterino;
using namespace literals;
diff --git a/tests/src/RatelimitBucket.cpp b/tests/src/RatelimitBucket.cpp
index c92a42234b8..850f14c68cb 100644
--- a/tests/src/RatelimitBucket.cpp
+++ b/tests/src/RatelimitBucket.cpp
@@ -1,6 +1,7 @@
#include "util/RatelimitBucket.hpp"
-#include
+#include "Test.hpp"
+
#include
#include
#include
diff --git a/tests/src/Selection.cpp b/tests/src/Selection.cpp
index 1f1f4a62137..a904b076656 100644
--- a/tests/src/Selection.cpp
+++ b/tests/src/Selection.cpp
@@ -1,6 +1,6 @@
#include "messages/Selection.hpp"
-#include
+#include "Test.hpp"
using namespace chatterino;
diff --git a/tests/src/SeventvEventAPI.cpp b/tests/src/SeventvEventAPI.cpp
index 780f90bac10..4e2d3228193 100644
--- a/tests/src/SeventvEventAPI.cpp
+++ b/tests/src/SeventvEventAPI.cpp
@@ -3,8 +3,8 @@
#include "providers/seventv/eventapi/Client.hpp"
#include "providers/seventv/eventapi/Dispatch.hpp"
#include "providers/seventv/eventapi/Message.hpp"
+#include "Test.hpp"
-#include
#include
#include
diff --git a/tests/src/SplitInput.cpp b/tests/src/SplitInput.cpp
index ed092f94baf..d84da81188a 100644
--- a/tests/src/SplitInput.cpp
+++ b/tests/src/SplitInput.cpp
@@ -12,11 +12,10 @@
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp"
+#include "Test.hpp"
#include "widgets/Notebook.hpp"
#include "widgets/splits/Split.hpp"
-#include
-#include
#include
#include
@@ -110,9 +109,8 @@ TEST_P(SplitInputTest, Reply)
auto reply = MessagePtr(message);
this->input.setReply(reply);
QString actual = this->input.getInputText();
- ASSERT_EQ(expected, actual)
- << "Input text after setReply should be '" << qUtf8Printable(expected)
- << "', but got '" << qUtf8Printable(actual) << "'";
+ ASSERT_EQ(expected, actual) << "Input text after setReply should be '"
+ << expected << "', but got '" << actual << "'";
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/tests/src/Test.cpp b/tests/src/Test.cpp
new file mode 100644
index 00000000000..5f245f5d7f2
--- /dev/null
+++ b/tests/src/Test.cpp
@@ -0,0 +1,42 @@
+#include "Test.hpp"
+
+#include
+#include
+
+std::ostream &operator<<(std::ostream &os, QStringView str)
+{
+ os << str.toString().toStdString();
+ return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const QByteArray &bytes)
+{
+ os << std::string_view{bytes.data(), static_cast(bytes.size())};
+ return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const QString &str)
+{
+ os << str.toStdString();
+ return os;
+}
+
+// The PrintTo overloads use UniversalPrint to print strings in quotes.
+// Even though this uses testing::internal, this is publically documented in
+// gtest/gtest-printers.h.
+
+void PrintTo(const QByteArray &bytes, std::ostream *os)
+{
+ ::testing::internal::UniversalPrint(bytes.toStdString(), os);
+}
+
+void PrintTo(QStringView str, std::ostream *os)
+{
+ ::testing::internal::UniversalPrint(
+ std::u16string{str.utf16(), static_cast(str.size())}, os);
+}
+
+void PrintTo(const QString &str, std::ostream *os)
+{
+ ::testing::internal::UniversalPrint(str.toStdU16String(), os);
+}
diff --git a/tests/src/Test.hpp b/tests/src/Test.hpp
new file mode 100644
index 00000000000..064f90c6d79
--- /dev/null
+++ b/tests/src/Test.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+class QString;
+class QStringView;
+class QByteArray;
+
+// This file is included in all TUs in chatterino-test to avoid ODR violations.
+std::ostream &operator<<(std::ostream &os, QStringView str);
+std::ostream &operator<<(std::ostream &os, const QByteArray &bytes);
+std::ostream &operator<<(std::ostream &os, const QString &str);
+
+// NOLINTBEGIN(readability-identifier-naming)
+// PrintTo is used for naming parameterized tests, and is part of gtest
+void PrintTo(const QByteArray &bytes, std::ostream *os);
+void PrintTo(QStringView str, std::ostream *os);
+void PrintTo(const QString &str, std::ostream *os);
+// NOLINTEND(readability-identifier-naming)
diff --git a/tests/src/TestHelpers.hpp b/tests/src/TestHelpers.hpp
deleted file mode 100644
index 30a2d0b1a25..00000000000
--- a/tests/src/TestHelpers.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-#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;
- }
-};
-
-inline std::ostream &operator<<(std::ostream &os, const QStringView &str)
-{
- os << qUtf8Printable(str.toString());
- return os;
-}
-
-inline std::ostream &operator<<(std::ostream &os, const QByteArray &bytes)
-{
- os << bytes.toStdString();
- return os;
-}
-
-inline std::ostream &operator<<(std::ostream &os, const QString &str)
-{
- os << qUtf8Printable(str);
- return os;
-}
diff --git a/tests/src/TwitchMessageBuilder.cpp b/tests/src/TwitchMessageBuilder.cpp
index 77ddcdf4659..d9d1d5a62f6 100644
--- a/tests/src/TwitchMessageBuilder.cpp
+++ b/tests/src/TwitchMessageBuilder.cpp
@@ -15,9 +15,8 @@
#include "providers/seventv/SeventvBadges.hpp"
#include "providers/twitch/TwitchBadge.hpp"
#include "singletons/Emotes.hpp"
-#include "TestHelpers.hpp"
+#include "Test.hpp"
-#include
#include
#include
#include
diff --git a/tests/src/TwitchPubSubClient.cpp b/tests/src/TwitchPubSubClient.cpp
index 30e02e56759..728b0e5bbcc 100644
--- a/tests/src/TwitchPubSubClient.cpp
+++ b/tests/src/TwitchPubSubClient.cpp
@@ -4,12 +4,12 @@
#include "providers/twitch/pubsubmessages/AutoMod.hpp"
#include "providers/twitch/pubsubmessages/Whisper.hpp"
#include "providers/twitch/TwitchAccount.hpp"
-#include "TestHelpers.hpp"
+#include "Test.hpp"
-#include
#include
#include
+#include
#include
using namespace chatterino;
@@ -33,6 +33,47 @@ using namespace std::chrono_literals;
#ifdef RUN_PUBSUB_TESTS
+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;
+ }
+};
+
class FTest : public PubSub
{
public:
diff --git a/tests/src/Updates.cpp b/tests/src/Updates.cpp
index da4762517a6..ce16f329f6a 100644
--- a/tests/src/Updates.cpp
+++ b/tests/src/Updates.cpp
@@ -1,8 +1,8 @@
#include "singletons/Updates.hpp"
#include "common/Version.hpp"
+#include "Test.hpp"
-#include
#include
using namespace chatterino;
diff --git a/tests/src/UtilTwitch.cpp b/tests/src/UtilTwitch.cpp
index 6a0b58d9fa6..3a2a7b41ba5 100644
--- a/tests/src/UtilTwitch.cpp
+++ b/tests/src/UtilTwitch.cpp
@@ -1,6 +1,6 @@
+#include "Test.hpp"
#include "util/Twitch.hpp"
-#include
#include
#include
#include
@@ -72,9 +72,8 @@ TEST(UtilTwitch, StripUserName)
stripUserName(userName);
EXPECT_EQ(userName, expectedUserName)
- << qUtf8Printable(userName) << " (" << qUtf8Printable(inputUserName)
- << ") did not match expected value "
- << qUtf8Printable(expectedUserName);
+ << userName << " (" << inputUserName
+ << ") did not match expected value " << expectedUserName;
}
}
@@ -153,10 +152,8 @@ TEST(UtilTwitch, StripChannelName)
stripChannelName(userName);
EXPECT_EQ(userName, expectedChannelName)
- << qUtf8Printable(userName) << " ("
- << qUtf8Printable(inputChannelName)
- << ") did not match expected value "
- << qUtf8Printable(expectedChannelName);
+ << userName << " (" << inputChannelName
+ << ") did not match expected value " << expectedChannelName;
}
}
@@ -259,14 +256,12 @@ TEST(UtilTwitch, ParseUserNameOrID)
auto [actualUserName, actualUserID] = parseUserNameOrID(input);
EXPECT_EQ(actualUserName, expectedUserName)
- << "name " << qUtf8Printable(actualUserName) << " ("
- << qUtf8Printable(input) << ") did not match expected value "
- << qUtf8Printable(expectedUserName);
+ << "name " << actualUserName << " (" << input
+ << ") did not match expected value " << expectedUserName;
EXPECT_EQ(actualUserID, expectedUserID)
- << "id " << qUtf8Printable(actualUserID) << " ("
- << qUtf8Printable(input) << ") did not match expected value "
- << qUtf8Printable(expectedUserID);
+ << "id " << actualUserID << " (" << input
+ << ") did not match expected value " << expectedUserID;
}
}
@@ -319,7 +314,7 @@ TEST(UtilTwitch, UserLoginRegexp)
auto actual = regexp.match(inputUserLogin);
EXPECT_EQ(match.hasMatch(), expectedMatch)
- << qUtf8Printable(inputUserLogin) << " did not match as expected";
+ << inputUserLogin << " did not match as expected";
}
}
@@ -371,7 +366,7 @@ TEST(UtilTwitch, UserNameRegexp)
auto actual = regexp.match(inputUserLogin);
EXPECT_EQ(match.hasMatch(), expectedMatch)
- << qUtf8Printable(inputUserLogin) << " did not match as expected";
+ << inputUserLogin << " did not match as expected";
}
}
@@ -405,8 +400,7 @@ TEST(UtilTwitch, CleanHelixColor)
cleanHelixColorName(actualColor);
EXPECT_EQ(actualColor, expectedColor)
- << qUtf8Printable(inputColor) << " cleaned up to "
- << qUtf8Printable(actualColor) << " instead of "
- << qUtf8Printable(expectedColor);
+ << inputColor << " cleaned up to " << actualColor << " instead of "
+ << expectedColor;
}
}
diff --git a/tests/src/XDGDesktopFile.cpp b/tests/src/XDGDesktopFile.cpp
index bffe529aad2..69f4d370642 100644
--- a/tests/src/XDGDesktopFile.cpp
+++ b/tests/src/XDGDesktopFile.cpp
@@ -1,6 +1,7 @@
#include "util/XDGDesktopFile.hpp"
-#include
+#include "Test.hpp"
+
#include
#if defined(Q_OS_UNIX) and !defined(Q_OS_DARWIN)
diff --git a/tests/src/XDGHelper.cpp b/tests/src/XDGHelper.cpp
index 3926d21d926..3ab48daa3d5 100644
--- a/tests/src/XDGHelper.cpp
+++ b/tests/src/XDGHelper.cpp
@@ -1,8 +1,7 @@
#include "util/XDGHelper.hpp"
-#include "TestHelpers.hpp"
+#include "Test.hpp"
-#include
#include
#if defined(Q_OS_UNIX) and !defined(Q_OS_DARWIN)
diff --git a/tests/src/main.cpp b/tests/src/main.cpp
index 3b24a997885..6c82f632cb8 100644
--- a/tests/src/main.cpp
+++ b/tests/src/main.cpp
@@ -1,8 +1,8 @@
#include "common/network/NetworkManager.hpp"
#include "singletons/Resources.hpp"
#include "singletons/Settings.hpp"
+#include "Test.hpp"
-#include
#include
#include
#include