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 "tagselectioncombobox.h"
0017 
0018 #include <QAbstractItemView>
0019 #include <QLineEdit>
0020 #include <QSignalSpy>
0021 #include <QTest>
0022 
0023 #include <memory>
0024 
0025 using namespace Akonadi;
0026 
0027 class TagSelectionComboBoxTest : public QObject
0028 {
0029     Q_OBJECT
0030 
0031     struct TestSetup {
0032         explicit TestSetup(bool checkable)
0033             : widget(std::make_unique<TagSelectionComboBox>())
0034         {
0035             widget->setCheckable(checkable);
0036             widget->show();
0037 
0038             monitor = widget->findChild<Monitor *>();
0039             QVERIFY(monitor);
0040             model = widget->findChild<TagModel *>();
0041             QVERIFY(model);
0042             QSignalSpy modelSpy(model, &TagModel::populated);
0043             QVERIFY(modelSpy.wait());
0044 
0045             QVERIFY(QTest::qWaitForWindowActive(widget.get()));
0046 
0047             valid = true;
0048         }
0049 
0050         ~TestSetup()
0051         {
0052             if (!createdTags.empty()) {
0053                 auto deleteJob = new TagDeleteJob(createdTags);
0054                 AKVERIFYEXEC(deleteJob);
0055             }
0056         }
0057 
0058         bool createTags(int count)
0059         {
0060             const auto doCreateTags = [this, count]() {
0061                 QSignalSpy monitorSpy(monitor, &Monitor::tagAdded);
0062                 for (int i = 0; i < count; ++i) {
0063                     auto job = new TagCreateJob(Tag(QStringLiteral("TestTag-%1").arg(i)));
0064                     AKVERIFYEXEC(job);
0065                     createdTags.push_back(job->tag());
0066                 }
0067                 QTRY_COMPARE(monitorSpy.count(), count);
0068             };
0069             doCreateTags();
0070             return createdTags.size() == count;
0071         }
0072 
0073         bool testSelectionMatches(QSignalSpy &selectionSpy, const Tag::List &selection) const
0074         {
0075             QStringList names;
0076             std::transform(selection.begin(), selection.end(), std::back_inserter(names), std::bind(&Tag::name, std::placeholders::_1));
0077 
0078             AKCOMPARE(widget->selection(), selection);
0079             AKCOMPARE(widget->selectionNames(), names);
0080             AKCOMPARE(selectionSpy.size(), 1);
0081 
0082             AKCOMPARE(selectionSpy.at(0).at(0).value<Tag::List>(), selection);
0083             AKCOMPARE(widget->currentText(), QLocale{}.createSeparatedList(names));
0084             return true;
0085         }
0086 
0087         bool selectTagsInComboBox(const Tag::List & /*selection*/)
0088         {
0089             const auto windows = QApplication::topLevelWidgets();
0090             for (auto window : windows) {
0091                 if (auto combo = qobject_cast<TagSelectionComboBox *>(window)) {
0092                     QTest::mouseClick(combo, Qt::LeftButton);
0093                     return true;
0094                 }
0095             }
0096 
0097             return false;
0098         }
0099 
0100         bool toggleDropdown() const
0101         {
0102             auto view = widget->view()->parentWidget();
0103             const bool visible = view->isVisible();
0104             QTest::mouseClick(widget->lineEdit(), Qt::LeftButton);
0105             QTest::qWait(10);
0106             AKCOMPARE(view->isVisible(), !visible);
0107 
0108             return true;
0109         }
0110 
0111         QModelIndex indexForTag(const Tag &tag) const
0112         {
0113             for (int i = 0; i < widget->model()->rowCount(); ++i) {
0114                 const auto index = widget->model()->index(i, 0);
0115                 if (widget->model()->data(index, TagModel::TagRole).value<Tag>().name() == tag.name()) {
0116                     return index;
0117                 }
0118             }
0119             return {};
0120         }
0121 
0122         std::unique_ptr<TagSelectionComboBox> widget;
0123         Monitor *monitor = nullptr;
0124         TagModel *model = nullptr;
0125 
0126         Tag::List createdTags;
0127 
0128         bool valid = false;
0129     };
0130 
0131 public:
0132     TagSelectionComboBoxTest()
0133     {
0134         qRegisterMetaType<Akonadi::Tag::List>();
0135     }
0136 
0137 private Q_SLOTS:
0138     void initTestCase()
0139     {
0140         AkonadiTest::checkTestIsIsolated();
0141     }
0142 
0143     void testInitialState()
0144     {
0145         TestSetup test{true};
0146         QVERIFY(test.valid);
0147 
0148         QVERIFY(test.widget->currentText().isEmpty());
0149         QVERIFY(test.widget->selection().isEmpty());
0150     }
0151 
0152     void testSettingSelectionFromCode()
0153     {
0154         TestSetup test{true};
0155         QVERIFY(test.valid);
0156         QVERIFY(test.createTags(4));
0157 
0158         QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged);
0159         const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]};
0160         test.widget->setSelection(selection);
0161 
0162         QVERIFY(test.testSelectionMatches(selectionSpy, selection));
0163     }
0164 
0165     void testSettingSelectionByName()
0166     {
0167         TestSetup test{true};
0168         QVERIFY(test.valid);
0169         QVERIFY(test.createTags(4));
0170 
0171         QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged);
0172         const auto selection = QStringList{test.createdTags[1].name(), test.createdTags[3].name()};
0173         test.widget->setSelection(selection);
0174 
0175         QVERIFY(test.testSelectionMatches(selectionSpy, {test.createdTags[1], test.createdTags[3]}));
0176     }
0177 
0178     void testSelectionByKeyboard()
0179     {
0180         TestSetup test{true};
0181         QVERIFY(test.valid);
0182         QVERIFY(test.createTags(4));
0183 
0184         QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged);
0185         const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]};
0186 
0187         QVERIFY(!test.widget->view()->parentWidget()->isVisible());
0188         QVERIFY(test.toggleDropdown());
0189 
0190         QTest::keyClick(test.widget->view(), Qt::Key_Down); // from name to tag 1
0191         QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 1 to tag 2
0192         QTest::keyClick(test.widget->view(), Qt::Key_Space); // select tag 2
0193         QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 2 to tag 3
0194         QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 3 to tag 4
0195         QTest::keyClick(test.widget->view(), Qt::Key_Space); // select tag 4
0196 
0197         QTest::keyClick(test.widget->view(), Qt::Key_Escape); // close
0198         QTest::qWait(100);
0199         QVERIFY(!test.widget->view()->parentWidget()->isVisible());
0200 
0201         QCOMPARE(selectionSpy.size(), 2); // two selections -> two signals
0202         selectionSpy.takeFirst(); // remove the first one
0203         QVERIFY(test.testSelectionMatches(selectionSpy, selection));
0204     }
0205 
0206     void testNonCheckableSelection()
0207     {
0208         TestSetup test{false};
0209         QVERIFY(test.valid);
0210         QVERIFY(test.createTags(4));
0211 
0212         test.widget->setCurrentIndex(1);
0213         QCOMPARE(test.widget->currentData(TagModel::TagRole).value<Tag>(), test.createdTags[0]);
0214 
0215         QCOMPARE(test.widget->selection(), Tag::List{test.createdTags[0]});
0216         QCOMPARE(test.widget->selectionNames(), QStringList{test.createdTags[0].name()});
0217 
0218         test.widget->setSelection({test.createdTags[1]});
0219         QCOMPARE(test.widget->currentIndex(), 2);
0220     }
0221 };
0222 
0223 QTEST_AKONADIMAIN(TagSelectionComboBoxTest)
0224 
0225 #include "tagselectioncomboboxtest.moc"