File indexing completed on 2024-11-10 04:40:23

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Daniel Vrátil <dvratil@kde.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  *
0006  */
0007 
0008 #include "qtest_akonadi.h"
0009 #include "shared/aktest.h"
0010 
0011 #include "monitor.h"
0012 #include "tag.h"
0013 #include "tagcreatejob.h"
0014 #include "tagdeletejob.h"
0015 #include "tagmodel.h"
0016 #include "tagselectiondialog.h"
0017 #include "tagwidget.h"
0018 
0019 #include <QDialogButtonBox>
0020 #include <QLineEdit>
0021 #include <QPushButton>
0022 #include <QSignalSpy>
0023 #include <QTest>
0024 #include <QToolButton>
0025 
0026 #include <memory>
0027 
0028 using namespace Akonadi;
0029 using namespace std::chrono_literals;
0030 class TagWidgetTest : public QObject
0031 {
0032     Q_OBJECT
0033 
0034     struct TestSetup {
0035         TestSetup()
0036             : widget(std::make_unique<TagWidget>())
0037         {
0038             widget->show();
0039 
0040             monitor = widget->findChild<Monitor *>();
0041             QVERIFY(monitor);
0042             model = widget->findChild<TagModel *>();
0043             QVERIFY(model);
0044             QSignalSpy modelSpy(model, &TagModel::populated);
0045             QVERIFY(modelSpy.wait());
0046 
0047             QVERIFY(QTest::qWaitForWindowActive(widget.get()));
0048 
0049             tagView = widget->findChild<QLineEdit *>(QStringLiteral("tagView"));
0050             QVERIFY(tagView);
0051             QVERIFY(tagView->isReadOnly()); // always read-only
0052             editButton = widget->findChild<QToolButton *>(QStringLiteral("editButton"));
0053             QVERIFY(editButton);
0054 
0055             valid = true;
0056         }
0057 
0058         ~TestSetup()
0059         {
0060             if (!createdTags.empty()) {
0061                 auto deleteJob = new TagDeleteJob(createdTags);
0062                 AKVERIFYEXEC(deleteJob);
0063             }
0064         }
0065 
0066         bool createTags(int count)
0067         {
0068             const auto doCreateTags = [this, count]() {
0069                 QSignalSpy monitorSpy(monitor, &Monitor::tagAdded);
0070                 for (int i = 0; i < count; ++i) {
0071                     auto job = new TagCreateJob(Tag(QStringLiteral("TestTag-%1").arg(i)));
0072                     AKVERIFYEXEC(job);
0073                     createdTags.push_back(job->tag());
0074                 }
0075                 QTRY_COMPARE(monitorSpy.count(), count);
0076             };
0077             doCreateTags();
0078             return createdTags.size() == count;
0079         }
0080 
0081         bool testSelectionMatches(QSignalSpy &selectionSpy, const Tag::List &selection) const
0082         {
0083             QStringList names;
0084             std::transform(selection.begin(), selection.end(), std::back_inserter(names), std::bind(&Tag::name, std::placeholders::_1));
0085 
0086             AKCOMPARE(widget->selection(), selection);
0087             AKCOMPARE(selectionSpy.size(), 1);
0088 
0089             AKCOMPARE(selectionSpy.at(0).at(0).value<Tag::List>(), selection);
0090             AKCOMPARE(tagView->text(), names.join(QStringLiteral(", ")));
0091             return true;
0092         }
0093 
0094         bool selectTagsInDialog(const Tag::List &selection)
0095         {
0096             const auto windows = QApplication::topLevelWidgets();
0097             for (auto window : windows) {
0098                 if (auto dlg = qobject_cast<TagSelectionDialog *>(window)) {
0099                     // Set the selection through code, testing selecting tags with mouse is
0100                     // out-of-scope for this test, there's a dedicated TagEditWidget test for that.
0101                     dlg->setSelection(selection);
0102                     auto button = dlg->buttons()->button(QDialogButtonBox::Ok);
0103                     AKVERIFY(button);
0104                     QTest::mouseClick(button, Qt::LeftButton);
0105                     return true;
0106                 }
0107             }
0108 
0109             return false;
0110         }
0111 
0112         std::unique_ptr<TagWidget> widget;
0113         Monitor *monitor = nullptr;
0114         TagModel *model = nullptr;
0115 
0116         QLineEdit *tagView = nullptr;
0117         QToolButton *editButton = nullptr;
0118 
0119         Tag::List createdTags;
0120 
0121         bool valid = false;
0122     };
0123 
0124 private Q_SLOTS:
0125     void initTestCase()
0126     {
0127         AkonadiTest::checkTestIsIsolated();
0128     }
0129 
0130     void testInitialState()
0131     {
0132         TestSetup test;
0133         QVERIFY(test.valid);
0134 
0135         QVERIFY(test.tagView->text().isEmpty());
0136         QVERIFY(test.widget->selection().isEmpty());
0137     }
0138 
0139     void testSettingSelectionFromCode()
0140     {
0141         TestSetup test;
0142         QVERIFY(test.valid);
0143         QVERIFY(test.createTags(4));
0144 
0145         QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged);
0146         const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]};
0147         test.widget->setSelection(selection);
0148 
0149         QVERIFY(test.testSelectionMatches(selectionSpy, selection));
0150     }
0151 
0152     void testSettingSelectionViaDialog()
0153     {
0154         TestSetup test;
0155         QVERIFY(test.valid);
0156         QVERIFY(test.createTags(4));
0157 
0158         QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged);
0159         const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]};
0160 
0161         bool ok = false;
0162         // Clicking on the Edit button opens the dialog in a blocking way, so
0163         // we need to dispatch the test from event loop
0164         QTimer::singleShot(100ms, this, [&test, &selection, &ok]() {
0165             QVERIFY(test.selectTagsInDialog(selection));
0166             ok = true;
0167         });
0168         QTest::mouseClick(test.editButton, Qt::LeftButton);
0169         QVERIFY(ok);
0170 
0171         QVERIFY(test.testSelectionMatches(selectionSpy, selection));
0172     }
0173 
0174     void testClearTagsFromCode()
0175     {
0176         TestSetup test;
0177         QVERIFY(test.valid);
0178         QVERIFY(test.createTags(4));
0179 
0180         const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]};
0181         test.widget->setSelection(selection);
0182         QCOMPARE(test.widget->selection(), selection);
0183 
0184         QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged);
0185         test.widget->clearTags();
0186         QVERIFY(test.widget->selection().isEmpty());
0187         QCOMPARE(selectionSpy.size(), 1);
0188         QVERIFY(selectionSpy.at(0).at(0).value<Tag::List>().empty());
0189         QVERIFY(test.tagView->text().isEmpty());
0190     }
0191 };
0192 
0193 QTEST_AKONADIMAIN(TagWidgetTest)
0194 
0195 #include "tagwidgettest.moc"