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 }