Warning, file /frameworks/kio/autotests/kfilewidgettest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of the KIO framework tests 0003 SPDX-FileCopyrightText: 2016 Albert Astals Cid <aacid@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 "kfilewidget.h" 0009 0010 #include <QLabel> 0011 #include <QLoggingCategory> 0012 #include <QSignalSpy> 0013 #include <QStandardPaths> 0014 #include <QTemporaryDir> 0015 #include <QTest> 0016 #include <QUrl> 0017 0018 #include "../utils_p.h" 0019 #include "kiotesthelper.h" // createTestFile 0020 #include <KDirLister> 0021 #include <KFileFilterCombo> 0022 #include <KUrlComboBox> 0023 #include <kdiroperator.h> 0024 #include <kurlnavigator.h> 0025 0026 #include <KLocalizedString> 0027 0028 #include <QAbstractItemView> 0029 #include <QDialog> 0030 #include <QDropEvent> 0031 #include <QLineEdit> 0032 #include <QList> 0033 #include <QMimeData> 0034 #include <QStringList> 0035 #include <QStringLiteral> 0036 #include <QUrl> 0037 0038 Q_DECLARE_LOGGING_CATEGORY(KIO_KFILEWIDGETS_FW) 0039 Q_LOGGING_CATEGORY(KIO_KFILEWIDGETS_FW, "kf.kio.kfilewidgets.kfilewidget", QtInfoMsg) 0040 0041 static QWidget *findLocationLabel(QWidget *parent) 0042 { 0043 const QList<QLabel *> labels = parent->findChildren<QLabel *>(); 0044 for (QLabel *label : labels) { 0045 if (label->text() == i18n("&Name:") || label->text() == i18n("Name:")) { 0046 return label->buddy(); 0047 } 0048 } 0049 Q_ASSERT(false); 0050 return nullptr; 0051 } 0052 0053 /** 0054 * Unit test for KFileWidget 0055 */ 0056 class KFileWidgetTest : public QObject 0057 { 0058 Q_OBJECT 0059 0060 private Q_SLOTS: 0061 void initTestCase(); 0062 void testFilterCombo(); 0063 void testFocusOnLocationEdit(); 0064 void testFocusOnLocationEditChangeDir(); 0065 void testFocusOnLocationEditChangeDir2(); 0066 void testFocusOnDirOps(); 0067 void testGetStartUrl(); 0068 void testSetSelection_data(); 0069 0070 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 33) 0071 void testSetSelection(); 0072 #endif 0073 0074 void testSetSelectedUrl_data(); 0075 void testSetSelectedUrl(); 0076 void testPreserveFilenameWhileNavigating(); 0077 void testEnterUrl_data(); 0078 void testEnterUrl(); 0079 void testSetFilterForSave_data(); 0080 void testSetFilterForSave(); 0081 void testExtensionForSave_data(); 0082 void testExtensionForSave(); 0083 void testFilterChange(); 0084 void testDropFile_data(); 0085 void testDropFile(); 0086 void testCreateNestedNewFolders(); 0087 void testTokenize_data(); 0088 void testTokenize(); 0089 }; 0090 0091 void KFileWidgetTest::initTestCase() 0092 { 0093 QStandardPaths::setTestModeEnabled(true); 0094 0095 QVERIFY(QDir::homePath() != QDir::tempPath()); 0096 } 0097 0098 void KFileWidgetTest::testFilterCombo() 0099 { 0100 KFileWidget fw(QUrl(QStringLiteral("kfiledialog:///SaveDialog")), nullptr); 0101 fw.setOperationMode(KFileWidget::Saving); 0102 fw.setMode(KFile::File); 0103 0104 fw.setFilter( 0105 QStringLiteral("*.xml *.a|Word 2003 XML (.xml)\n" 0106 "*.odt|ODF Text Document (.odt)\n" 0107 "*.xml *.b|DocBook (.xml)\n" 0108 "*|Raw (*)")); 0109 0110 // default filter is selected 0111 QCOMPARE(fw.currentFilter(), QStringLiteral("*.xml *.a")); 0112 0113 // setUrl runs with blocked signals, so use setUrls. 0114 // auto-select ODT filter via filename 0115 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); 0116 QCOMPARE(fw.currentFilter(), QStringLiteral("*.odt")); 0117 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.odt")); 0118 0119 // select 2nd duplicate XML filter (see bug 407642) 0120 fw.filterWidget()->setCurrentFilter("*.xml *.b|DocBook (.xml)"); 0121 QCOMPARE(fw.currentFilter(), QStringLiteral("*.xml *.b")); 0122 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.xml")); 0123 0124 // keep filter after file change with same extension 0125 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test2.xml"))); 0126 QCOMPARE(fw.currentFilter(), QStringLiteral("*.xml *.b")); 0127 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test2.xml")); 0128 0129 // back to the non-xml / ODT filter 0130 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); 0131 QCOMPARE(fw.currentFilter(), QStringLiteral("*.odt")); 0132 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.odt")); 0133 0134 // auto-select 1st XML filter 0135 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test.xml"))); 0136 QCOMPARE(fw.currentFilter(), QStringLiteral("*.xml *.a")); 0137 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.xml")); 0138 0139 // select Raw '*' filter 0140 fw.filterWidget()->setCurrentFilter("*|Raw (*)"); 0141 QCOMPARE(fw.currentFilter(), QStringLiteral("*")); 0142 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.xml")); 0143 0144 // keep Raw '*' filter with matching file extension 0145 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); 0146 QCOMPARE(fw.currentFilter(), QStringLiteral("*")); 0147 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.odt")); 0148 0149 // keep Raw '*' filter with non-matching file extension 0150 fw.locationEdit()->setUrls(QStringList(QStringLiteral("test.core"))); 0151 QCOMPARE(fw.currentFilter(), QStringLiteral("*")); 0152 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.core")); 0153 0154 // select 2nd XML filter 0155 fw.filterWidget()->setCurrentFilter("*.xml *.b|DocBook (.xml)"); 0156 QCOMPARE(fw.currentFilter(), QStringLiteral("*.xml *.b")); 0157 QCOMPARE(fw.locationEdit()->urls()[0], QStringLiteral("test.xml")); 0158 } 0159 0160 void KFileWidgetTest::testFocusOnLocationEdit() 0161 { 0162 KFileWidget fw(QUrl::fromLocalFile(QDir::homePath())); 0163 fw.show(); 0164 fw.activateWindow(); 0165 QVERIFY(QTest::qWaitForWindowActive(&fw)); 0166 0167 QWidget *label = findLocationLabel(&fw); 0168 QVERIFY(label); 0169 QVERIFY(label->hasFocus()); 0170 } 0171 0172 void KFileWidgetTest::testFocusOnLocationEditChangeDir() 0173 { 0174 KFileWidget fw(QUrl::fromLocalFile(QDir::homePath())); 0175 fw.setUrl(QUrl::fromLocalFile(QDir::tempPath())); 0176 fw.show(); 0177 fw.activateWindow(); 0178 QVERIFY(QTest::qWaitForWindowActive(&fw)); 0179 0180 QWidget *label = findLocationLabel(&fw); 0181 QVERIFY(label); 0182 QVERIFY(label->hasFocus()); 0183 } 0184 0185 void KFileWidgetTest::testFocusOnLocationEditChangeDir2() 0186 { 0187 KFileWidget fw(QUrl::fromLocalFile(QDir::homePath())); 0188 fw.show(); 0189 fw.activateWindow(); 0190 QVERIFY(QTest::qWaitForWindowActive(&fw)); 0191 0192 fw.setUrl(QUrl::fromLocalFile(QDir::tempPath())); 0193 0194 QWidget *label = findLocationLabel(&fw); 0195 QVERIFY(label); 0196 QVERIFY(label->hasFocus()); 0197 } 0198 0199 void KFileWidgetTest::testFocusOnDirOps() 0200 { 0201 KFileWidget fw(QUrl::fromLocalFile(QDir::homePath())); 0202 fw.show(); 0203 fw.activateWindow(); 0204 QVERIFY(QTest::qWaitForWindowActive(&fw)); 0205 0206 const QList<KUrlNavigator *> nav = fw.findChildren<KUrlNavigator *>(); 0207 QCOMPARE(nav.count(), 1); 0208 nav[0]->setFocus(); 0209 0210 fw.setUrl(QUrl::fromLocalFile(QDir::tempPath())); 0211 0212 const QList<KDirOperator *> ops = fw.findChildren<KDirOperator *>(); 0213 QCOMPARE(ops.count(), 1); 0214 QVERIFY(ops[0]->hasFocus()); 0215 } 0216 0217 void KFileWidgetTest::testGetStartUrl() 0218 { 0219 QString recentDirClass; 0220 QString outFileName; 0221 QUrl localUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///attachmentDir")), recentDirClass, outFileName); 0222 QCOMPARE(recentDirClass, QStringLiteral(":attachmentDir")); 0223 QCOMPARE(localUrl.toLocalFile(), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); 0224 QVERIFY(outFileName.isEmpty()); 0225 0226 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 96) 0227 localUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///attachments/foo.txt?global")), recentDirClass, outFileName); 0228 QCOMPARE(recentDirClass, QStringLiteral("::attachments")); 0229 #else 0230 localUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///attachments/foo.txt")), recentDirClass, outFileName); 0231 QCOMPARE(recentDirClass, QStringLiteral(":attachments")); 0232 #endif 0233 QCOMPARE(localUrl.toLocalFile(), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); 0234 QCOMPARE(outFileName, QStringLiteral("foo.txt")); 0235 } 0236 0237 void KFileWidgetTest::testSetSelection_data() 0238 { 0239 QTest::addColumn<QString>("baseDir"); 0240 QTest::addColumn<QString>("selection"); 0241 QTest::addColumn<QString>("expectedBaseDir"); 0242 QTest::addColumn<QString>("expectedCurrentText"); 0243 0244 const QString baseDir = QDir::homePath(); 0245 // A nice filename to detect URL encoding issues 0246 const QString fileName = QStringLiteral("some:fi#le"); 0247 0248 // Bug 369216, kdialog calls setSelection(path) 0249 QTest::newRow("path") << baseDir << baseDir + QLatin1Char('/') + fileName << baseDir << fileName; 0250 QTest::newRow("differentPath") << QDir::rootPath() << baseDir + QLatin1Char('/') + fileName << baseDir << fileName; 0251 // kdeplatformfiledialoghelper.cpp calls setSelection(URL as string) 0252 QTest::newRow("url") << baseDir << QUrl::fromLocalFile(baseDir + QLatin1Char('/') + fileName).toString() << baseDir << fileName; 0253 // What if someone calls setSelection(fileName)? That breaks, hence e70f8134a2b in plasma-integration.git 0254 QTest::newRow("filename") << baseDir << fileName << baseDir << fileName; 0255 } 0256 0257 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 33) 0258 void KFileWidgetTest::testSetSelection() 0259 { 0260 // GIVEN 0261 QFETCH(QString, baseDir); 0262 QFETCH(QString, selection); 0263 QFETCH(QString, expectedBaseDir); 0264 QFETCH(QString, expectedCurrentText); 0265 const QUrl baseUrl = QUrl::fromLocalFile(baseDir).adjusted(QUrl::StripTrailingSlash); 0266 const QUrl expectedBaseUrl = QUrl::fromLocalFile(expectedBaseDir); 0267 0268 KFileWidget fw(baseUrl); 0269 0270 // WHEN 0271 fw.setSelection(selection); // now deprecated, this test shows why ;) 0272 0273 // THEN 0274 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), expectedBaseUrl); 0275 // if (QByteArray(QTest::currentDataTag()) == "filename") { 0276 QEXPECT_FAIL("filename", "setSelection cannot work with filenames, bad API", Continue); 0277 //} 0278 QCOMPARE(fw.locationEdit()->currentText(), expectedCurrentText); 0279 } 0280 #endif 0281 0282 void KFileWidgetTest::testSetSelectedUrl_data() 0283 { 0284 QTest::addColumn<QString>("baseDir"); 0285 QTest::addColumn<QUrl>("selectionUrl"); 0286 QTest::addColumn<QString>("expectedBaseDir"); 0287 QTest::addColumn<QString>("expectedCurrentText"); 0288 0289 const QString baseDir = QDir::homePath(); 0290 // A nice filename to detect URL encoding issues 0291 const QString fileName = QStringLiteral("some:fi#le"); 0292 const QUrl fileUrl = QUrl::fromLocalFile(baseDir + QLatin1Char('/') + fileName); 0293 0294 QTest::newRow("path") << baseDir << fileUrl << baseDir << fileName; 0295 QTest::newRow("differentPath") << QDir::rootPath() << fileUrl << baseDir << fileName; 0296 QTest::newRow("url") << baseDir << QUrl::fromLocalFile(baseDir + QLatin1Char('/') + fileName) << baseDir << fileName; 0297 0298 QUrl relativeUrl; 0299 relativeUrl.setPath(fileName); 0300 QTest::newRow("filename") << baseDir << relativeUrl << baseDir << fileName; 0301 } 0302 0303 void KFileWidgetTest::testSetSelectedUrl() 0304 { 0305 // GIVEN 0306 QFETCH(QString, baseDir); 0307 QFETCH(QUrl, selectionUrl); 0308 QFETCH(QString, expectedBaseDir); 0309 QFETCH(QString, expectedCurrentText); 0310 0311 const QUrl baseUrl = QUrl::fromLocalFile(baseDir).adjusted(QUrl::StripTrailingSlash); 0312 const QUrl expectedBaseUrl = QUrl::fromLocalFile(expectedBaseDir); 0313 KFileWidget fw(baseUrl); 0314 0315 // WHEN 0316 fw.setSelectedUrl(selectionUrl); 0317 0318 // THEN 0319 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), expectedBaseUrl); 0320 QCOMPARE(fw.locationEdit()->currentText(), expectedCurrentText); 0321 } 0322 0323 void KFileWidgetTest::testPreserveFilenameWhileNavigating() // bug 418711 0324 { 0325 // GIVEN 0326 const QUrl url = QUrl::fromLocalFile(QDir::homePath()); 0327 KFileWidget fw(url); 0328 fw.setOperationMode(KFileWidget::Saving); 0329 fw.setMode(KFile::File); 0330 QString baseDir = QDir::homePath(); 0331 if (baseDir.endsWith('/')) { 0332 baseDir.chop(1); 0333 } 0334 const QString fileName = QStringLiteral("somefi#le"); 0335 const QUrl fileUrl = QUrl::fromLocalFile(baseDir + QLatin1Char('/') + fileName); 0336 fw.setSelectedUrl(fileUrl); 0337 const QUrl baseUrl = QUrl::fromLocalFile(baseDir); 0338 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), baseUrl); 0339 QCOMPARE(fw.locationEdit()->currentText(), fileName); 0340 0341 // WHEN 0342 fw.dirOperator()->cdUp(); 0343 0344 // THEN 0345 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), baseUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)); 0346 QCOMPARE(fw.locationEdit()->currentText(), fileName); // unchanged 0347 } 0348 0349 void KFileWidgetTest::testEnterUrl_data() 0350 { 0351 QTest::addColumn<QUrl>("expectedUrl"); 0352 0353 // Check if the root urls are well transformed into themself, otherwise 0354 // when going up from file:///home/ it will become file:///home/user 0355 QTest::newRow("file") << QUrl::fromLocalFile("/"); 0356 QTest::newRow("trash") << QUrl("trash:/"); 0357 QTest::newRow("sftp") << QUrl("sftp://127.0.0.1/"); 0358 } 0359 0360 void KFileWidgetTest::testEnterUrl() 0361 { 0362 // GIVEN 0363 QFETCH(QUrl, expectedUrl); 0364 0365 // WHEN 0366 // These lines are copied from src/filewidgets/kfilewidget.cpp 0367 // void KFileWidgetPrivate::_k_enterUrl(const QUrl &url) 0368 QUrl u(expectedUrl); 0369 Utils::appendSlashToPath(u); 0370 // THEN 0371 QVERIFY(u.isValid()); 0372 QCOMPARE(u, expectedUrl); 0373 } 0374 0375 void KFileWidgetTest::testSetFilterForSave_data() 0376 { 0377 QTest::addColumn<QString>("fileName"); 0378 QTest::addColumn<QString>("filter"); 0379 QTest::addColumn<QString>("expectedCurrentText"); 0380 QTest::addColumn<QString>("expectedSelectedFileName"); 0381 0382 const QString filter = QStringLiteral("*.txt|Text files\n*.HTML|HTML files"); 0383 0384 QTest::newRow("some.txt") << "some.txt" << filter << QStringLiteral("some.txt") << QStringLiteral("some.txt"); 0385 0386 // If an application provides a name without extension, then the 0387 // displayed name will not receive an extension. It will however be 0388 // appended when the dialog is closed. 0389 QTest::newRow("extensionless name") << "some" << filter << QStringLiteral("some") << QStringLiteral("some.txt"); 0390 0391 // If the file literally exists, then no new extension will be appended. 0392 QTest::newRow("existing file") << "README" << filter << QStringLiteral("README") << QStringLiteral("README"); 0393 0394 // XXX perhaps the "extension" should not be modified when it does not 0395 // match any of the existing types? Should "some.2019.txt" be expected? 0396 QTest::newRow("some.2019") << "some.2019" << filter << QStringLiteral("some.txt") << QStringLiteral("some.txt"); 0397 0398 // XXX be smarter and do not change the extension if one of the other 0399 // filters match. Should "some.html" be expected? 0400 QTest::newRow("some.html") << "some.html" << filter << QStringLiteral("some.txt") << QStringLiteral("some.txt"); 0401 } 0402 0403 void KFileWidgetTest::testSetFilterForSave() 0404 { 0405 QFETCH(QString, fileName); 0406 QFETCH(QString, filter); 0407 QFETCH(QString, expectedCurrentText); 0408 QFETCH(QString, expectedSelectedFileName); 0409 0410 // Use a temporary directory since the presence of existing files 0411 // influences whether an extension is automatically appended. 0412 QTemporaryDir tempDir; 0413 const QUrl dirUrl = QUrl::fromLocalFile(tempDir.path()); 0414 const QUrl fileUrl = QUrl::fromLocalFile(tempDir.filePath(fileName)); 0415 const QUrl expectedFileUrl = QUrl::fromLocalFile(tempDir.filePath(expectedSelectedFileName)); 0416 createTestFile(tempDir.filePath("README")); 0417 0418 KFileWidget fw(dirUrl); 0419 fw.setOperationMode(KFileWidget::Saving); 0420 fw.setSelectedUrl(fileUrl); 0421 // Calling setFilter has side-effects and changes the file name. 0422 fw.setFilter(filter); 0423 0424 // Verify the expected populated name. 0425 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), dirUrl); 0426 QCOMPARE(fw.locationEdit()->currentText(), expectedCurrentText); 0427 0428 // QFileDialog ends up calling KDEPlatformFileDialog::selectedFiles() 0429 // which calls KFileWidget::selectedUrls(). 0430 // Accept the filename to ensure that a filename is selected. 0431 connect(&fw, &KFileWidget::accepted, &fw, &KFileWidget::accept); 0432 QTest::keyClick(fw.locationEdit(), Qt::Key_Return); 0433 QList<QUrl> urls = fw.selectedUrls(); 0434 QCOMPARE(urls.size(), 1); 0435 QCOMPARE(urls[0], expectedFileUrl); 0436 } 0437 0438 void KFileWidgetTest::testExtensionForSave_data() 0439 { 0440 QTest::addColumn<QString>("fileName"); 0441 QTest::addColumn<QString>("filter"); 0442 QTest::addColumn<QString>("expectedCurrentText"); 0443 QTest::addColumn<QString>("expectedSelectedFileName"); 0444 0445 const QString filter = QStringLiteral("*.txt *.text|Text files\n*.HTML|HTML files"); 0446 0447 QTest::newRow("some.txt") << "some.txt" << filter << QStringLiteral("some.txt") << QStringLiteral("some.txt"); 0448 0449 // If an application provides a name without extension, then the 0450 // displayed name will not receive an extension. It will however be 0451 // appended when the dialog is closed. 0452 QTest::newRow("extensionless name") << "some" << filter << QStringLiteral("some") << QStringLiteral("some.txt"); 0453 QTest::newRow("extensionless name") << "some.with_dot" << filter << QStringLiteral("some.with_dot") << QStringLiteral("some.with_dot.txt"); 0454 QTest::newRow("extensionless name") << "some.with.dots" << filter << QStringLiteral("some.with.dots") << QStringLiteral("some.with.dots.txt"); 0455 0456 // If the file literally exists, then no new extension will be appended. 0457 QTest::newRow("existing file") << "README" << filter << QStringLiteral("README") << QStringLiteral("README"); 0458 } 0459 0460 void KFileWidgetTest::testExtensionForSave() 0461 { 0462 QFETCH(QString, fileName); 0463 QFETCH(QString, filter); 0464 QFETCH(QString, expectedCurrentText); 0465 QFETCH(QString, expectedSelectedFileName); 0466 0467 // Use a temporary directory since the presence of existing files 0468 // influences whether an extension is automatically appended. 0469 QTemporaryDir tempDir; 0470 const QUrl dirUrl = QUrl::fromLocalFile(tempDir.path()); 0471 const QUrl fileUrl = QUrl::fromLocalFile(tempDir.filePath(fileName)); 0472 const QUrl expectedFileUrl = QUrl::fromLocalFile(tempDir.filePath(expectedSelectedFileName)); 0473 createTestFile(tempDir.filePath("README")); 0474 0475 KFileWidget fw(dirUrl); 0476 fw.setOperationMode(KFileWidget::Saving); 0477 // Calling setFilter has side-effects and changes the file name. 0478 // The difference to testSetFilterForSave is that the filter is already set before the fileUrl 0479 // is set, and will not be changed after. 0480 fw.setFilter(filter); 0481 fw.setSelectedUrl(fileUrl); 0482 0483 // Verify the expected populated name. 0484 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), dirUrl); 0485 QCOMPARE(fw.locationEdit()->currentText(), expectedCurrentText); 0486 0487 // QFileDialog ends up calling KDEPlatformFileDialog::selectedFiles() 0488 // which calls KFileWidget::selectedUrls(). 0489 // Accept the filename to ensure that a filename is selected. 0490 connect(&fw, &KFileWidget::accepted, &fw, &KFileWidget::accept); 0491 QTest::keyClick(fw.locationEdit(), Qt::Key_Return); 0492 QList<QUrl> urls = fw.selectedUrls(); 0493 QCOMPARE(urls.size(), 1); 0494 QCOMPARE(urls[0], expectedFileUrl); 0495 } 0496 0497 void KFileWidgetTest::testFilterChange() 0498 { 0499 QTemporaryDir tempDir; 0500 createTestFile(tempDir.filePath("some.c")); 0501 bool created = QDir(tempDir.path()).mkdir("directory"); 0502 Q_ASSERT(created); 0503 0504 KFileWidget fw(QUrl::fromLocalFile(tempDir.path())); 0505 fw.setOperationMode(KFileWidget::Saving); 0506 fw.setSelectedUrl(QUrl::fromLocalFile(tempDir.filePath("some.txt"))); 0507 fw.setFilter("*.txt|Txt\n*.c|C"); 0508 0509 // Initial filename. 0510 QCOMPARE(fw.locationEdit()->currentText(), QStringLiteral("some.txt")); 0511 QCOMPARE(fw.filterWidget()->currentFilter(), QStringLiteral("*.txt")); 0512 0513 // Select type with an existing file. 0514 fw.filterWidget()->setCurrentFilter("*.c|C"); 0515 QCOMPARE(fw.locationEdit()->currentText(), QStringLiteral("some.c")); 0516 QCOMPARE(fw.filterWidget()->currentFilter(), QStringLiteral("*.c")); 0517 0518 // Do not update extension if the current selection is a directory. 0519 fw.setSelectedUrl(QUrl::fromLocalFile(tempDir.filePath("directory"))); 0520 fw.filterWidget()->setCurrentFilter("*.txt|Txt"); 0521 QCOMPARE(fw.locationEdit()->currentText(), QStringLiteral("directory")); 0522 QCOMPARE(fw.filterWidget()->currentFilter(), QStringLiteral("*.txt")); 0523 } 0524 0525 void KFileWidgetTest::testDropFile_data() 0526 { 0527 QTest::addColumn<QString>("dir"); 0528 QTest::addColumn<QString>("fileName"); 0529 QTest::addColumn<QString>("expectedCurrentText"); 0530 0531 QTest::newRow("some.txt") << "" 0532 << "some.txt" 0533 << "some.txt"; 0534 0535 QTest::newRow("subdir/some.txt") << "subdir" 0536 << "subdir/some.txt" 0537 << "some.txt"; 0538 } 0539 0540 void KFileWidgetTest::testDropFile() 0541 { 0542 QFETCH(QString, dir); 0543 QFETCH(QString, fileName); 0544 QFETCH(QString, expectedCurrentText); 0545 0546 // Use a temporary directory since the presence of existing files 0547 // influences whether an extension is automatically appended. 0548 QTemporaryDir tempDir; 0549 QUrl dirUrl = QUrl::fromLocalFile(tempDir.path()); 0550 const QUrl fileUrl = QUrl::fromLocalFile(tempDir.filePath(fileName)); 0551 if (!dir.isEmpty()) { 0552 createTestDirectory(tempDir.filePath(dir)); 0553 dirUrl = QUrl::fromLocalFile(tempDir.filePath(dir)); 0554 } 0555 createTestFile(tempDir.filePath(fileName)); 0556 0557 KFileWidget fileWidget(QUrl::fromLocalFile(tempDir.path())); 0558 fileWidget.setOperationMode(KFileWidget::Saving); 0559 fileWidget.setMode(KFile::File); 0560 fileWidget.show(); 0561 0562 QMimeData *mimeData = new QMimeData(); 0563 mimeData->setUrls(QList<QUrl>() << fileUrl); 0564 0565 KDirLister *dirLister = fileWidget.dirOperator()->dirLister(); 0566 QSignalSpy spy(dirLister, qOverload<>(&KCoreDirLister::completed)); 0567 0568 QAbstractItemView *view = fileWidget.dirOperator()->view(); 0569 QVERIFY(view); 0570 0571 QDragEnterEvent event1(QPoint(), Qt::DropAction::MoveAction, mimeData, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier); 0572 QVERIFY(qApp->sendEvent(view->viewport(), &event1)); 0573 0574 // Fake drop 0575 QDropEvent event(QPoint(), Qt::DropAction::MoveAction, mimeData, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier); 0576 QVERIFY(qApp->sendEvent(view->viewport(), &event)); 0577 0578 if (!dir.isEmpty()) { 0579 // once we drop a file the dirlister scans the dir 0580 // wait for the completed signal from the dirlister 0581 QVERIFY(spy.wait()); 0582 } 0583 0584 // Verify the expected populated name. 0585 QCOMPARE(fileWidget.baseUrl().adjusted(QUrl::StripTrailingSlash), dirUrl); 0586 QCOMPARE(fileWidget.locationEdit()->currentText(), expectedCurrentText); 0587 0588 // QFileDialog ends up calling KDEPlatformFileDialog::selectedFiles() 0589 // which calls KFileWidget::selectedUrls(). 0590 // Accept the filename to ensure that a filename is selected. 0591 connect(&fileWidget, &KFileWidget::accepted, &fileWidget, &KFileWidget::accept); 0592 QTest::keyClick(fileWidget.locationEdit(), Qt::Key_Return); 0593 const QList<QUrl> urls = fileWidget.selectedUrls(); 0594 QCOMPARE(urls.size(), 1); 0595 QCOMPARE(urls[0], fileUrl); 0596 } 0597 0598 void KFileWidgetTest::testCreateNestedNewFolders() 0599 { 0600 // when creating multiple nested new folders in the "save as" dialog, where folders are 0601 // created and entered, kdirlister would hit an assert (in reinsert()), bug 408801 0602 QTemporaryDir tempDir; 0603 QVERIFY(tempDir.isValid()); 0604 const QString dir = tempDir.path(); 0605 const QUrl url = QUrl::fromLocalFile(dir); 0606 KFileWidget fw(url); 0607 fw.setOperationMode(KFileWidget::Saving); 0608 fw.setMode(KFile::File); 0609 0610 QString currentPath = dir; 0611 // create the nested folders 0612 for (int i = 1; i < 6; ++i) { 0613 fw.dirOperator()->mkdir(); 0614 QDialog *dialog; 0615 // QTRY_ because a NameFinderJob could be running and the dialog will be shown when 0616 // it finishes. 0617 QTRY_VERIFY(dialog = fw.findChild<QDialog *>()); 0618 QLineEdit *lineEdit = dialog->findChild<QLineEdit *>(); 0619 QVERIFY(lineEdit); 0620 const QString name = QStringLiteral("folder%1").arg(i); 0621 lineEdit->setText(name); 0622 // simulate the time the user will take to type the new folder name 0623 QTest::qWait(1000); 0624 0625 dialog->accept(); 0626 0627 currentPath += QLatin1Char('/') + name; 0628 // Wait till the filewidget changes to the new folder 0629 QTRY_COMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash).toLocalFile(), currentPath); 0630 } 0631 } 0632 0633 void KFileWidgetTest::testTokenize_data() 0634 { 0635 // Real filename (as in how they are stored in the fs) 0636 QTest::addColumn<QStringList>("fileNames"); 0637 // Escaped value of the text-box in the dialog 0638 QTest::addColumn<QString>("expectedCurrentText"); 0639 0640 QTest::newRow("simple") << QStringList{"test2"} << QString("test2"); 0641 0642 // When a single file with space is selected, it is _not_ quoted ... 0643 QTest::newRow("space-single-file") << QStringList{"test space"} << QString("test space"); 0644 0645 // However, when multiple files are selected, they are quoted 0646 QTest::newRow("space-multi-file") << QStringList{"test space", "test2"} << QString("\"test space\" \"test2\""); 0647 0648 // All quotes in names should be escaped, however since this is a single 0649 // file, the whole name will not be escaped. 0650 QTest::newRow("quote-single-file") << QStringList{"test\"quote"} << QString("test\\\"quote"); 0651 0652 // Escape multiple files. Files should also be wrapped in "" 0653 // Note that we are also testing quote at the end of the name 0654 QTest::newRow("quote-multi-file") << QStringList{"test\"quote", "test2-quote\"", "test"} << QString("\"test\\\"quote\" \"test2-quote\\\"\" \"test\""); 0655 0656 // Ok, enough with quotes... lets do some backslashes 0657 // Backslash literals in file names - Unix only case 0658 QTest::newRow("backslash-single-file") << QStringList{"test\\backslash"} << QString("test\\\\backslash"); 0659 0660 QTest::newRow("backslash-multi-file") << QStringList{"test\\back\\slash", "test"} << QString("\"test\\\\back\\\\slash\" \"test\""); 0661 0662 QTest::newRow("double-backslash-multi-file") << QStringList{"test\\\\back\\slash", "test"} << QString("\"test\\\\\\\\back\\\\slash\" \"test\""); 0663 0664 QTest::newRow("double-backslash-end") << QStringList{"test\\\\"} << QString("test\\\\\\\\"); 0665 0666 QTest::newRow("single-backslash-end") << QStringList{"some thing", "test\\"} << QString("\"some thing\" \"test\\\\\""); 0667 0668 QTest::newRow("sharp") << QStringList{"some#thing"} << QString("some#thing"); 0669 0670 // Filenames beginning with ':'; QDir::isAbsolutePath() always returns true 0671 // in that case, #322837 0672 QTest::newRow("file-beginning-with-colon") << QStringList{":test2"} << QString{":test2"}; 0673 0674 QTest::newRow("multiple-files-beginning-with-colon") << QStringList{":test space", ":test2"} << QString{"\":test space\" \":test2\""}; 0675 } 0676 0677 void KFileWidgetTest::testTokenize() 0678 { 0679 // We will use setSelectedUrls([QUrl]) here in order to check correct 0680 // filename escaping. Afterwards we will accept() the dialog to confirm 0681 // correct result 0682 QFETCH(QStringList, fileNames); 0683 QFETCH(QString, expectedCurrentText); 0684 0685 QTemporaryDir tempDir; 0686 const QString tempDirPath = tempDir.path(); 0687 const QUrl tempDirUrl = QUrl::fromLocalFile(tempDirPath); 0688 QList<QUrl> fileUrls; 0689 for (const auto &fileName : fileNames) { 0690 const QString filePath = tempDirPath + QLatin1Char('/') + fileName; 0691 const QUrl localUrl = QUrl::fromLocalFile(filePath); 0692 fileUrls.append(localUrl); 0693 qCDebug(KIO_KFILEWIDGETS_FW) << fileName << " => " << localUrl; 0694 } 0695 0696 KFileWidget fw(tempDirUrl); 0697 fw.setOperationMode(KFileWidget::Opening); 0698 fw.setMode(KFile::Files); 0699 fw.setSelectedUrls(fileUrls); 0700 0701 // Verify the expected populated name. 0702 QCOMPARE(fw.baseUrl().adjusted(QUrl::StripTrailingSlash), tempDirUrl); 0703 QCOMPARE(fw.locationEdit()->currentText(), expectedCurrentText); 0704 0705 // QFileDialog ends up calling KDEPlatformFileDialog::selectedFiles() 0706 // which calls KFileWidget::selectedUrls(). 0707 // Accept the filename to ensure that a filename is selected. 0708 connect(&fw, &KFileWidget::accepted, &fw, &KFileWidget::accept); 0709 QTest::keyClick(fw.locationEdit(), Qt::Key_Return); 0710 const QList<QUrl> urls = fw.selectedUrls(); 0711 0712 // We must have the same size as requested files 0713 QCOMPARE(urls.size(), fileNames.size()); 0714 QCOMPARE(urls, fileUrls); 0715 } 0716 0717 QTEST_MAIN(KFileWidgetTest) 0718 0719 #include "kfilewidgettest.moc"