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"