// SPDX-FileCopyrightText: 2022 Carl Schwan // SPDX-License-Identifier: GPL-3.0-or-later #include #include "autotests/mockaccount.h" #include "utils/texthandler.h" using namespace Qt::Literals::StringLiterals; class PostTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { } void testFromJson() { MockAccount account; QFile statusExampleApi; statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status.json"_L1); statusExampleApi.open(QIODevice::ReadOnly); const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll()); Post post(&account, doc.object()); QCOMPARE(post.spoilerText(), QStringLiteral("SPOILER")); QCOMPARE(post.content(), QStringLiteral("

LOREM

")); QVERIFY(post.card()); QCOMPARE(post.sensitive(), false); QCOMPARE(post.visibility(), Post::Visibility::Public); QCOMPARE(post.wasEdited(), false); QCOMPARE(post.authorIdentity()->displayName(), QStringLiteral("Eugen :kde:")); QCOMPARE(post.authorIdentity()->displayNameHtml(), QStringLiteral("Eugen ")); } void testFromJsonWithPoll() { MockAccount account; QFile statusExampleApi; statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status-poll.json"_L1); statusExampleApi.open(QIODevice::ReadOnly); const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll()); Post post(&account, doc.object()); QCOMPARE(post.wasEdited(), true); QVERIFY(post.poll()); const auto poll = post.poll(); QCOMPARE(poll->id(), QStringLiteral("34830")); QCOMPARE(poll->expiresAt().date().year(), 2019); QCOMPARE(poll->expired(), true); QCOMPARE(poll->multiple(), false); QCOMPARE(poll->votesCount(), 10); QCOMPARE(poll->votersCount(), -1); QCOMPARE(poll->voted(), true); const auto ownVotes = poll->ownVotes(); QCOMPARE(ownVotes.count(), 1); QCOMPARE(ownVotes[0], 1); const auto options = poll->options(); QCOMPARE(options.count(), 2); QCOMPARE(options[0]["title"_L1], QStringLiteral("accept")); QCOMPARE(options[0]["votesCount"_L1], 6); QCOMPARE(options[1]["title"_L1], QStringLiteral("deny ")); QCOMPARE(options[1]["votesCount"_L1], 4); } // Normal case void testContentParsing() { MockAccount account; QFile statusExampleApi; statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status-tags.json"_L1); statusExampleApi.open(QIODevice::ReadOnly); const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll()); Post post(&account, doc.object()); const QVector standaloneTags = {QStringLiteral("blackandwhite"), QStringLiteral("photo"), QStringLiteral("monochrome"), QStringLiteral("landscape"), QStringLiteral("photography")}; QCOMPARE(post.content(), QStringLiteral("

Yosemite Valley reflections with rock

")); QCOMPARE(post.standaloneTags(), standaloneTags); } // Ensure that extra

's are removed void testContentParsingEdgeCaseOne() { const QString testHtml = QStringLiteral( "

Boris Karloff (again) as Imhotep

#Inktober #Halloween #TheMummy

"); const auto [content, tags] = TextHandler::removeStandaloneTags(testHtml); QCOMPARE(content, QStringLiteral("

Boris Karloff (again) as Imhotep

")); } // Ensure that unicode/non-english characters (like Japanese) are picked up by the parser void testContentParsingEdgeCaseTwo() { const QString testHtml = QStringLiteral( R"(

cropping of homura and madoka
\uD83C\uDF80\uD83E\uDDA2\uD83C\uDF38\uD83C\uDFF9✨

finished version here - https://floodkiss.tumblr.com/post/682418812978659328/even-if-you-cant-see-me-even-if-you-cant-hear

#MadokaMagica #魔法少女まどかマギカ #FediArt #MastoArt #FanArt #HomuraAkemi #MadokaKaname

)"); const auto [content, tags] = TextHandler::removeStandaloneTags(testHtml); const QString expected = QStringLiteral( R"(

cropping of homura and madoka
\uD83C\uDF80\uD83E\uDDA2\uD83C\uDF38\uD83C\uDFF9✨

finished version here - https://floodkiss.tumblr.com/post/682418812978659328/even-if-you-cant-see-me-even-if-you-cant-hear

)"); QCOMPARE(tags[1], QStringLiteral("魔法少女まどかマギカ")); QCOMPARE(content, expected); } // Ensure that posts that separate the tags not in a separate paragraph, but with a
for some reason void testContentParsingEdgeCaseThree() { const QString testHtml = QStringLiteral( R"(

Made a small FPS demo in @godotengine

Walls were made in #MaterialMaker but it seems godot has trouble with the normal maps :( One common trick I use is to flip faces to break repetition but even if you don't it makes those weird light artefacts
#indiedev #gamedev #GodotEngine

)"); const auto [content, tags] = TextHandler::removeStandaloneTags(testHtml); const QString expected = QStringLiteral( R"(

Made a small FPS demo in @godotengine

Walls were made in #MaterialMaker but it seems godot has trouble with the normal maps :( One common trick I use is to flip faces to break repetition but even if you don't it makes those weird light artefacts

)"); QCOMPARE(tags[1], QStringLiteral("gamedev")); QCOMPARE(content, expected); } // Ensure that posts that paragraphs that have a mix of tags and text don't get snipped void testContentParsingEdgeCaseFour() { const QString testHtml = QStringLiteral( R"(

I never got around to writing my #introduction, so here it is then.

#Books & #movies recommendations are always welcome!

)"); const auto [content, tags] = TextHandler::removeStandaloneTags(testHtml); // Nothing should happen to this text QVERIFY(tags.empty()); QCOMPARE(content, testHtml); } // Ensure that post URLs are detected void testContentParsingPostURLDetection_data() { QTest::addColumn("url"); QTest::addColumn("valid"); QTest::addRow("Mastodon") << "https://mastodon.art/@auser/105304668353589277" << true; QTest::addRow("Pleroma/Akkoma/Misskey") << "https://somesite.art/notes/A5DFjasba5" << true; QTest::addRow("Pixelfed") << "https://pixelfed.de/p/durchdiewelt/704323350617677895" << true; QTest::addRow("Regular website") << "https://kde.org" << false; QTest::addRow("Clearly malformed URL") << "https://mastodon.art/admin/abc" << false; } void testContentParsingPostURLDetection() { QFETCH(QString, url); QFETCH(bool, valid); QCOMPARE(TextHandler::isPostUrl(url), valid); } }; QTEST_MAIN(PostTest) #include "posttest.moc"