#include #include "../src/utils/Log.h" class TestLog : public QObject { Q_OBJECT private slots: // ParseLogLevel tests void testParseLogLevel_data(); void testParseLogLevel(); // CensorAuthTokens tests void testCensorAuthTokens_data(); void testCensorAuthTokens(); }; /////////////////////////////////////////////////////////////////////////////// // ParseLogLevel /////////////////////////////////////////////////////////////////////////////// void TestLog::testParseLogLevel_data() { QTest::addColumn("input"); QTest::addColumn("expected"); // Log levels. QTest::newRow("debug") << "debug" << 0; QTest::newRow("info") << "info" << 1; QTest::newRow("warn") << "warn" << 2; QTest::newRow("error") << "error" << 3; QTest::newRow("fatal") << "fatal" << 4; // Invalid log levels. QTest::newRow("empty string") << "" << -1; QTest::newRow("unknown level") << "whoohoo" << -1; QTest::newRow("numeric") << "0" << -1; QTest::newRow("uppercase DEBUG") << "DEBUG" << -1; QTest::newRow("mixed case Info") << "InFo" << -1; QTest::newRow("warning") << "warning" << -1; QTest::newRow("critical") << "critical" << -1; QTest::newRow("space before") << " debug" << -1; QTest::newRow("trailing space") << "debug " << -1; } void TestLog::testParseLogLevel() { QFETCH(QString, input); QFETCH(int, expected); QCOMPARE(Log::ParseLogLevel(input), expected); } /////////////////////////////////////////////////////////////////////////////// // CensorAuthTokens /////////////////////////////////////////////////////////////////////////////// void TestLog::testCensorAuthTokens_data() { QTest::addColumn("input"); QTest::addColumn("expected"); const QString masked32 = QString(32, 'x'); // Base case: No tokens in string QTest::newRow("no token") << "GET /Items?UserId=abc123" << "GET /Items?UserId=abc123"; // Base case: Empty string QTest::newRow("empty string") << "" << ""; // API key QTest::newRow("api_key") << "url?api_key=abcdef0123456789abcdef0123456789&other=1" << "url?api_key=" + masked32 + "&other=1"; // X-MediaBrowser-Token, URL-encoded QTest::newRow("X-MediaBrowser-Token URL-encoded") << "header=X-MediaBrowser-Token%3Dabcdef0123456789abcdef0123456789done" << "header=X-MediaBrowser-Token%3D" + masked32 + "done"; // X-MediaBrowser-Token, plain QTest::newRow("X-MediaBrowser-Token plain") << "X-MediaBrowser-Token=abcdef0123456789abcdef0123456789end" << "X-MediaBrowser-Token=" + masked32 + "end"; // ApiKey= pattern QTest::newRow("ApiKey") << "ApiKey=abcdef0123456789abcdef0123456789rest" << "ApiKey=" + masked32 + "rest"; // AccessToken= pattern QTest::newRow("AccessToken=") << "AccessToken=abcdef0123456789abcdef0123456789end" << "AccessToken=" + masked32 + "end"; // AccessToken":" pattern (appears to be JSON formatted) QTest::newRow("AccessToken JSON") << R"({"AccessToken":"abcdef0123456789abcdef0123456789"})" << R"({"AccessToken":")" + masked32 + R"("})"; // Multiple tokens QTest::newRow("two api_key tokens") << "url?api_key=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect=url2?api_key=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" << "url?api_key=" + masked32 + "&redirect=url2?api_key=" + masked32; QTest::newRow("mixed token types") << "api_key=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA and AccessToken=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" << "api_key=" + masked32 + " and AccessToken=" + masked32; // Truncated token QTest::newRow("api_key truncated at end") << "api_key=short" << "api_key=short"; QTest::newRow("api_key exactly 32 chars at end") << "api_key=abcdef0123456789abcdef0123456789" << "api_key=" + masked32; // Not quite an API key QTest::newRow("partial pattern match") << "not_an_api_key=something" << "not_an_api_key=something"; // Token with multiple parameters QTest::newRow("token in log line") << "2024-01-01 12:00:00 [info] Request GET /Items?api_key=abcdef0123456789abcdef0123456789&format=json" << "2024-01-01 12:00:00 [info] Request GET /Items?api_key=" + masked32 + "&format=json"; } void TestLog::testCensorAuthTokens() { QFETCH(QString, input); QFETCH(QString, expected); QString msg = input; Log::CensorAuthTokens(msg); QCOMPARE(msg, expected); } QTEST_APPLESS_MAIN(TestLog) #include "test_log.moc"