File indexing completed on 2024-04-28 13:29:00

0001 /*  This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 2014 Dominik Haumann <dhaumann@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include <KDirOperator>
0008 #include <KFileWidget>
0009 #include <QDir>
0010 #include <QFileDialog>
0011 #include <QTemporaryDir>
0012 #include <QTemporaryFile>
0013 #include <QTest>
0014 #include <QTimer>
0015 
0016 Q_DECLARE_METATYPE(QFileDialog::ViewMode)
0017 Q_DECLARE_METATYPE(QFileDialog::FileMode)
0018 Q_DECLARE_METATYPE(KFile::FileView)
0019 Q_DECLARE_METATYPE(KFile::Modes)
0020 
0021 class KFileDialog_UnitTest : public QObject
0022 {
0023     Q_OBJECT
0024 private Q_SLOTS:
0025     void initTestCase()
0026     {
0027     }
0028 
0029     void init()
0030     {
0031     }
0032 
0033     void cleanupTestCase()
0034     {
0035     }
0036 
0037     void testSetNameFilters()
0038     {
0039         QFileDialog dialog;
0040 
0041         QStringList nameFilterList = QStringList() << QStringLiteral("c (*.cpp)") << QStringLiteral("h (*.h)");
0042         dialog.setNameFilters(nameFilterList);
0043         QCOMPARE(dialog.nameFilters(), nameFilterList);
0044     }
0045 
0046     void testSelectNameFilter()
0047     {
0048         QFileDialog dialog;
0049 
0050         QStringList nameFilterList = QStringList() << QStringLiteral("c (*.cpp)") << QStringLiteral("h (*.h)");
0051         dialog.setNameFilters(nameFilterList);
0052         QCOMPARE(dialog.nameFilters(), nameFilterList);
0053 
0054         QString selectNameFilter(QStringLiteral("h (*.h)"));
0055         dialog.selectNameFilter(selectNameFilter);
0056         QEXPECT_FAIL("", "Does currently not work. Works, once the dialog gets shown, though.", Continue);
0057         QCOMPARE(dialog.selectedNameFilter(), selectNameFilter);
0058 
0059         dialog.show();
0060         QCOMPARE(dialog.selectedNameFilter(), selectNameFilter);
0061     }
0062 
0063     void testSelectNameFilterMultipleMatching()
0064     {
0065         QFileDialog dialog;
0066 
0067         QStringList nameFilterList = QStringList() << QStringLiteral("c (*.cpp)") << QStringLiteral("h1 (*.h)") << QStringLiteral("h2 (*.h)");
0068         dialog.setNameFilters(nameFilterList);
0069         QCOMPARE(dialog.nameFilters(), nameFilterList);
0070 
0071         QString selectNameFilter(QStringLiteral("h2 (*.h)"));
0072         dialog.selectNameFilter(selectNameFilter);
0073         QEXPECT_FAIL("", "Does currently not work. Works, once the dialog gets shown, though.", Continue);
0074         QCOMPARE(dialog.selectedNameFilter(), selectNameFilter);
0075 
0076         dialog.show();
0077         QCOMPARE(dialog.selectedNameFilter(), selectNameFilter);
0078     }
0079 
0080     void testSelectedMimeTypeFilter_data()
0081     {
0082         QTest::addColumn<QStringList>("mimeTypeFilters");
0083         QTest::addColumn<QString>("targetMimeTypeFilter");
0084 
0085         const auto headerMime = QStringLiteral("text/x-chdr");
0086         const auto jsonMime = QStringLiteral("application/json");
0087         const auto zipMime = QStringLiteral("application/zip");
0088 
0089         QTest::newRow("single mime filter (C header file)") << QStringList{headerMime} << headerMime;
0090 
0091         QTest::newRow("single mime filter (JSON file)") << QStringList{jsonMime} << jsonMime;
0092 
0093         QTest::newRow("multiple mime filters") << QStringList{jsonMime, zipMime} << jsonMime;
0094     }
0095 
0096     void testSelectedMimeTypeFilter()
0097     {
0098         QFileDialog dialog;
0099 
0100         QFETCH(QStringList, mimeTypeFilters);
0101         dialog.setMimeTypeFilters(mimeTypeFilters);
0102 
0103         QFETCH(QString, targetMimeTypeFilter);
0104         dialog.selectMimeTypeFilter(targetMimeTypeFilter);
0105 
0106         dialog.show();
0107         QCOMPARE(dialog.selectedMimeTypeFilter(), targetMimeTypeFilter);
0108     }
0109 
0110     void testFallbackOnFirstFilterInSaveMode()
0111     {
0112         QFileDialog dialog;
0113         dialog.setAcceptMode(QFileDialog::AcceptSave);
0114         dialog.setMimeTypeFilters({QStringLiteral("application/json"), QStringLiteral("application/zip")});
0115         dialog.show();
0116         QCOMPARE(dialog.selectedMimeTypeFilter(), QStringLiteral("application/json"));
0117     }
0118 
0119     void testSetDirectory()
0120     {
0121         QFileDialog dialog;
0122         dialog.setDirectory(QDir::rootPath());
0123         QCOMPARE(dialog.directory().absolutePath(), QDir::rootPath());
0124     }
0125 
0126     void testSelectUrl()
0127     {
0128         QTemporaryFile tempFile(m_tempDir.path() + "/kfiledialogtest_XXXXXX");
0129         tempFile.setAutoRemove(true);
0130         tempFile.open();
0131         QString tempName = tempFile.fileName();
0132         QUrl url = QUrl::fromLocalFile(tempName);
0133         int idx = tempName.lastIndexOf('/');
0134         QUrl directoryUrl = QUrl::fromLocalFile(tempName.left(idx + 1));
0135 
0136         QFileDialog dialog;
0137         dialog.selectUrl(url);
0138         dialog.show();
0139 
0140         // check if dialog was set to base directory url of the passed file url
0141         QCOMPARE(dialog.directoryUrl(), directoryUrl);
0142     }
0143 
0144     void testGetSaveFileUrl()
0145     {
0146         QObject lambdaGuard;
0147         QTemporaryFile tempFile(m_tempDir.path() + "/kfiledialogtest_XXXXXX");
0148         tempFile.open();
0149         const QString tempName = tempFile.fileName();
0150         const QUrl url = QUrl::fromLocalFile(tempName);
0151 
0152         // Need to use a lambda and not just QTest::qWaitForWindowExposed();
0153         // because with the static getSaveFileUrl we do not have access
0154         // to the QFileDialog object, so instead we hook to a signal
0155         KFileWidget::OperationMode saveFileOperationMode = KFileWidget::Other;
0156         connect(qApp, &QGuiApplication::focusWindowChanged, &lambdaGuard, [&saveFileOperationMode] {
0157             KFileWidget *fileWidget = findFileWidget();
0158             saveFileOperationMode = fileWidget->operationMode();
0159             qApp->activeWindow()->close();
0160         });
0161 
0162         QFileDialog::getSaveFileUrl(nullptr, QString(), url);
0163 
0164         QCOMPARE(saveFileOperationMode, KFileWidget::Saving);
0165     }
0166 
0167     void testViewMode()
0168     {
0169         // Open a file dialog, and change view mode to tree
0170         {
0171             QFileDialog dialog;
0172             dialog.show();
0173 
0174             KFileWidget *fw = findFileWidget();
0175             QVERIFY(fw);
0176             fw->setViewMode(KFile::Tree);
0177             fw->slotCancel(); // the saving happens there
0178         }
0179         // Open another one, and check that the view mode is now tree, change it to simple
0180         {
0181             QFileDialog dialog;
0182             dialog.show();
0183 
0184             KFileWidget *fw = findFileWidget();
0185             QVERIFY(fw);
0186             KDirOperator *op = fw->dirOperator();
0187             QCOMPARE(fileViewToString(op->viewMode()), fileViewToString(KFile::Tree));
0188             fw->setViewMode(KFile::Simple);
0189             fw->slotCancel();
0190         }
0191         // Open another one, and check that the view mode is now simple
0192         {
0193             QFileDialog dialog;
0194             dialog.show();
0195 
0196             KFileWidget *fw = findFileWidget();
0197             QVERIFY(fw);
0198             KDirOperator *op = fw->dirOperator();
0199             QCOMPARE(fileViewToString(op->viewMode()), fileViewToString(KFile::Simple));
0200             fw->setViewMode(KFile::Detail);
0201             fw->slotCancel();
0202         }
0203     }
0204 
0205     void testOpenDialog()
0206     {
0207         // Open parentless
0208         {
0209             QFileDialog dialog;
0210             dialog.open();
0211 
0212             KFileWidget *fw = findFileWidget();
0213             QVERIFY(fw);
0214             QCOMPARE(fw->isVisible(), true);
0215             fw->slotCancel();
0216         }
0217         // Open with parent
0218         {
0219             QWidget w;
0220             w.show();
0221 
0222             QFileDialog dialog(&w);
0223             dialog.open();
0224 
0225             KFileWidget *fw = findFileWidget();
0226             QVERIFY(fw);
0227             QCOMPARE(fw->isVisible(), true);
0228             fw->slotCancel();
0229         }
0230     }
0231 
0232     void testShowDialog()
0233     {
0234         // Show parentless
0235         {
0236             QFileDialog dialog;
0237             dialog.show();
0238 
0239             KFileWidget *fw = findFileWidget();
0240             QVERIFY(fw);
0241             QCOMPARE(fw->isVisible(), true);
0242             fw->slotCancel();
0243         }
0244         // Show with parent
0245         {
0246             QWidget w;
0247             w.show();
0248 
0249             QFileDialog dialog(&w);
0250             dialog.show();
0251 
0252             KFileWidget *fw = findFileWidget();
0253             QVERIFY(fw);
0254             QCOMPARE(fw->isVisible(), true);
0255             fw->slotCancel();
0256         }
0257     }
0258 
0259     void testSetFileMode_data()
0260     {
0261         QTest::addColumn<QFileDialog::FileMode>("qtFileMode");
0262         QTest::addColumn<KFile::Modes>("kdeFileMode");
0263         QTest::newRow("anyfile") << QFileDialog::AnyFile << KFile::Modes(KFile::File);
0264         QTest::newRow("existingfile") << QFileDialog::ExistingFile << KFile::Modes(KFile::File | KFile::ExistingOnly);
0265         QTest::newRow("directory") << QFileDialog::Directory << KFile::Modes(KFile::Directory | KFile::ExistingOnly);
0266         QTest::newRow("existingfiles") << QFileDialog::ExistingFiles << KFile::Modes(KFile::Files | KFile::ExistingOnly);
0267     }
0268 
0269     void testSetFileMode()
0270     {
0271         QFETCH(QFileDialog::FileMode, qtFileMode);
0272         QFETCH(KFile::Modes, kdeFileMode);
0273         QFileDialog dialog;
0274         dialog.setFileMode(qtFileMode);
0275         dialog.show();
0276 
0277         KFileWidget *fw = findFileWidget();
0278         QVERIFY(fw);
0279         QCOMPARE(fw->mode(), kdeFileMode);
0280 
0281         QCOMPARE(dialog.fileMode(), qtFileMode);
0282     }
0283 
0284     void testSaveOverwrite_data()
0285     {
0286         QTest::addColumn<bool>("qtOverwriteOption");
0287         QTest::addColumn<bool>("messageBoxExpected");
0288         QTest::newRow("checkoverwrite") << false << true;
0289         QTest::newRow("allowoverwrite") << true << false;
0290     }
0291 
0292     void testSaveOverwrite()
0293     {
0294         QFETCH(bool, qtOverwriteOption);
0295         QFETCH(bool, messageBoxExpected);
0296 
0297         QTemporaryFile tempFile(m_tempDir.path() + "/kfiledialogtest_XXXXXX");
0298         tempFile.setAutoRemove(true);
0299         tempFile.open();
0300         QString tempName = tempFile.fileName();
0301         tempFile.close();
0302         int idx = tempName.lastIndexOf('/');
0303 
0304         QFileDialog dialog;
0305         dialog.setAcceptMode(QFileDialog::AcceptSave);
0306         if (qtOverwriteOption)
0307             dialog.setOption(QFileDialog::DontConfirmOverwrite);
0308         dialog.setDirectory(tempName.left(idx + 1));
0309         dialog.selectFile(tempName.mid(idx + 1));
0310         dialog.open();
0311 
0312         KFileWidget *fw = findFileWidget();
0313         QVERIFY(fw);
0314         QVERIFY(QTest::qWaitForWindowExposed(fw->window()));
0315         QCOMPARE(fw->isVisible(), true);
0316 
0317         bool timerRun = false;
0318 
0319         QTimer::singleShot(3500, this, [&] {
0320             timerRun = true;
0321             QDialog *msgbox = findMessageBox();
0322             if (msgbox) {
0323                 QVERIFY(QTest::qWaitForWindowExposed(msgbox));
0324                 QCOMPARE(msgbox->isVisible(), true);
0325                 msgbox->close();
0326                 QVERIFY(messageBoxExpected);
0327             } else {
0328                 QVERIFY(!messageBoxExpected);
0329             }
0330         });
0331         fw->slotOk();
0332 
0333         QTRY_VERIFY(timerRun);
0334     }
0335 
0336     void testRememberLastDirectory()
0337     {
0338         const QUrl dir = QUrl::fromLocalFile(QDir::tempPath()).adjusted(QUrl::StripTrailingSlash);
0339         // Open and navigate
0340         {
0341             QFileDialog dialog;
0342             dialog.open();
0343 
0344             KFileWidget *fw = findFileWidget();
0345             QVERIFY(fw);
0346             QCOMPARE(fw->isVisible(), true);
0347             fw->setUrl(dir);
0348             fw->slotCancel();
0349         }
0350         // Open another filedialog, check that the default directory is the one from above
0351         {
0352             QFileDialog dialog;
0353             dialog.open();
0354 
0355             KFileWidget *fw = findFileWidget();
0356             QVERIFY(fw);
0357             QCOMPARE(fw->isVisible(), true);
0358             QCOMPARE(dialog.directoryUrl().adjusted(QUrl::StripTrailingSlash), dir);
0359             fw->slotCancel();
0360         }
0361     }
0362 
0363 private:
0364     QTemporaryDir m_tempDir;
0365 
0366     static QString fileViewToString(KFile::FileView fv)
0367     {
0368         switch (fv) {
0369         case KFile::Detail:
0370             return QStringLiteral("Detail");
0371         case KFile::Simple:
0372             return QStringLiteral("Simple");
0373         case KFile::Tree:
0374             return QStringLiteral("Tree");
0375         case KFile::DetailTree:
0376             return QStringLiteral("DetailTree");
0377         default:
0378             break;
0379         }
0380         return QStringLiteral("ERROR");
0381     }
0382 
0383     static KFileWidget *findFileWidget()
0384     {
0385         QList<KFileWidget *> widgets;
0386         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
0387             KFileWidget *fw = widget->findChild<KFileWidget *>();
0388             if (fw) {
0389                 widgets.append(fw);
0390             }
0391         }
0392         Q_ASSERT(widgets.count() == 1);
0393         return (widgets.count() == 1) ? widgets.first() : nullptr;
0394     }
0395 
0396     static QDialog *findMessageBox()
0397     {
0398         QList<QDialog *> widgets;
0399         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
0400             QDialog *dlg = widget->findChild<QDialog *>();
0401             if (dlg) {
0402                 widgets.append(dlg);
0403             }
0404         }
0405         return (widgets.count() == 1) ? widgets.first() : nullptr;
0406     }
0407 };
0408 
0409 QTEST_MAIN(KFileDialog_UnitTest)
0410 
0411 #include "kfiledialog_unittest.moc"