File indexing completed on 2025-02-02 03:48:45
0001 /* 0002 This file is part of the KDE Frameworks 0003 SPDX-FileCopyrightText: 2008, 2016 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include <KComboBox> 0009 #include <kdiroperator.h> 0010 #include <kfilewidget.h> 0011 #include <kurlrequester.h> 0012 0013 #include <QLineEdit> 0014 #include <QSignalSpy> 0015 #include <QTemporaryFile> 0016 #include <QTest> 0017 0018 /* 0019 IMPORTANT: 0020 Because this unittest interacts with the file dialog, 0021 remember to run it both with plugins/platformthemes/KDEPlasmaPlatformTheme.so (to use KFileWidget) 0022 and without it (to use the builtin QFileDialog code) 0023 */ 0024 0025 class KUrlRequesterTest : public QObject 0026 { 0027 Q_OBJECT 0028 private Q_SLOTS: 0029 void testUrlRequester(); 0030 void testComboRequester(); 0031 void testComboRequester_data(); 0032 void testNameFilters(); 0033 void testNameFilters_data(); 0034 0035 private: 0036 bool createTestFile(const QString &fileName) 0037 { 0038 QFile file(fileName); 0039 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0040 return false; 0041 } 0042 file.write("Hello world\n"); 0043 return true; 0044 } 0045 }; 0046 0047 // Same as in kfiledialog_unittest.cpp 0048 static KFileWidget *findFileWidget() 0049 { 0050 QList<KFileWidget *> widgets; 0051 const QList<QWidget *> widgetsList = QApplication::topLevelWidgets(); 0052 for (QWidget *widget : widgetsList) { 0053 KFileWidget *fw = widget->findChild<KFileWidget *>(); 0054 if (fw) { 0055 widgets.append(fw); 0056 } 0057 } 0058 return (widgets.count() == 1) ? widgets.first() : nullptr; 0059 } 0060 0061 void KUrlRequesterTest::testUrlRequester() 0062 { 0063 KUrlRequester req; 0064 req.setFileDialogModality(Qt::NonModal); 0065 const QString fileName = QStringLiteral("some_test_file"); 0066 QVERIFY(createTestFile(fileName)); 0067 QTemporaryFile tempFile; 0068 QVERIFY(tempFile.open()); 0069 const QString filePath2 = tempFile.fileName(); 0070 QVERIFY(QFile::exists(filePath2)); 0071 0072 // Set start dir 0073 const QUrl dirUrl = QUrl::fromLocalFile(QDir::currentPath()); 0074 req.setStartDir(dirUrl); 0075 QCOMPARE(req.startDir().toString(), dirUrl.toString()); 0076 0077 // Click the button 0078 req.button()->click(); 0079 QFileDialog *fileDialog = req.findChild<QFileDialog *>(); 0080 QVERIFY(fileDialog); 0081 0082 // Find out if we're using KFileDialog or QFileDialog 0083 KFileWidget *fw = findFileWidget(); 0084 0085 // Wait for directory listing 0086 if (fw) { 0087 QSignalSpy spy(fw->dirOperator(), &KDirOperator::finishedLoading); 0088 QVERIFY(spy.wait()); 0089 } 0090 0091 // Select file 0092 const QString filePath = dirUrl.toLocalFile() + '/' + fileName; 0093 fileDialog->selectFile(fileName); 0094 0095 // Click OK, check URLRequester shows and returns selected file 0096 QKeyEvent keyPressEv(QKeyEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); 0097 qApp->sendEvent(fw ? static_cast<QWidget *>(fw) : static_cast<QWidget *>(fileDialog), &keyPressEv); 0098 QCOMPARE(fileDialog->result(), static_cast<int>(QDialog::Accepted)); 0099 QCOMPARE(fileDialog->selectedFiles(), QStringList{filePath}); 0100 QCOMPARE(req.url().toLocalFile(), filePath); 0101 0102 // Check there is no longer any file dialog visible 0103 QVERIFY(fileDialog->isHidden()); 0104 0105 // Click KUrlRequester button again. This time the filedialog is initialized with a file URL 0106 req.button()->click(); 0107 fileDialog = req.findChild<QFileDialog *>(); 0108 QVERIFY(fileDialog); 0109 fw = findFileWidget(); 0110 if (fw) { // no need to wait for dir listing again, but we need it to be visible at least (for Key_Return to accept) 0111 // QVERIFY(QTest::qWaitForWindowExposed(fw->window())); // doesn't seem to be enough 0112 QTRY_VERIFY(fw->isVisible()); 0113 } 0114 0115 // Select file 2 0116 fileDialog->selectFile(filePath2); 0117 0118 // Click OK, check URLRequester shows and returns selected file 0119 qApp->sendEvent(fw ? static_cast<QWidget *>(fw) : static_cast<QWidget *>(fileDialog), &keyPressEv); 0120 QCOMPARE(fileDialog->result(), static_cast<int>(QDialog::Accepted)); 0121 QCOMPARE(fileDialog->selectedFiles(), QStringList{filePath2}); 0122 QCOMPARE(req.url().toLocalFile(), filePath2); 0123 } 0124 0125 void KUrlRequesterTest::testComboRequester() 0126 { 0127 QFETCH(bool, editable); 0128 0129 KUrlComboRequester req; 0130 req.show(); 0131 0132 QList<QLineEdit *> lineEdits = req.findChildren<QLineEdit *>(); 0133 QVERIFY(lineEdits.isEmpty()); // no lineedits, only a readonly combo 0134 0135 QSignalSpy textSpy(&req, &KUrlComboRequester::textChanged); 0136 QSignalSpy editSpy(&req, &KUrlComboRequester::textEdited); 0137 0138 QSignalSpy returnWithTextSpy(&req, &KUrlComboRequester::returnPressed); 0139 0140 QVERIFY(!req.comboBox()->isEditable()); 0141 if (editable) { 0142 req.comboBox()->setEditable(true); 0143 0144 const auto text = QStringLiteral("foobar"); 0145 QTest::keyClicks(req.comboBox(), text, Qt::NoModifier); 0146 QCOMPARE(textSpy.size(), text.size()); 0147 QCOMPARE(editSpy.size(), text.size()); 0148 QCOMPARE(textSpy.last().first().toString(), text); 0149 QCOMPARE(editSpy.last().first().toString(), text); 0150 0151 QCOMPARE(returnWithTextSpy.size(), 0); 0152 0153 QTest::keyEvent(QTest::Click, req.comboBox(), Qt::Key_Return); 0154 0155 QCOMPARE(returnWithTextSpy.size(), 1); 0156 QCOMPARE(returnWithTextSpy.last().first().toString(), text); 0157 } else { 0158 const auto url1 = QUrl("file:///foo/bar/1"); 0159 const auto url2 = QUrl("file:///foo/bar/2"); 0160 req.comboBox()->addUrl(url1); 0161 QCOMPARE(textSpy.size(), 1); 0162 QCOMPARE(textSpy.last().first().toUrl(), url1); 0163 0164 req.comboBox()->addUrl(url2); 0165 QCOMPARE(textSpy.size(), 1); 0166 0167 QTest::keyEvent(QTest::Click, req.comboBox(), Qt::Key_Down); 0168 QCOMPARE(textSpy.size(), 2); 0169 QCOMPARE(textSpy.last().first().toUrl(), url2); 0170 0171 // only editable combo boxes get the edit and return signals emitted 0172 QCOMPARE(editSpy.size(), 0); 0173 0174 QCOMPARE(returnWithTextSpy.size(), 0); 0175 } 0176 } 0177 0178 void KUrlRequesterTest::testComboRequester_data() 0179 { 0180 QTest::addColumn<bool>("editable"); 0181 0182 QTest::newRow("read-only") << false; 0183 QTest::newRow("editable") << true; 0184 } 0185 0186 void KUrlRequesterTest::testNameFilters() 0187 { 0188 QFETCH(QString, nameFilter); 0189 QFETCH(QStringList, nameFilters); 0190 0191 KUrlRequester req; 0192 req.setFileDialogModality(Qt::NonModal); 0193 0194 // Click the button to get the filedialog 0195 req.button()->click(); 0196 QFileDialog *fileDialog = req.findChild<QFileDialog *>(); 0197 QVERIFY(fileDialog); 0198 0199 // set name filter 0200 req.setNameFilter(nameFilter); 0201 0202 // check all 0203 QCOMPARE(req.nameFilters(), nameFilters); 0204 QCOMPARE(fileDialog->nameFilters(), nameFilters); 0205 0206 // set name filters 0207 req.setNameFilters(nameFilters); 0208 0209 // check all 0210 QCOMPARE(req.nameFilters(), nameFilters); 0211 QCOMPARE(fileDialog->nameFilters(), nameFilters); 0212 } 0213 0214 void KUrlRequesterTest::testNameFilters_data() 0215 { 0216 QTest::addColumn<QString>("nameFilter"); 0217 QTest::addColumn<QStringList>("nameFilters"); 0218 0219 /* clang-format off */ 0220 QTest::newRow("singleglob-comment") 0221 << QStringLiteral("Comment (*.foo)") 0222 << QStringList{QStringLiteral("Comment (*.foo)")}; 0223 0224 QTest::newRow("singleglob-nocomment") 0225 << QStringLiteral("*.foo") 0226 << QStringList{QStringLiteral("*.foo")}; 0227 0228 QTest::newRow("multiglob-comment") 0229 << QStringLiteral("Comment (*.foo *.bar)") 0230 << QStringList{QStringLiteral("Comment (*.foo *.bar)")}; 0231 0232 QTest::newRow("multiglob-nocomment") 0233 << QStringLiteral("*.foo *.bar") 0234 << QStringList{QStringLiteral("*.foo *.bar")}; 0235 0236 QTest::newRow("multilines-comment") 0237 << QStringLiteral("Comment (*.foo *.bar);;Comment2 (*.kde)") 0238 << QStringList{QStringLiteral("Comment (*.foo *.bar)"), QStringLiteral("Comment2 (*.kde)")}; 0239 0240 QTest::newRow("multilines-nocomment") 0241 << QStringLiteral("*.foo *.bar;;*.kde") 0242 << QStringList{QStringLiteral("*.foo *.bar"), QStringLiteral("*.kde")}; 0243 0244 QTest::newRow("multilines-commentmixed") 0245 << QStringLiteral("Comment (*.foo *.bar);;*.kde") 0246 << QStringList{QStringLiteral("Comment (*.foo *.bar)"), QStringLiteral("*.kde")}; 0247 /* clang-format on */ 0248 } 0249 0250 QTEST_MAIN(KUrlRequesterTest) 0251 #include "kurlrequestertest.moc"