File indexing completed on 2024-05-05 05:04:13

0001 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
0002 // SPDX-License-Identifier: GPL-3.0-or-later
0003 
0004 #include <QtTest/QtTest>
0005 
0006 #include "mockaccount.h"
0007 
0008 using namespace Qt::Literals::StringLiterals;
0009 
0010 class PostTest : public QObject
0011 {
0012     Q_OBJECT
0013 
0014 private Q_SLOTS:
0015     void initTestCase()
0016     {
0017     }
0018 
0019     void testFromJson()
0020     {
0021         MockAccount account;
0022 
0023         QFile statusExampleApi;
0024         statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status.json"_L1);
0025         statusExampleApi.open(QIODevice::ReadOnly);
0026 
0027         const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll());
0028         Post post(&account, doc.object());
0029 
0030         QCOMPARE(post.spoilerText(), QStringLiteral("SPOILER"));
0031         QCOMPARE(post.content(), QStringLiteral("<p>LOREM</p>"));
0032         QVERIFY(post.card());
0033         QCOMPARE(post.contentType(), QString());
0034         QCOMPARE(post.sensitive(), false);
0035         QCOMPARE(post.visibility(), Post::Visibility::Public);
0036         QCOMPARE(post.wasEdited(), false);
0037 
0038         QCOMPARE(post.authorIdentity()->displayName(), QStringLiteral("Eugen :kde:"));
0039         QCOMPARE(post.authorIdentity()->displayNameHtml(), QStringLiteral("Eugen <img height=\"16\" align=\"middle\" width=\"16\" src=\"https://kde.org\">"));
0040     }
0041 
0042     void testFromJsonWithPoll()
0043     {
0044         MockAccount account;
0045 
0046         QFile statusExampleApi;
0047         statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status-poll.json"_L1);
0048         statusExampleApi.open(QIODevice::ReadOnly);
0049 
0050         const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll());
0051         Post post(&account, doc.object());
0052 
0053         QCOMPARE(post.wasEdited(), true);
0054         QVERIFY(post.poll());
0055         const auto poll = post.poll();
0056         QCOMPARE(poll->id(), QStringLiteral("34830"));
0057         QCOMPARE(poll->expiresAt().date().year(), 2019);
0058         QCOMPARE(poll->expired(), true);
0059         QCOMPARE(poll->multiple(), false);
0060         QCOMPARE(poll->votesCount(), 10);
0061         QCOMPARE(poll->votersCount(), -1);
0062         QCOMPARE(poll->voted(), true);
0063         const auto ownVotes = poll->ownVotes();
0064         QCOMPARE(ownVotes.count(), 1);
0065         QCOMPARE(ownVotes[0], 1);
0066         const auto options = poll->options();
0067         QCOMPARE(options.count(), 2);
0068         QCOMPARE(options[0]["title"_L1], QStringLiteral("accept"));
0069         QCOMPARE(options[0]["votesCount"_L1], 6);
0070         QCOMPARE(options[1]["title"_L1], QStringLiteral("deny <img height=\"16\" align=\"middle\" width=\"16\" src=\"https://kde.org\">"));
0071         QCOMPARE(options[1]["votesCount"_L1], 4);
0072     }
0073 
0074     // Normal case
0075     void testContentParsing()
0076     {
0077         MockAccount account;
0078 
0079         QFile statusExampleApi;
0080         statusExampleApi.setFileName(QLatin1String(DATA_DIR) + QLatin1Char('/') + "status-tags.json"_L1);
0081         statusExampleApi.open(QIODevice::ReadOnly);
0082 
0083         const auto doc = QJsonDocument::fromJson(statusExampleApi.readAll());
0084         Post post(&account, doc.object());
0085 
0086         const QVector<QString> standaloneTags = {QStringLiteral("blackandwhite"),
0087                                                  QStringLiteral("photo"),
0088                                                  QStringLiteral("monochrome"),
0089                                                  QStringLiteral("landscape"),
0090                                                  QStringLiteral("photography")};
0091 
0092         QCOMPARE(post.content(), QStringLiteral("<p>Yosemite Valley reflections with rock</p>"));
0093         QCOMPARE(post.standaloneTags(), standaloneTags);
0094     }
0095 
0096     // Ensure that extra <p>'s are removed
0097     void testContentParsingEdgeCaseOne()
0098     {
0099         const QString testHtml = QStringLiteral(
0100             "<p>Boris Karloff (again) as Imhotep</p><p><a href=\"https://mastodon.art/tags/Inktober\" class=\"mention hashtag\" "
0101             "rel=\"tag\">#<span>Inktober</span></a> <a href=\"https://mastodon.art/tags/Halloween\" class=\"mention hashtag\" "
0102             "rel=\"tag\">#<span>Halloween</span></a> <a href=\"https://mastodon.art/tags/TheMummy\" class=\"mention hashtag\" "
0103             "rel=\"tag\">#<span>TheMummy</span></a></p>");
0104 
0105         const auto [content, tags] = Post::parseContent(testHtml);
0106 
0107         QCOMPARE(content, QStringLiteral("<p>Boris Karloff (again) as Imhotep</p>"));
0108     }
0109 
0110     // Ensure that unicode/non-english characters (like Japanese) are picked up by the parser
0111     void testContentParsingEdgeCaseTwo()
0112     {
0113         const QString testHtml = QStringLiteral(
0114             R"(<p>cropping of homura and madoka <br />\uD83C\uDF80\uD83E\uDDA2\uD83C\uDF38\uD83C\uDFF9✨</p><p>finished version here - <a href=\"https://floodkiss.tumblr.com/post/682418812978659328/even-if-you-cant-see-me-even-if-you-cant-hear\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">floodkiss.tumblr.com/post/6824</span><span class=\"invisible\">18812978659328/even-if-you-cant-see-me-even-if-you-cant-hear</span></a></p><p><a href=\"https://mastodon.art/tags/MadokaMagica\" class=\"mention hashtag\" rel=\"tag\">#<span>MadokaMagica</span></a> <a href=\"https://mastodon.art/tags/%E9%AD%94%E6%B3%95%E5%B0%91%E5%A5%B3%E3%81%BE%E3%81%A9%E3%81%8B%E3%83%9E%E3%82%AE%E3%82%AB\" class=\"mention hashtag\" rel=\"tag\">#<span>魔法少女まどかマギカ</span></a> <a href=\"https://mastodon.art/tags/FediArt\" class=\"mention hashtag\" rel=\"tag\">#<span>FediArt</span></a> <a href=\"https://mastodon.art/tags/MastoArt\" class=\"mention hashtag\" rel=\"tag\">#<span>MastoArt</span></a> <a href=\"https://mastodon.art/tags/FanArt\" class=\"mention hashtag\" rel=\"tag\">#<span>FanArt</span></a> <a href=\"https://mastodon.art/tags/HomuraAkemi\" class=\"mention hashtag\" rel=\"tag\">#<span>HomuraAkemi</span></a> <a href=\"https://mastodon.art/tags/MadokaKaname\" class=\"mention hashtag\" rel=\"tag\">#<span>MadokaKaname</span></a></p>)");
0115 
0116         const auto [content, tags] = Post::parseContent(testHtml);
0117 
0118         const QString expected = QStringLiteral(
0119             R"(<p>cropping of homura and madoka <br />\uD83C\uDF80\uD83E\uDDA2\uD83C\uDF38\uD83C\uDFF9✨</p><p>finished version here - <a href=\"https://floodkiss.tumblr.com/post/682418812978659328/even-if-you-cant-see-me-even-if-you-cant-hear\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">floodkiss.tumblr.com/post/6824</span><span class=\"invisible\">18812978659328/even-if-you-cant-see-me-even-if-you-cant-hear</span></a></p>)");
0120 
0121         QCOMPARE(tags[1], QStringLiteral("魔法少女まどかマギカ"));
0122         QCOMPARE(content, expected);
0123     }
0124 
0125     // Ensure that posts that separate the tags not in a separate paragraph, but with a <br> for some reason
0126     void testContentParsingEdgeCaseThree()
0127     {
0128         const QString testHtml = QStringLiteral(
0129             R"(<p>Made a small FPS demo in @godotengine</p><p>Walls were made in <a href=\"/tags/MaterialMaker\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>MaterialMaker</span></a> 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<br><a href=\"/tags/indiedev\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>indiedev</span></a> <a href=\"/tags/gamedev\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>gamedev</span></a> <a href=\"/tags/GodotEngine\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>GodotEngine</span></a></p>)");
0130 
0131         const auto [content, tags] = Post::parseContent(testHtml);
0132 
0133         const QString expected = QStringLiteral(
0134             R"(<p>Made a small FPS demo in @godotengine</p><p>Walls were made in <a href=\"/tags/MaterialMaker\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>MaterialMaker</span></a> 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</p>)");
0135 
0136         QCOMPARE(tags[1], QStringLiteral("gamedev"));
0137         QCOMPARE(content, expected);
0138     }
0139 
0140     // Ensure that posts that paragraphs that have a mix of tags and text don't get snipped
0141     void testContentParsingEdgeCaseFour()
0142     {
0143         const QString testHtml = QStringLiteral(
0144             R"(<p>I never got around to writing my <a href=\"/tags/introduction\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>introduction</span></a>, so here it is then.</p><p><a href=\"/tags/Books\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>Books</span></a> &amp; <a href=\"/tags/movies\" class=\"mention hashtag status-link\" rel=\"tag\">#<span>movies</span></a> recommendations are always welcome!</p>)");
0145 
0146         const auto [content, tags] = Post::parseContent(testHtml);
0147 
0148         // Nothing should happen to this text
0149         QVERIFY(tags.empty());
0150         QCOMPARE(content, testHtml);
0151     }
0152 };
0153 
0154 QTEST_MAIN(PostTest)
0155 #include "posttest.moc"