Warning, file /plasma/plasma-workspace/libnotificationmanager/autotests/notifications_test.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
0003     SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include <QDebug>
0009 #include <QObject>
0010 #include <QSignalSpy>
0011 #include <QTest>
0012 
0013 #include "notification.h"
0014 #include "notificationsmodel.h"
0015 #include "server.h"
0016 
0017 namespace NotificationManager
0018 {
0019 class NotificationTest : public QObject
0020 {
0021     Q_OBJECT
0022 public:
0023     NotificationTest()
0024     {
0025     }
0026 private Q_SLOTS:
0027     void parse_data();
0028     void parse();
0029 
0030     void compressNotificationRemoval();
0031 };
0032 
0033 void NotificationTest::parse_data()
0034 {
0035     QTest::addColumn<QString>("messageIn");
0036     QTest::addColumn<QString>("expectedOut");
0037 
0038     // clang-format off
0039     QTest::newRow("basic no HTML") << "I am a notification" << "I am a notification";
0040     QTest::newRow("whitespace") << "      I am a   notification  " << "I am a notification";
0041 
0042     QTest::newRow("basic html") << "I am <b>the</b> notification" << "I am <b>the</b> notification";
0043     QTest::newRow("nested html") << "I am <i><b>the</b></i> notification" << "I am <i><b>the</b></i> notification";
0044 
0045     QTest::newRow("no extra tags") << "I am <blink>the</blink> notification" << "I am the notification";
0046     QTest::newRow("no extra attrs") << "I am <b style=\"font-weight:20\">the</b> notification" << "I am <b>the</b> notification";
0047 
0048     QTest::newRow("newlines") << "I am\nthe\nnotification" << "I am<br/>the<br/>notification";
0049     QTest::newRow("multinewlines") << "I am\n\nthe\n\n\nnotification" << "I am<br/>the<br/>notification";
0050 
0051     QTest::newRow("amp") << "me&you" << "me&amp;you";
0052     QTest::newRow("double escape") << "foo &amp; &lt;bar&gt;" << "foo &amp; &lt;bar&gt;";
0053 
0054     QTest::newRow("quotes") << "&apos;foo&apos;" << "'foo'";//as label can't handle this normally valid entity
0055 
0056     QTest::newRow("image normal") << "This is <img src=\"file:://foo/boo.png\" alt=\"cheese\"/> and more text" << "This is <img src=\"file:://foo/boo.png\" alt=\"cheese\"/> and more text";
0057 
0058     //this input is technically wrong, so the output is also wrong, but QTextHtmlParser does the "right" thing
0059     QTest::newRow("image normal no close") << "This is <img src=\"file:://foo/boo.png\" alt=\"cheese\"> and more text" << "This is <img src=\"file:://foo/boo.png\" alt=\"cheese\"> and more text</img>";
0060 
0061     QTest::newRow("image remote URL") << "This is <img src=\"http://foo.com/boo.png\" alt=\"cheese\" /> and more text" << "This is <img alt=\"cheese\"/> and more text";
0062 
0063     //more bad formatted options. To some extent actual output doesn't matter. Garbage in, garbage out.
0064     //the important thing is that it doesn't contain anything that could be parsed as the remote URL
0065     QTest::newRow("image remote URL no close") << "This is <img src=\"http://foo.com/boo.png>\" alt=\"cheese\">  and more text" << "This is <img alt=\"cheese\"> and more text</img>";
0066     QTest::newRow("image remote URL double open") << "This is <<img src=\"http://foo.com/boo.png>\"  and more text" << "This is ";
0067     QTest::newRow("image remote URL no entity close") << "This is <img src=\"http://foo.com/boo.png\"  and more text" << "This is ";
0068     QTest::newRow("image remote URL space in element name") << "This is < img src=\"http://foo.com/boo.png\" alt=\"cheese\" /> and more text" << "This is ";
0069 
0070     QTest::newRow("link") << "This is a link <a href=\"http://foo.com/boo\"/> and more text" << "This is a link <a href=\"http://foo.com/boo\"/> and more text";
0071     // clang-format on
0072 }
0073 
0074 void NotificationTest::parse()
0075 {
0076     QFETCH(QString, messageIn);
0077     QFETCH(QString, expectedOut);
0078 
0079     NotificationManager::Notification notification;
0080     notification.setBody(messageIn);
0081 
0082     expectedOut = "<?xml version=\"1.0\"?><html>" + expectedOut + "</html>\n";
0083 
0084     QCOMPARE(notification.body(), expectedOut);
0085 }
0086 
0087 void NotificationTest::compressNotificationRemoval()
0088 {
0089     const int notificationCount = 10;
0090     const int gapId = 4;
0091 
0092     auto model = NotificationsModel::createNotificationsModel();
0093 
0094     QSignalSpy rowsRemovedSpy(model.get(), &QAbstractItemModel::rowsRemoved);
0095     QVERIFY(rowsRemovedSpy.isValid());
0096 
0097     for (uint i = 1; i <= notificationCount; ++i) {
0098         Notification notification{i};
0099         notification.setSummary(QStringLiteral("Notification %1").arg(i));
0100         model->onNotificationAdded(notification);
0101     }
0102 
0103     QCOMPARE(model->rowCount(), notificationCount);
0104 
0105     for (uint i = 1; i <= notificationCount; ++i) {
0106         // Leave a gap inbetween
0107         if (i != gapId) {
0108             model->onNotificationRemoved(i, Server::CloseReason::Revoked);
0109         }
0110     }
0111 
0112     // We should have two ranges that we ended up removing
0113     QTRY_COMPARE(rowsRemovedSpy.count(), 2);
0114 
0115     // The fact that it emits row removal in reverse order is an implementation detail
0116     // We only really care that the number of rows emitted matches our expectation
0117     int removedCount = 0;
0118     for (const auto &removedEmission : rowsRemovedSpy) {
0119         const int from = removedEmission.at(1).toInt();
0120         const int to = removedEmission.at(2).toInt();
0121         removedCount += (to - from) + 1;
0122     }
0123 
0124     QCOMPARE(removedCount, notificationCount - 1);
0125     QCOMPARE(model->rowCount(), 1);
0126 
0127     rowsRemovedSpy.clear();
0128 
0129     // Removing a random non-existing notification should noop
0130     model->onNotificationRemoved(3, Server::CloseReason::Revoked);
0131     QTRY_COMPARE(rowsRemovedSpy.count(), 0);
0132     QCOMPARE(model->rowCount(), 1);
0133     rowsRemovedSpy.clear();
0134 
0135     // Now remove the last one
0136     model->onNotificationRemoved(gapId, Server::CloseReason::Revoked);
0137     QTRY_COMPARE(rowsRemovedSpy.count(), 1);
0138     QCOMPARE(rowsRemovedSpy.at(0).at(1), 0); // from
0139     QCOMPARE(rowsRemovedSpy.at(0).at(2), 0); // to
0140     QCOMPARE(model->rowCount(), 0);
0141 }
0142 
0143 } // namespace NotificationManager
0144 
0145 QTEST_GUILESS_MAIN(NotificationManager::NotificationTest)
0146 
0147 #include "notifications_test.moc"