File indexing completed on 2025-01-26 05:06:19

0001 /*
0002     SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
0003     SPDX-FileContributor: Andras Mantia <andras.mantia@kdab.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "foldermodeltest.h"
0009 #include "foldermodel.h"
0010 #include "screenmapper.h"
0011 
0012 #include <QSignalSpy>
0013 #include <QTemporaryDir>
0014 #include <QTest>
0015 
0016 QTEST_MAIN(FolderModelTest)
0017 
0018 static const QLatin1String desktop(QLatin1String("Desktop"));
0019 
0020 static QUrl stringToUrl(const QString &path)
0021 {
0022     return QUrl::fromUserInput(path, {}, QUrl::AssumeLocalFile);
0023 }
0024 
0025 void FolderModelTest::createTestFolder(const QString &path)
0026 {
0027     QDir dir(m_folderDir->path());
0028     dir.mkdir(path);
0029     dir.cd(path);
0030     dir.mkdir(QStringLiteral("firstDir"));
0031     QFile f;
0032     for (int i = 1; i < 15; i++) {
0033         if (i < 10) {
0034             f.setFileName(QStringLiteral("%1/file%2.txt").arg(dir.path(), QString::number(i)));
0035         } else {
0036             f.setFileName(QStringLiteral("%1/.file%2.txt").arg(dir.path(), QString::number(i - 9)));
0037         }
0038 
0039         f.open(QFile::WriteOnly);
0040         f.close();
0041     }
0042 }
0043 
0044 void FolderModelTest::init()
0045 {
0046     m_currentActivity = QStringLiteral("00000000-0000-0000-0000-000000000000");
0047     m_folderDir = new QTemporaryDir();
0048     createTestFolder(desktop);
0049     m_folderModel = new FolderModel(this);
0050     m_folderModel->classBegin();
0051     m_folderModel->setUrl(m_folderDir->path() + QDir::separator() + desktop);
0052     m_folderModel->componentComplete();
0053     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
0054     s.wait(1000);
0055 }
0056 
0057 void FolderModelTest::cleanup()
0058 {
0059     delete m_folderDir;
0060     m_folderDir = nullptr;
0061     delete m_folderModel;
0062     m_folderModel = nullptr;
0063 }
0064 
0065 void FolderModelTest::tst_listing()
0066 {
0067     QCOMPARE(m_folderModel->url(), m_folderDir->path() + QDir::separator() + desktop);
0068 
0069     const auto count = m_folderModel->rowCount();
0070     QCOMPARE(count, 10);
0071     QCOMPARE(m_folderModel->index(0, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir"));
0072     for (int i = 1; i < count; i++) {
0073         const auto index = m_folderModel->index(i, 0);
0074         QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i));
0075     }
0076 }
0077 
0078 void FolderModelTest::tst_listingDescending()
0079 {
0080     m_folderModel->setSortDesc(true);
0081     QCOMPARE(m_folderModel->index(0, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir"));
0082     const auto count = m_folderModel->rowCount();
0083     for (int i = 1; i < count; i++) {
0084         const auto index = m_folderModel->index(i, 0);
0085         QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(count - i));
0086     }
0087 }
0088 
0089 void FolderModelTest::tst_listingFolderNotFirst()
0090 {
0091     const auto count = m_folderModel->rowCount();
0092     m_folderModel->setSortDirsFirst(false);
0093     QCOMPARE(count, 10);
0094     QCOMPARE(m_folderModel->index(9, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir"));
0095     for (int i = 0; i < count - 1; i++) {
0096         const auto index = m_folderModel->index(i, 0);
0097         QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i + 1));
0098     }
0099 }
0100 
0101 void FolderModelTest::tst_listingHidden()
0102 {
0103     m_folderModel->setShowHiddenFiles(true);
0104     const auto count = m_folderModel->rowCount();
0105     QCOMPARE(count, 15);
0106     QCOMPARE(m_folderModel->index(0, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir"));
0107     for (int i = 1; i < count; i++) {
0108         const auto index = m_folderModel->index(i, 0);
0109         QString fileName = index.data(FolderModel::FileNameRole).toString();
0110         // hidden files are listed first
0111         if (i <= 5) {
0112             QCOMPARE(fileName, QStringLiteral(".file%1.txt").arg(i));
0113         } else {
0114             QCOMPARE(fileName, QStringLiteral("file%1.txt").arg(i - 5));
0115         }
0116     }
0117 }
0118 
0119 void FolderModelTest::tst_filterListing()
0120 {
0121     // a little bit weird API, as both pattern and mimetype needs to be set
0122     m_folderModel->setFilterPattern(QStringLiteral("*.txt"));
0123     m_folderModel->setFilterMimeTypes(QStringList{QStringLiteral("all/all")});
0124     m_folderModel->setFilterMode(FolderModel::FilterShowMatches);
0125     const auto count = m_folderModel->rowCount();
0126     QCOMPARE(count, 9);
0127     for (int i = 0; i < count; i++) {
0128         const auto index = m_folderModel->index(i, 0);
0129         QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i + 1));
0130     }
0131 }
0132 
0133 void FolderModelTest::tst_cd()
0134 {
0135     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
0136 
0137     // go into firstDir subfolder
0138     const auto url = m_folderModel->resolvedUrl();
0139     m_folderModel->cd(0);
0140     QVERIFY(s.wait(500));
0141     const auto url2 = m_folderModel->resolvedUrl();
0142     QVERIFY(url.isParentOf(url2));
0143 
0144     // go back to Desktop
0145     m_folderModel->up();
0146     // The first signal might come from KCoreDirListerCache::emitItemsFromCache
0147     QVERIFY(s.wait(500));
0148     // The second signal comes from KCoreDirListerCache::slotUpdateResult
0149     s.wait(500);
0150     QCOMPARE(m_folderModel->resolvedUrl(), url);
0151 
0152     // try to cd to an invalid entry (a file)
0153     m_folderModel->cd(1);
0154     // Signal is not emitted here as it's invalided
0155     QVERIFY(!s.wait(500));
0156     QCOMPARE(m_folderModel->resolvedUrl(), url);
0157 }
0158 
0159 void FolderModelTest::tst_rename_data()
0160 {
0161     QTest::addColumn<int>("row");
0162     QTest::addColumn<QString>("name");
0163     QTest::newRow("Folder rename") << 0 << "firstDirRenamed";
0164     QTest::newRow("File rename") << 1 << "file1.pdf";
0165     QTest::newRow("Invalid rename") << 11 << "foo";
0166 }
0167 
0168 void FolderModelTest::tst_rename()
0169 {
0170     QFETCH(int, row);
0171     QFETCH(QString, name);
0172     m_folderModel->rename(row, name);
0173     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
0174     const auto index = m_folderModel->index(row, 0);
0175     s.wait(500);
0176     QEXPECT_FAIL("Invalid rename", "This is expected to fail", Continue);
0177     QCOMPARE(index.data(FolderModel::FileNameRole).toString(), name);
0178 }
0179 
0180 void FolderModelTest::tst_selection()
0181 {
0182     m_folderModel->setSelected(1);
0183     QVERIFY(m_folderModel->hasSelection());
0184     QVERIFY(m_folderModel->isSelected(1));
0185 
0186     m_folderModel->clearSelection();
0187     QVERIFY(!m_folderModel->hasSelection());
0188 
0189     m_folderModel->toggleSelected(1);
0190     QVERIFY(m_folderModel->isSelected(1));
0191     m_folderModel->toggleSelected(1);
0192     QVERIFY(!m_folderModel->isSelected(1));
0193 
0194     m_folderModel->setRangeSelected(1, 4);
0195     QVERIFY(m_folderModel->hasSelection());
0196     for (int i = 1; i <= 4; i++) {
0197         QVERIFY(m_folderModel->isSelected(i));
0198     }
0199 
0200     m_folderModel->updateSelection({5, 6}, false);
0201     for (int i = 1; i <= 4; i++) {
0202         QVERIFY(!m_folderModel->isSelected(i));
0203     }
0204     QVERIFY(m_folderModel->isSelected(5));
0205     QVERIFY(m_folderModel->isSelected(6));
0206 
0207     m_folderModel->setRangeSelected(1, 4);
0208     m_folderModel->pinSelection();
0209     m_folderModel->updateSelection({5, 6}, true);
0210     for (int i = 1; i <= 6; i++) {
0211         QVERIFY(m_folderModel->isSelected(i));
0212     }
0213 
0214     m_folderModel->unpinSelection();
0215     m_folderModel->updateSelection({5, 6}, true);
0216     for (int i = 1; i <= 6; i++) {
0217         if (i < 5) {
0218             QVERIFY(!m_folderModel->isSelected(i));
0219         } else {
0220             QVERIFY(m_folderModel->isSelected(i));
0221         }
0222     }
0223 }
0224 
0225 void FolderModelTest::tst_defaultValues()
0226 {
0227     FolderModel folderModel;
0228     QCOMPARE(folderModel.status(), FolderModel::Status::None);
0229     QVERIFY(folderModel.locked());
0230     QVERIFY(!folderModel.sortDesc());
0231     QVERIFY(folderModel.sortDirsFirst());
0232     QVERIFY(!folderModel.parseDesktopFiles());
0233     QVERIFY(!folderModel.previews());
0234     QVERIFY(!folderModel.usedByContainment());
0235     QCOMPARE(folderModel.sortMode(), 0);
0236     QCOMPARE(folderModel.filterMode(), (int)FolderModel::NoFilter);
0237     QVERIFY(folderModel.newMenu());
0238     QCOMPARE(folderModel.filterCaseSensitivity(), Qt::CaseInsensitive);
0239     QVERIFY(folderModel.dynamicSortFilter());
0240     QVERIFY(folderModel.isSortLocaleAware());
0241 }
0242 
0243 void FolderModelTest::tst_actionMenu()
0244 {
0245     const QStringList lst{QStringLiteral("open"),
0246                           QStringLiteral("cut"),
0247                           QStringLiteral("open"),
0248                           QStringLiteral("cut"),
0249                           QStringLiteral("undo"),
0250                           QStringLiteral("copy"),
0251                           QStringLiteral("paste"),
0252                           QStringLiteral("pasteto"),
0253                           QStringLiteral("refresh"),
0254                           QStringLiteral("rename"),
0255                           QStringLiteral("trash"),
0256                           QStringLiteral("del"),
0257                           QStringLiteral("restoreFromTrash"),
0258                           QStringLiteral("emptyTrash")};
0259     for (const QString &str : lst) {
0260         QVERIFY(m_folderModel->action(str));
0261     }
0262 }
0263 
0264 void FolderModelTest::tst_lockedChanged()
0265 {
0266     QSignalSpy s(m_folderModel, &FolderModel::lockedChanged);
0267     m_folderModel->setLocked(false);
0268     QCOMPARE(s.count(), 1);
0269     m_folderModel->setLocked(false);
0270     QCOMPARE(s.count(), 1);
0271     m_folderModel->setLocked(true);
0272     QCOMPARE(s.count(), 2);
0273 }
0274 
0275 void FolderModelTest::tst_multiScreen()
0276 {
0277     delete m_folderModel;
0278     // Custom instance for this test to set used by containment before marking component
0279     // as complete.
0280     m_folderModel = new FolderModel(this);
0281     m_folderModel->classBegin();
0282     m_folderModel->setUrl(m_folderDir->path() + QDir::separator() + desktop);
0283     m_folderModel->setUsedByContainment(true);
0284     m_folderModel->setScreen(0);
0285     m_folderModel->componentComplete();
0286 
0287     auto *screenMapper = ScreenMapper::instance();
0288 
0289     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
0290     QVERIFY(s.wait(1000));
0291     const auto count = m_folderModel->rowCount();
0292     for (int i = 0; i < count; i++) {
0293         const auto index = m_folderModel->index(i, 0);
0294         const auto name = index.data(FolderModel::UrlRole).toUrl();
0295         // all items are on the first screen by default
0296         QCOMPARE(screenMapper->screenForItem(name, m_currentActivity), 0);
0297     }
0298 
0299     // move one file to a new screen
0300     const auto movedItem = m_folderModel->index(0, 0).data(FolderModel::UrlRole).toUrl();
0301     FolderModel secondFolderModel;
0302     secondFolderModel.classBegin();
0303     secondFolderModel.setUrl(m_folderDir->path() + QDir::separator() + desktop);
0304     secondFolderModel.setUsedByContainment(true);
0305     secondFolderModel.setScreen(1);
0306     secondFolderModel.componentComplete();
0307     QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted);
0308     QVERIFY(s2.wait(1000));
0309     const auto count2 = secondFolderModel.rowCount();
0310     QCOMPARE(count2, 0);
0311 
0312     screenMapper->addMapping(movedItem, 1, m_currentActivity);
0313     m_folderModel->invalidate();
0314     secondFolderModel.invalidate();
0315     s.wait(1000);
0316     s2.wait(1000);
0317     // we have one less item
0318     QCOMPARE(m_folderModel->rowCount(), count - 1);
0319     QCOMPARE(secondFolderModel.rowCount(), 1);
0320     QCOMPARE(secondFolderModel.index(0, 0).data(FolderModel::UrlRole).toUrl(), movedItem);
0321     QCOMPARE(screenMapper->screenForItem(movedItem, m_currentActivity), 1);
0322 
0323     // remove extra screen, we have all items back
0324     screenMapper->removeScreen(1, m_currentActivity, stringToUrl(m_folderModel->url()));
0325     s.wait(500);
0326     QCOMPARE(m_folderModel->rowCount(), count);
0327     QCOMPARE(secondFolderModel.rowCount(), 0);
0328     QCOMPARE(screenMapper->screenForItem(movedItem, m_currentActivity), 0);
0329 
0330     // add back extra screen, the item is moved there
0331     screenMapper->addScreen(1, m_currentActivity, stringToUrl(m_folderModel->url()));
0332     s.wait(500);
0333     s2.wait(500);
0334     QCOMPARE(m_folderModel->rowCount(), count - 1);
0335     QCOMPARE(secondFolderModel.rowCount(), 1);
0336     QCOMPARE(secondFolderModel.index(0, 0).data(FolderModel::UrlRole).toUrl(), movedItem);
0337     QCOMPARE(screenMapper->screenForItem(movedItem, m_currentActivity), 1);
0338 
0339     // create a new item, it appears on the first screen
0340     QDir dir(m_folderDir->path());
0341     dir.cd(desktop);
0342     dir.mkdir(QStringLiteral("secondDir"));
0343     dir.cd(QStringLiteral("secondDir"));
0344     s.wait(1000);
0345     QCOMPARE(m_folderModel->rowCount(), count);
0346     QCOMPARE(secondFolderModel.rowCount(), 1);
0347     QCOMPARE(screenMapper->screenForItem(stringToUrl(QLatin1String("file://") + dir.path()), m_currentActivity), 0);
0348 }
0349 
0350 void FolderModelTest::tst_multiScreenDifferenPath()
0351 {
0352     m_folderModel->setUsedByContainment(true);
0353     m_folderModel->setScreen(0);
0354     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
0355     s.wait(1000);
0356     const auto count = m_folderModel->rowCount();
0357     QCOMPARE(count, 10);
0358 
0359     const QLatin1String desktop2(QLatin1String("Desktop2"));
0360     createTestFolder(desktop2);
0361     FolderModel secondFolderModel;
0362     secondFolderModel.setUsedByContainment(true);
0363     secondFolderModel.setUrl(m_folderDir->path() + QDir::separator() + desktop2);
0364     secondFolderModel.setScreen(1);
0365     QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted);
0366     s2.wait(1000);
0367     const auto count2 = secondFolderModel.rowCount();
0368     QCOMPARE(count2, 10);
0369 
0370     // create a new item, it appears on the first screen
0371     QDir dir(m_folderDir->path());
0372     dir.cd(desktop);
0373     dir.mkdir(QStringLiteral("secondDir"));
0374     s.wait(1000);
0375     QCOMPARE(m_folderModel->rowCount(), count + 1);
0376     QCOMPARE(secondFolderModel.rowCount(), count2);
0377 
0378     // create a new item, it appears on the second screen
0379     dir.cd(m_folderDir->path() + QDir::separator() + desktop2);
0380     dir.mkdir(QStringLiteral("secondDir2"));
0381     s.wait(1000);
0382     QCOMPARE(m_folderModel->rowCount(), count + 1);
0383     QCOMPARE(secondFolderModel.rowCount(), count2 + 1);
0384 }