File indexing completed on 2024-10-06 12:21:14
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-only 0006 */ 0007 0008 #include <QDBusInterface> 0009 #include <QDebug> 0010 #include <QObject> 0011 #include <QSignalSpy> 0012 #include <QTemporaryDir> 0013 #include <QTest> 0014 0015 #include <KBookmark> 0016 #include <KBookmarkManager> 0017 #include <KConfig> 0018 #include <KConfigGroup> 0019 #include <KProtocolInfo> 0020 #include <QStandardPaths> 0021 #include <kfileplacesmodel.h> 0022 #include <solid/device.h> 0023 0024 #include <stdlib.h> 0025 0026 Q_DECLARE_METATYPE(KFilePlacesModel::GroupType) 0027 0028 // Avoid QHash randomization so that the order of the devices is stable 0029 static void seedInit() 0030 { 0031 qputenv("QT_HASH_SEED", "0"); 0032 // This env var has no effect because this comes too late. qCpuFeatures() was already called by 0033 // a Q_CONSTRUCTOR_FUNCTION inside QtGui (see image/qimage_conversions.cpp). Argh. QTBUG-47566. 0034 qputenv("QT_NO_CPU_FEATURE", "sse4.2"); 0035 } 0036 Q_CONSTRUCTOR_FUNCTION(seedInit) 0037 0038 class KFilePlacesModelTest : public QObject 0039 { 0040 Q_OBJECT 0041 0042 private Q_SLOTS: 0043 void initTestCase(); 0044 void cleanupTestCase(); 0045 0046 void testInitialList(); 0047 void testAddingInLaterVersion_data(); 0048 void testAddingInLaterVersion(); 0049 void testReparse(); 0050 void testInternalBookmarksHaveIds(); 0051 void testHiding(); 0052 void testMove(); 0053 void testPlacesLifecycle(); 0054 void testDevicePlugging(); 0055 void testDragAndDrop(); 0056 void testDeviceSetupTeardown(); 0057 void testEnableBaloo(); 0058 void testRemoteUrls_data(); 0059 void testRemoteUrls(); 0060 void testRefresh(); 0061 void testConvertedUrl_data(); 0062 void testConvertedUrl(); 0063 void testBookmarkObject(); 0064 void testDataChangedSignal(); 0065 void testIconRole_data(); 0066 void testIconRole(); 0067 void testMoveFunction(); 0068 void testPlaceGroupHidden(); 0069 void testPlaceGroupHiddenVsPlaceChildShown(); 0070 void testPlaceGroupHiddenAndShownWithHiddenChild(); 0071 void testPlaceGroupHiddenGroupIndexesIntegrity(); 0072 void testPlaceGroupHiddenSignal(); 0073 void testPlaceGroupHiddenRole(); 0074 void testFilterWithAlternativeApplicationName(); 0075 void testSupportedSchemes(); 0076 0077 private: 0078 QStringList placesUrls(KFilePlacesModel *model = nullptr) const; 0079 QDBusInterface *fakeManager(); 0080 QDBusInterface *fakeDevice(const QString &udi); 0081 void createPlacesModels(); 0082 0083 KFilePlacesModel *m_places; 0084 KFilePlacesModel *m_places2; // To check that they always stay in sync 0085 // actually supposed to work across processes, 0086 // but much harder to test 0087 0088 QMap<QString, QDBusInterface *> m_interfacesMap; 0089 QTemporaryDir m_tmpHome; 0090 bool m_hasRecentlyUsedKio; 0091 }; 0092 0093 static QString bookmarksFile() 0094 { 0095 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/user-places.xbel"); 0096 } 0097 0098 void KFilePlacesModelTest::initTestCase() 0099 { 0100 QVERIFY(m_tmpHome.isValid()); 0101 qputenv("HOME", m_tmpHome.path().toUtf8()); // use a empty home dir 0102 0103 QStandardPaths::setTestModeEnabled(true); 0104 0105 // Ensure we'll have a clean bookmark file to start 0106 QFile::remove(bookmarksFile()); 0107 0108 // disable baloo by default 0109 KConfig config(QStringLiteral("baloofilerc")); 0110 KConfigGroup basicSettings = config.group("Basic Settings"); 0111 basicSettings.writeEntry("Indexing-Enabled", false); 0112 config.sync(); 0113 0114 qRegisterMetaType<QModelIndex>(); 0115 qRegisterMetaType<KFilePlacesModel::GroupType>(); 0116 0117 const QString fakeHw = QFINDTESTDATA("fakecomputer.xml"); 0118 QVERIFY(!fakeHw.isEmpty()); 0119 qputenv("SOLID_FAKEHW", QFile::encodeName(fakeHw)); 0120 m_hasRecentlyUsedKio = qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused")); 0121 0122 createPlacesModels(); 0123 } 0124 0125 void KFilePlacesModelTest::createPlacesModels() 0126 { 0127 KBookmarkManager *mgr = KBookmarkManager::managerForExternalFile(bookmarksFile()); 0128 QSignalSpy spy(mgr, &KBookmarkManager::changed); 0129 m_places = new KFilePlacesModel(); 0130 m_places2 = new KFilePlacesModel(); 0131 0132 // When the xbel file is empty, KFilePlacesModel fills it with 3 default items 0133 // 5 when KIO worker recentlyused:/ is installed 0134 QCOMPARE(m_places->rowCount(), m_hasRecentlyUsedKio ? 5 : 3); 0135 0136 QVERIFY(spy.wait()); 0137 0138 // Devices have a delayed loading. Waiting for KDirWatch also waits for that to happen 0139 QCOMPARE(m_places->rowCount(), m_hasRecentlyUsedKio ? 10 : 8); 0140 } 0141 0142 void KFilePlacesModelTest::cleanupTestCase() 0143 { 0144 delete m_places; 0145 delete m_places2; 0146 qDeleteAll(m_interfacesMap); 0147 QFile::remove(bookmarksFile()); 0148 } 0149 0150 QStringList KFilePlacesModelTest::placesUrls(KFilePlacesModel *model) const 0151 { 0152 KFilePlacesModel *currentModel = model; 0153 if (!currentModel) { 0154 currentModel = m_places; 0155 } 0156 QStringList urls; 0157 for (int row = 0; row < currentModel->rowCount(); ++row) { 0158 QModelIndex index = currentModel->index(row, 0); 0159 urls << currentModel->url(index).toDisplayString(QUrl::PreferLocalFile); 0160 } 0161 return urls; 0162 } 0163 0164 /* clang-format off */ 0165 #define CHECK_PLACES_URLS(urls) \ 0166 if (placesUrls() != urls) { \ 0167 qDebug() << "Expected:" << urls; \ 0168 qDebug() << "Got:" << placesUrls(); \ 0169 QCOMPARE(placesUrls(), urls); \ 0170 } \ 0171 for (int row = 0; row < urls.size(); ++row) { \ 0172 QModelIndex index = m_places->index(row, 0); \ 0173 \ 0174 QCOMPARE(m_places->url(index).toString(), QUrl::fromUserInput(urls[row]).toString()); \ 0175 QCOMPARE(m_places->data(index, KFilePlacesModel::UrlRole).toUrl(), QUrl(m_places->url(index))); \ 0176 \ 0177 index = m_places2->index(row, 0); \ 0178 \ 0179 QCOMPARE(m_places2->url(index).toString(), QUrl::fromUserInput(urls[row]).toString()); \ 0180 QCOMPARE(m_places2->data(index, KFilePlacesModel::UrlRole).toUrl(), QUrl(m_places2->url(index))); \ 0181 } \ 0182 \ 0183 QCOMPARE(urls.size(), m_places->rowCount()); \ 0184 QCOMPARE(urls.size(), m_places2->rowCount()); 0185 /*clang-format on */ 0186 0187 QDBusInterface *KFilePlacesModelTest::fakeManager() 0188 { 0189 return fakeDevice(QStringLiteral("/org/kde/solid/fakehw")); 0190 } 0191 0192 QDBusInterface *KFilePlacesModelTest::fakeDevice(const QString &udi) 0193 { 0194 QDBusInterface *interface = m_interfacesMap[udi]; 0195 if (interface) { 0196 return interface; 0197 } 0198 0199 QDBusInterface *iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), udi); 0200 m_interfacesMap[udi] = iface; 0201 0202 return iface; 0203 } 0204 0205 static const QStringList initialListOfPlaces() 0206 { 0207 return QStringList{QDir::homePath(), QStringLiteral("trash:/")}; 0208 } 0209 0210 static const QStringList initialListOfShared() 0211 { 0212 return QStringList{QStringLiteral("remote:/"), QStringLiteral("/media/nfs")}; 0213 } 0214 0215 static const QStringList initialListOfRecent() 0216 { 0217 auto list = QStringList(); 0218 if (qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) { 0219 list << QStringLiteral("recentlyused:/files"); 0220 list << QStringLiteral("recentlyused:/locations"); 0221 } 0222 return list; 0223 } 0224 0225 static const QStringList initialListOfDevices() 0226 { 0227 return QStringList{QStringLiteral("/foreign")}; 0228 } 0229 0230 static const QStringList initialListOfRemovableDevices() 0231 { 0232 return QStringList{QStringLiteral("/media/floppy0"), QStringLiteral("/media/XO-Y4"), QStringLiteral("/media/cdrom")}; 0233 } 0234 0235 static const QStringList initialListOfUrls() 0236 { 0237 return QStringList() << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() 0238 << initialListOfRemovableDevices(); 0239 } 0240 0241 void KFilePlacesModelTest::testInitialList() 0242 { 0243 const QStringList urls = initialListOfUrls(); 0244 CHECK_PLACES_URLS(urls); 0245 } 0246 0247 void KFilePlacesModelTest::testAddingInLaterVersion_data() 0248 { 0249 QTest::addColumn<QByteArray>("contents"); 0250 QTest::addColumn<QStringList>("expectedUrls"); 0251 0252 // Create a places file with only Home in it, and no version number 0253 static const char contentsPart1[] = 0254 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 0255 "<xbel xmlns:bookmark=\"http://www.freedesktop.org/standards/desktop-bookmarks\">\n"; 0256 0257 static const char versionXml[] = 0258 " <info>\n" 0259 " <metadata owner=\"http://www.kde.org\">\n" 0260 " <kde_places_version>2</kde_places_version>\n" 0261 " </metadata>\n" 0262 " </info>\n"; 0263 0264 static const char contentsPart2[] = 0265 " <bookmark href=\"trash:/\">\n" 0266 " <title>Home</title>\n" 0267 " <info>\n" 0268 " <metadata owner=\"http://freedesktop.org\">\n" 0269 " <bookmark:icon name=\"user-home\"/>\n" 0270 " </metadata>\n" 0271 " <metadata owner=\"http://www.kde.org\">\n" 0272 " <ID>1481703882/0</ID>\n" 0273 " <isSystemItem>true</isSystemItem>\n" 0274 " </metadata>\n" 0275 " </info>\n" 0276 " </bookmark>\n" 0277 "</xbel>"; 0278 0279 // No version key: KFilePlacesModel will add the missing entries: home and remote 0280 // Just not in the usual order 0281 QStringList expectedWithReorder = initialListOfUrls(); 0282 expectedWithReorder.move(1, 0); 0283 QTest::newRow("just_home_no_version") << (QByteArray(contentsPart1) + contentsPart2) << expectedWithReorder; 0284 0285 // Existing version key: home and remote were removed by the user, leave them out 0286 QStringList expectedUrls{QStringLiteral("trash:/")}; 0287 expectedUrls << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 0288 QVERIFY(expectedUrls.removeOne(QStringLiteral("remote:/"))); 0289 QTest::newRow("just_home_version_2") << (QByteArray(contentsPart1) + versionXml + contentsPart2) << expectedUrls; 0290 } 0291 0292 void KFilePlacesModelTest::testAddingInLaterVersion() 0293 { 0294 QFETCH(QByteArray, contents); 0295 QFETCH(QStringList, expectedUrls); 0296 0297 // Avoid interference 0298 delete m_places; 0299 delete m_places2; 0300 QCoreApplication::processEvents(); 0301 0302 KBookmarkManager *mgr = KBookmarkManager::managerForExternalFile(bookmarksFile()); 0303 0304 auto cleanupFunc = [this, mgr]() { 0305 QFile::remove(bookmarksFile()); 0306 // let KDirWatch process the deletion 0307 QTRY_VERIFY(mgr->root().first().isNull()); 0308 createPlacesModels(); 0309 testInitialList(); 0310 }; 0311 struct Cleanup { 0312 explicit Cleanup(const std::function<void()> &f) 0313 : func(f) 0314 { 0315 } 0316 ~Cleanup() 0317 { 0318 func(); 0319 } 0320 std::function<void()> func; 0321 } cleanup(cleanupFunc); 0322 0323 QTest::qWait(1000); // for KDirWatch 0324 QSignalSpy spy(mgr, &KBookmarkManager::changed); 0325 0326 // WHEN 0327 QFile file(bookmarksFile()); 0328 QVERIFY(file.open(QIODevice::WriteOnly)); 0329 file.write(contents); 0330 file.close(); 0331 QVERIFY(spy.wait()); 0332 0333 // THEN 0334 KFilePlacesModel model; 0335 QCoreApplication::processEvents(); // Devices have a delayed loading 0336 0337 if (placesUrls(&model) != expectedUrls) { 0338 qDebug() << "Expected:" << expectedUrls; 0339 qDebug() << "Got:" << placesUrls(&model); 0340 QCOMPARE(placesUrls(&model), expectedUrls); 0341 } 0342 } 0343 0344 void KFilePlacesModelTest::testReparse() 0345 { 0346 // add item 0347 m_places->addPlace(QStringLiteral("foo"), QUrl::fromLocalFile(QStringLiteral("/foo")), QString(), QString()); 0348 0349 QStringList urls = initialListOfUrls(); 0350 // it will be added at the end of places section 0351 urls.insert(2, QStringLiteral("/foo")); 0352 CHECK_PLACES_URLS(urls); 0353 0354 // reparse the bookmark file 0355 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0356 bookmarkManager->notifyCompleteChange(QString()); 0357 0358 // check if they are the same 0359 CHECK_PLACES_URLS(urls); 0360 0361 // try to remove item 0362 m_places->removePlace(m_places->index(2, 0)); 0363 0364 urls = initialListOfUrls(); 0365 CHECK_PLACES_URLS(urls); 0366 } 0367 0368 void KFilePlacesModelTest::testInternalBookmarksHaveIds() 0369 { 0370 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0371 KBookmarkGroup root = bookmarkManager->root(); 0372 0373 // Verify every entry has an id or an udi 0374 KBookmark bookmark = root.first(); 0375 while (!bookmark.isNull()) { 0376 QVERIFY(!bookmark.metaDataItem(QStringLiteral("ID")).isEmpty() || !bookmark.metaDataItem(QStringLiteral("UDI")).isEmpty()); 0377 // It's mutually exclusive though 0378 QVERIFY(bookmark.metaDataItem(QStringLiteral("ID")).isEmpty() || bookmark.metaDataItem(QStringLiteral("UDI")).isEmpty()); 0379 0380 bookmark = root.next(bookmark); 0381 } 0382 0383 // Verify that adding a bookmark behind its back the model gives it an id 0384 // (in real life it requires the user to modify the file by hand, 0385 // unlikely but better safe than sorry). 0386 // It induces a small race condition which means several ids will be 0387 // successively set on the same bookmark but no big deal since it won't 0388 // break the system 0389 KBookmark foo = root.addBookmark(QStringLiteral("Foo"), QUrl(QStringLiteral("file:/foo")), QStringLiteral("red-folder")); 0390 QCOMPARE(foo.text(), QStringLiteral("Foo")); 0391 QVERIFY(foo.metaDataItem(QStringLiteral("ID")).isEmpty()); 0392 bookmarkManager->emitChanged(root); 0393 QCOMPARE(foo.text(), QStringLiteral("Foo")); 0394 QVERIFY(!foo.metaDataItem(QStringLiteral("ID")).isEmpty()); 0395 0396 // Verify that all the ids are different 0397 bookmark = root.first(); 0398 QSet<QString> ids; 0399 while (!bookmark.isNull()) { 0400 QString id; 0401 if (!bookmark.metaDataItem(QStringLiteral("UDI")).isEmpty()) { 0402 id = bookmark.metaDataItem(QStringLiteral("UDI")); 0403 } else { 0404 id = bookmark.metaDataItem(QStringLiteral("ID")); 0405 } 0406 0407 if (ids.contains(id)) { 0408 // Some debugging help 0409 qDebug() << "Bookmarks file:" << bookmarksFile() << "contains one (or more) duplicated bookmarks:"; 0410 QFile debugFile(bookmarksFile()); 0411 QVERIFY(debugFile.open(QIODevice::ReadOnly)); 0412 qDebug() << QString::fromUtf8(debugFile.readAll()); 0413 QVERIFY2(!ids.contains(id), qPrintable("Duplicated ID found: " + id)); 0414 } 0415 ids << id; 0416 bookmark = root.next(bookmark); 0417 } 0418 0419 // Cleanup foo 0420 root.deleteBookmark(foo); 0421 bookmarkManager->emitChanged(root); 0422 } 0423 0424 void KFilePlacesModelTest::testHiding() 0425 { 0426 // Verify that nothing is hidden 0427 for (int row = 0; row < m_places->rowCount(); ++row) { 0428 QModelIndex index = m_places->index(row, 0); 0429 QVERIFY(!m_places->isHidden(index)); 0430 } 0431 0432 QModelIndex a = m_places->index(2, 0); 0433 QModelIndex b = m_places->index(6, 0); 0434 0435 QList<QVariant> args; 0436 QSignalSpy spy(m_places, &QAbstractItemModel::dataChanged); 0437 0438 // Verify that hidden is taken into account and is not global 0439 m_places->setPlaceHidden(a, true); 0440 QVERIFY(m_places->isHidden(a)); 0441 QVERIFY(m_places->data(a, KFilePlacesModel::HiddenRole).toBool()); 0442 QVERIFY(!m_places->isHidden(b)); 0443 QVERIFY(!m_places->data(b, KFilePlacesModel::HiddenRole).toBool()); 0444 QCOMPARE(spy.count(), 1); 0445 args = spy.takeFirst(); 0446 QCOMPARE(args.at(0).toModelIndex(), a); 0447 QCOMPARE(args.at(1).toModelIndex(), a); 0448 0449 m_places->setPlaceHidden(b, true); 0450 QVERIFY(m_places->isHidden(a)); 0451 QVERIFY(m_places->data(a, KFilePlacesModel::HiddenRole).toBool()); 0452 QVERIFY(m_places->isHidden(b)); 0453 QVERIFY(m_places->data(b, KFilePlacesModel::HiddenRole).toBool()); 0454 QCOMPARE(spy.count(), 1); 0455 args = spy.takeFirst(); 0456 QCOMPARE(args.at(0).toModelIndex(), b); 0457 QCOMPARE(args.at(1).toModelIndex(), b); 0458 0459 m_places->setPlaceHidden(a, false); 0460 m_places->setPlaceHidden(b, false); 0461 QVERIFY(!m_places->isHidden(a)); 0462 QVERIFY(!m_places->data(a, KFilePlacesModel::HiddenRole).toBool()); 0463 QVERIFY(!m_places->isHidden(b)); 0464 QVERIFY(!m_places->data(b, KFilePlacesModel::HiddenRole).toBool()); 0465 QCOMPARE(spy.count(), 2); 0466 args = spy.takeFirst(); 0467 QCOMPARE(args.at(0).toModelIndex(), a); 0468 QCOMPARE(args.at(1).toModelIndex(), a); 0469 args = spy.takeFirst(); 0470 QCOMPARE(args.at(0).toModelIndex(), b); 0471 QCOMPARE(args.at(1).toModelIndex(), b); 0472 } 0473 0474 void KFilePlacesModelTest::testMove() 0475 { 0476 QList<QVariant> args; 0477 QSignalSpy spy_inserted(m_places, &QAbstractItemModel::rowsInserted); 0478 QSignalSpy spy_removed(m_places, &QAbstractItemModel::rowsRemoved); 0479 0480 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0481 KBookmarkGroup root = bookmarkManager->root(); 0482 0483 KBookmark system_home = m_places->bookmarkForIndex(m_places->index(0, 0)); 0484 0485 // Trying move the root at the end of the list, should move it to the end of places section instead 0486 // to keep it grouped 0487 KBookmark last = root.first(); 0488 while (!root.next(last).isNull()) { 0489 last = root.next(last); 0490 } 0491 root.moveBookmark(system_home, last); 0492 bookmarkManager->emitChanged(root); 0493 0494 QStringList urls; 0495 urls << QStringLiteral("trash:/") << QDir::homePath() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() 0496 << initialListOfRemovableDevices(); 0497 0498 CHECK_PLACES_URLS(urls); 0499 QCOMPARE(spy_inserted.count(), 1); 0500 args = spy_inserted.takeFirst(); 0501 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0502 QCOMPARE(args.at(1).toInt(), 1); 0503 QCOMPARE(args.at(2).toInt(), 1); 0504 QCOMPARE(spy_removed.count(), 1); 0505 args = spy_removed.takeFirst(); 0506 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0507 QCOMPARE(args.at(1).toInt(), 0); 0508 QCOMPARE(args.at(2).toInt(), 0); 0509 0510 // Move home at the beginning of the list (at its original place) 0511 root.moveBookmark(system_home, KBookmark()); 0512 bookmarkManager->emitChanged(root); 0513 urls.clear(); 0514 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 0515 CHECK_PLACES_URLS(urls); 0516 QCOMPARE(spy_inserted.count(), 1); 0517 args = spy_inserted.takeFirst(); 0518 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0519 QCOMPARE(args.at(1).toInt(), 1); 0520 QCOMPARE(args.at(2).toInt(), 1); 0521 QCOMPARE(spy_removed.count(), 1); 0522 args = spy_removed.takeFirst(); 0523 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0524 QCOMPARE(args.at(1).toInt(), 0); 0525 QCOMPARE(args.at(2).toInt(), 0); 0526 } 0527 0528 void KFilePlacesModelTest::testDragAndDrop() 0529 { 0530 QList<QVariant> args; 0531 QSignalSpy spy_moved(m_places, &QAbstractItemModel::rowsMoved); 0532 0533 // Monitor rowsInserted() and rowsRemoved() to ensure they are never emitted: 0534 // Moving with drag and drop is expected to emit rowsMoved() 0535 QSignalSpy spy_inserted(m_places, &QAbstractItemModel::rowsInserted); 0536 QSignalSpy spy_removed(m_places, &QAbstractItemModel::rowsRemoved); 0537 0538 // Move /home at the end of the places list 0539 QModelIndexList indexes; 0540 indexes << m_places->index(0, 0); 0541 QMimeData *mimeData = m_places->mimeData(indexes); 0542 QVERIFY(m_places->dropMimeData(mimeData, Qt::MoveAction, 2, 0, QModelIndex())); 0543 0544 QStringList urls; 0545 urls << QStringLiteral("trash:/") << QDir::homePath() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() 0546 << initialListOfRemovableDevices(); 0547 CHECK_PLACES_URLS(urls); 0548 QCOMPARE(spy_inserted.count(), 0); 0549 QCOMPARE(spy_removed.count(), 0); 0550 QCOMPARE(spy_moved.count(), 1); 0551 args = spy_moved.takeFirst(); 0552 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0553 QCOMPARE(args.at(1).toInt(), 0); 0554 QCOMPARE(args.at(2).toInt(), 0); 0555 QCOMPARE(args.at(3).toModelIndex(), QModelIndex()); 0556 QCOMPARE(args.at(4).toInt(), 2); 0557 0558 // Move home back at the beginning of the list 0559 indexes.clear(); 0560 indexes << m_places->index(1, 0); 0561 mimeData = m_places->mimeData(indexes); 0562 QVERIFY(m_places->dropMimeData(mimeData, Qt::MoveAction, 0, 0, QModelIndex())); 0563 0564 urls.clear(); 0565 urls << QDir::homePath() << QStringLiteral("trash:/") << initialListOfShared() << initialListOfRecent() << initialListOfDevices() 0566 << initialListOfRemovableDevices(); 0567 CHECK_PLACES_URLS(urls); 0568 QCOMPARE(spy_inserted.count(), 0); 0569 QCOMPARE(spy_removed.count(), 0); 0570 QCOMPARE(spy_moved.count(), 1); 0571 args = spy_moved.takeFirst(); 0572 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0573 QCOMPARE(args.at(1).toInt(), 1); 0574 QCOMPARE(args.at(2).toInt(), 1); 0575 QCOMPARE(args.at(3).toModelIndex(), QModelIndex()); 0576 QCOMPARE(args.at(4).toInt(), 0); 0577 0578 // Dropping on an item is not allowed 0579 indexes.clear(); 0580 indexes << m_places->index(4, 0); 0581 mimeData = m_places->mimeData(indexes); 0582 QVERIFY(!m_places->dropMimeData(mimeData, Qt::MoveAction, -1, 0, m_places->index(2, 0))); 0583 CHECK_PLACES_URLS(urls); 0584 QCOMPARE(spy_inserted.count(), 0); 0585 QCOMPARE(spy_removed.count(), 0); 0586 QCOMPARE(spy_moved.count(), 0); 0587 } 0588 0589 void KFilePlacesModelTest::testPlacesLifecycle() 0590 { 0591 QList<QVariant> args; 0592 QSignalSpy spy_inserted(m_places, &QAbstractItemModel::rowsInserted); 0593 QSignalSpy spy_removed(m_places, &QAbstractItemModel::rowsRemoved); 0594 QSignalSpy spy_changed(m_places, &QAbstractItemModel::dataChanged); 0595 0596 m_places->addPlace(QStringLiteral("Foo"), QUrl::fromLocalFile(QStringLiteral("/home/foo"))); 0597 0598 QStringList urls; 0599 urls << initialListOfPlaces() << QStringLiteral("/home/foo") << initialListOfShared() << initialListOfRecent() << initialListOfDevices() 0600 << initialListOfRemovableDevices(); 0601 CHECK_PLACES_URLS(urls); 0602 QCOMPARE(spy_inserted.count(), 1); 0603 args = spy_inserted.takeFirst(); 0604 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0605 QCOMPARE(args.at(1).toInt(), 2); 0606 QCOMPARE(args.at(2).toInt(), 2); 0607 QCOMPARE(spy_removed.count(), 0); 0608 0609 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0610 KBookmarkGroup root = bookmarkManager->root(); 0611 KBookmark before_trash = m_places->bookmarkForIndex(m_places->index(0, 0)); 0612 KBookmark foo = m_places->bookmarkForIndex(m_places->index(2, 0)); 0613 0614 root.moveBookmark(foo, before_trash); 0615 bookmarkManager->emitChanged(root); 0616 0617 urls.clear(); 0618 urls << QDir::homePath() << QStringLiteral("/home/foo") << QStringLiteral("trash:/") << initialListOfShared() << initialListOfRecent() 0619 << initialListOfDevices() << initialListOfRemovableDevices(); 0620 CHECK_PLACES_URLS(urls); 0621 QCOMPARE(spy_inserted.count(), 1); 0622 args = spy_inserted.takeFirst(); 0623 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0624 QCOMPARE(args.at(1).toInt(), 2); 0625 QCOMPARE(args.at(2).toInt(), 2); 0626 QCOMPARE(spy_removed.count(), 1); 0627 args = spy_removed.takeFirst(); 0628 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0629 QCOMPARE(args.at(1).toInt(), 1); 0630 QCOMPARE(args.at(2).toInt(), 1); 0631 0632 m_places->editPlace(m_places->index(1, 0), QStringLiteral("Foo"), QUrl::fromLocalFile(QStringLiteral("/mnt/foo"))); 0633 0634 urls.clear(); 0635 urls << QDir::homePath() << QStringLiteral("/mnt/foo") << QStringLiteral("trash:/") << initialListOfShared() << initialListOfRecent() 0636 << initialListOfDevices() << initialListOfRemovableDevices(); 0637 CHECK_PLACES_URLS(urls); 0638 QCOMPARE(spy_inserted.count(), 0); 0639 QCOMPARE(spy_removed.count(), 0); 0640 QCOMPARE(spy_changed.count(), 1); 0641 args = spy_changed.takeFirst(); 0642 QCOMPARE(args.at(0).toModelIndex(), m_places->index(1, 0)); 0643 QCOMPARE(args.at(1).toModelIndex(), m_places->index(1, 0)); 0644 0645 foo = m_places->bookmarkForIndex(m_places->index(1, 0)); 0646 foo.setFullText(QStringLiteral("Bar")); 0647 bookmarkManager->notifyCompleteChange(QString()); 0648 0649 urls.clear(); 0650 urls << QDir::homePath() << QStringLiteral("/mnt/foo") << QStringLiteral("trash:/") << initialListOfShared() << initialListOfRecent() 0651 << initialListOfDevices() << initialListOfRemovableDevices(); 0652 0653 CHECK_PLACES_URLS(urls); 0654 QCOMPARE(spy_inserted.count(), 0); 0655 QCOMPARE(spy_removed.count(), 0); 0656 QCOMPARE(spy_changed.count(), m_hasRecentlyUsedKio ? 11 : 9); 0657 args = spy_changed[2]; 0658 QCOMPARE(args.at(0).toModelIndex(), m_places->index(2, 0)); 0659 QCOMPARE(args.at(1).toModelIndex(), m_places->index(2, 0)); 0660 spy_changed.clear(); 0661 0662 m_places->removePlace(m_places->index(1, 0)); 0663 0664 urls.clear(); 0665 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 0666 CHECK_PLACES_URLS(urls); 0667 QCOMPARE(spy_inserted.count(), 0); 0668 QCOMPARE(spy_removed.count(), 1); 0669 args = spy_removed.takeFirst(); 0670 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0671 QCOMPARE(args.at(1).toInt(), 1); 0672 QCOMPARE(args.at(2).toInt(), 1); 0673 0674 m_places->addPlace(QStringLiteral("Foo"), QUrl::fromLocalFile(QStringLiteral("/home/foo")), QString(), QString(), m_places->index(0, 0)); 0675 0676 urls.clear(); 0677 urls << QDir::homePath() << QStringLiteral("/home/foo") << QStringLiteral("trash:/") << initialListOfShared() << initialListOfRecent() 0678 << initialListOfDevices() << initialListOfRemovableDevices(); 0679 CHECK_PLACES_URLS(urls); 0680 QCOMPARE(spy_inserted.count(), 1); 0681 args = spy_inserted.takeFirst(); 0682 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0683 QCOMPARE(args.at(1).toInt(), 1); 0684 QCOMPARE(args.at(2).toInt(), 1); 0685 QCOMPARE(spy_removed.count(), 0); 0686 0687 m_places->removePlace(m_places->index(1, 0)); 0688 } 0689 0690 void KFilePlacesModelTest::testDevicePlugging() 0691 { 0692 QList<QVariant> args; 0693 QSignalSpy spy_inserted(m_places, &QAbstractItemModel::rowsInserted); 0694 QSignalSpy spy_removed(m_places, &QAbstractItemModel::rowsRemoved); 0695 0696 fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); 0697 0698 QStringList urls; 0699 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/floppy0") 0700 << QStringLiteral("/media/cdrom"); 0701 CHECK_PLACES_URLS(urls); 0702 QCOMPARE(spy_inserted.count(), 0); 0703 QCOMPARE(spy_removed.count(), 1); 0704 args = spy_removed.takeFirst(); 0705 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0706 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0707 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0708 0709 fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); 0710 0711 urls.clear(); 0712 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 0713 CHECK_PLACES_URLS(urls); 0714 QCOMPARE(spy_inserted.count(), 1); 0715 args = spy_inserted.takeFirst(); 0716 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0717 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0718 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0719 QCOMPARE(spy_removed.count(), 0); 0720 0721 // Move the device in the list, and check that it memorizes the position across plug/unplug 0722 0723 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0724 KBookmarkGroup root = bookmarkManager->root(); 0725 KBookmark before_floppy; 0726 0727 KBookmark device = root.first(); // The device we'll move is the 6th bookmark 0728 const int count = m_hasRecentlyUsedKio ? 7 : 5; 0729 for (int i = 0; i < count; i++) { 0730 if (i == 2) { 0731 // store item before to be able to move it back to original position 0732 device = before_floppy = root.next(device); 0733 } else { 0734 device = root.next(device); 0735 } 0736 } 0737 0738 root.moveBookmark(device, before_floppy); 0739 bookmarkManager->emitChanged(root); 0740 0741 urls.clear(); 0742 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/XO-Y4") 0743 << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); 0744 CHECK_PLACES_URLS(urls); 0745 QCOMPARE(spy_inserted.count(), 1); 0746 args = spy_inserted.takeFirst(); 0747 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0748 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0749 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0750 QCOMPARE(spy_removed.count(), 1); 0751 args = spy_removed.takeFirst(); 0752 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0753 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0754 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0755 0756 fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); 0757 0758 urls.clear(); 0759 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/floppy0") 0760 << QStringLiteral("/media/cdrom"); 0761 CHECK_PLACES_URLS(urls); 0762 QCOMPARE(spy_inserted.count(), 0); 0763 QCOMPARE(spy_removed.count(), 1); 0764 args = spy_removed.takeFirst(); 0765 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0766 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0767 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0768 0769 fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); 0770 0771 urls.clear(); 0772 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/XO-Y4") 0773 << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); 0774 CHECK_PLACES_URLS(urls); 0775 QCOMPARE(spy_inserted.count(), 1); 0776 args = spy_inserted.takeFirst(); 0777 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0778 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0779 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0780 QCOMPARE(spy_removed.count(), 0); 0781 0782 KBookmark seventh = root.first(); 0783 for (int i = 0; i < count; i++) { 0784 seventh = root.next(seventh); 0785 } 0786 root.moveBookmark(device, seventh); 0787 bookmarkManager->emitChanged(root); 0788 0789 urls.clear(); 0790 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 0791 CHECK_PLACES_URLS(urls); 0792 QCOMPARE(spy_inserted.count(), 1); 0793 args = spy_inserted.takeFirst(); 0794 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0795 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0796 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 8 : 6); 0797 QCOMPARE(spy_removed.count(), 1); 0798 args = spy_removed.takeFirst(); 0799 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0800 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0801 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 5); 0802 } 0803 0804 void KFilePlacesModelTest::testDeviceSetupTeardown() 0805 { 0806 QList<QVariant> args; 0807 QSignalSpy spy_changed(m_places, &QAbstractItemModel::dataChanged); 0808 0809 fakeDevice(QStringLiteral("/org/kde/solid/fakehw/volume_part1_size_993284096/StorageAccess"))->call(QStringLiteral("teardown")); 0810 0811 QCOMPARE(spy_changed.count(), 1); 0812 args = spy_changed.takeFirst(); 0813 QCOMPARE(args.at(0).toModelIndex().row(), m_hasRecentlyUsedKio ? 8 : 6); 0814 QCOMPARE(args.at(1).toModelIndex().row(), m_hasRecentlyUsedKio ? 8 : 6); 0815 0816 fakeDevice(QStringLiteral("/org/kde/solid/fakehw/volume_part1_size_993284096/StorageAccess"))->call(QStringLiteral("setup")); 0817 0818 QCOMPARE(spy_changed.count(), 1); 0819 args = spy_changed.takeFirst(); 0820 QCOMPARE(args.at(0).toModelIndex().row(), m_hasRecentlyUsedKio ? 8 : 6); 0821 QCOMPARE(args.at(1).toModelIndex().row(), m_hasRecentlyUsedKio ? 8 : 6); 0822 } 0823 0824 void KFilePlacesModelTest::testEnableBaloo() 0825 { 0826 KConfig config(QStringLiteral("baloofilerc")); 0827 KConfigGroup basicSettings = config.group("Basic Settings"); 0828 basicSettings.writeEntry("Indexing-Enabled", true); 0829 config.sync(); 0830 0831 KFilePlacesModel places_with_baloo; 0832 QStringList urls; 0833 for (int row = 0; row < places_with_baloo.rowCount(); ++row) { 0834 QModelIndex index = places_with_baloo.index(row, 0); 0835 urls << places_with_baloo.url(index).toDisplayString(QUrl::PreferLocalFile); 0836 } 0837 0838 if (m_hasRecentlyUsedKio) { 0839 QVERIFY(urls.contains("recentlyused:/files")); 0840 QVERIFY(urls.contains("recentlyused:/locations")); 0841 } 0842 } 0843 0844 void KFilePlacesModelTest::testRemoteUrls_data() 0845 { 0846 QTest::addColumn<QUrl>("url"); 0847 QTest::addColumn<int>("expectedRow"); 0848 QTest::addColumn<QString>("expectedGroup"); 0849 0850 QTest::newRow("Ftp") << QUrl(QStringLiteral("ftp://192.168.1.1/ftp")) << 4 << QStringLiteral("Remote"); 0851 QTest::newRow("Samba") << QUrl(QStringLiteral("smb://192.168.1.1/share")) << 4 << QStringLiteral("Remote"); 0852 QTest::newRow("Sftp") << QUrl(QStringLiteral("sftp://192.168.1.1/share")) << 4 << QStringLiteral("Remote"); 0853 QTest::newRow("Fish") << QUrl(QStringLiteral("fish://192.168.1.1/share")) << 4 << QStringLiteral("Remote"); 0854 QTest::newRow("Webdav") << QUrl(QStringLiteral("webdav://192.168.1.1/share")) << 4 << QStringLiteral("Remote"); 0855 } 0856 0857 void KFilePlacesModelTest::testRemoteUrls() 0858 { 0859 QFETCH(QUrl, url); 0860 QFETCH(int, expectedRow); 0861 QFETCH(QString, expectedGroup); 0862 0863 QList<QVariant> args; 0864 QSignalSpy spy_inserted(m_places, &QAbstractItemModel::rowsInserted); 0865 0866 // insert a new network url 0867 m_places->addPlace(QStringLiteral("My Shared"), url, QString(), QString(), QModelIndex()); 0868 0869 // check if url list is correct after insertion 0870 QStringList urls; 0871 urls << QDir::homePath() << QStringLiteral("trash:/") // places 0872 << QStringLiteral("remote:/") << QStringLiteral("/media/nfs") << url.toString() << initialListOfRecent() << QStringLiteral("/foreign") 0873 << QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom"); 0874 CHECK_PLACES_URLS(urls); 0875 0876 // check if the new url was inserted in the right position (end of "Remote" section) 0877 QTRY_COMPARE(spy_inserted.count(), 1); 0878 args = spy_inserted.takeFirst(); 0879 QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); 0880 QCOMPARE(args.at(1).toInt(), expectedRow); 0881 QCOMPARE(args.at(2).toInt(), expectedRow); 0882 0883 // check if the new url has the right group "Remote" 0884 const QModelIndex index = m_places->index(expectedRow, 0); 0885 QCOMPARE(index.data(KFilePlacesModel::GroupRole).toString(), expectedGroup); 0886 0887 m_places->removePlace(index); 0888 } 0889 0890 void KFilePlacesModelTest::testRefresh() 0891 { 0892 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 0893 KBookmarkGroup root = bookmarkManager->root(); 0894 KBookmark homePlace = root.first(); 0895 const QModelIndex homePlaceIndex = m_places->index(0, 0); 0896 0897 QCOMPARE(m_places->text(homePlaceIndex), homePlace.fullText()); 0898 0899 // modify bookmark 0900 homePlace.setFullText("Test change the text"); 0901 QVERIFY(m_places->text(homePlaceIndex) != homePlace.fullText()); 0902 0903 // reload bookmark data 0904 m_places->refresh(); 0905 QCOMPARE(m_places->text(homePlaceIndex), homePlace.fullText()); 0906 } 0907 0908 void KFilePlacesModelTest::testConvertedUrl_data() 0909 { 0910 QTest::addColumn<QUrl>("url"); 0911 QTest::addColumn<QUrl>("expectedUrl"); 0912 0913 // places 0914 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << QUrl::fromLocalFile(QDir::homePath()); 0915 0916 // baloo -search 0917 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << QUrl("baloosearch:/documents"); 0918 0919 QTest::newRow("Baloo - Unknown Type") << QUrl("search:/unknown") << QUrl("search:/unknown"); 0920 0921 // baloo - timeline 0922 const QDate lastMonthDate = QDate::currentDate().addMonths(-1); 0923 QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") 0924 << QUrl(QString("timeline:/%1-%2").arg(lastMonthDate.year()).arg(lastMonthDate.month(), 2, 10, QLatin1Char('0'))); 0925 0926 // devices 0927 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << QUrl("file:///media/floppy0"); 0928 } 0929 0930 void KFilePlacesModelTest::testConvertedUrl() 0931 { 0932 QFETCH(QUrl, url); 0933 QFETCH(QUrl, expectedUrl); 0934 0935 const QUrl convertedUrl = KFilePlacesModel::convertedUrl(url); 0936 0937 QCOMPARE(convertedUrl.scheme(), expectedUrl.scheme()); 0938 QCOMPARE(convertedUrl.path(), expectedUrl.path()); 0939 QCOMPARE(convertedUrl, expectedUrl); 0940 } 0941 0942 void KFilePlacesModelTest::testBookmarkObject() 0943 { 0944 // make sure that all items return a valid bookmark 0945 for (int row = 0; row < m_places->rowCount(); row++) { 0946 const QModelIndex index = m_places->index(row, 0); 0947 const KBookmark bookmark = m_places->bookmarkForIndex(index); 0948 QVERIFY(!bookmark.isNull()); 0949 } 0950 } 0951 0952 void KFilePlacesModelTest::testDataChangedSignal() 0953 { 0954 QSignalSpy dataChangedSpy(m_places, &KFilePlacesModel::dataChanged); 0955 0956 const QModelIndex index = m_places->index(1, 0); 0957 const KBookmark bookmark = m_places->bookmarkForIndex(index); 0958 0959 // call function with the same data 0960 m_places->editPlace(index, bookmark.fullText(), bookmark.url(), bookmark.icon(), bookmark.metaDataItem(QStringLiteral("OnlyInApp"))); 0961 QCOMPARE(dataChangedSpy.count(), 0); 0962 0963 // call function with different data 0964 const QString originalText = bookmark.fullText(); 0965 m_places->editPlace(index, QStringLiteral("My text"), bookmark.url(), bookmark.icon(), bookmark.metaDataItem(QStringLiteral("OnlyInApp"))); 0966 QCOMPARE(dataChangedSpy.count(), 1); 0967 QList<QVariant> args = dataChangedSpy.takeFirst(); 0968 QCOMPARE(args.at(0).toModelIndex().row(), 1); 0969 QCOMPARE(args.at(0).toModelIndex().column(), 0); 0970 QCOMPARE(args.at(1).toModelIndex().row(), 1); 0971 QCOMPARE(args.at(1).toModelIndex().column(), 0); 0972 QCOMPARE(m_places->text(index), QStringLiteral("My text")); 0973 0974 // restore original value 0975 dataChangedSpy.clear(); 0976 m_places->editPlace(index, originalText, bookmark.url(), bookmark.icon(), bookmark.metaDataItem(QStringLiteral("OnlyInApp"))); 0977 QCOMPARE(dataChangedSpy.count(), 1); 0978 } 0979 0980 void KFilePlacesModelTest::testIconRole_data() 0981 { 0982 QTest::addColumn<QModelIndex>("index"); 0983 QTest::addColumn<QString>("expectedIconName"); 0984 0985 // places 0986 int index = 0; 0987 QTest::newRow("Places - Home") << m_places->index(index++, 0) << QStringLiteral("user-home"); 0988 QTest::newRow("Places - Trash") << m_places->index(index++, 0) << QStringLiteral("user-trash"); 0989 0990 QTest::newRow("Remote - Network") << m_places->index(index++, 0) << QStringLiteral("folder-network"); 0991 QTest::newRow("Devices - Nfs") << m_places->index(index++, 0) << QStringLiteral("hwinfo"); 0992 if (m_hasRecentlyUsedKio) { 0993 QTest::newRow("Recent Files") << m_places->index(index++, 0) << QStringLiteral("document-open-recent"); 0994 QTest::newRow("Recent Locations") << m_places->index(index++, 0) << QStringLiteral("folder-open-recent"); 0995 } 0996 QTest::newRow("Devices - foreign") << m_places->index(index++, 0) << QStringLiteral("blockdevice"); 0997 QTest::newRow("Devices - Floppy") << m_places->index(index++, 0) << QStringLiteral("blockdevice"); 0998 QTest::newRow("Devices - cdrom") << m_places->index(index++, 0) << QStringLiteral("blockdevice"); 0999 } 1000 1001 void KFilePlacesModelTest::testIconRole() 1002 { 1003 QFETCH(QModelIndex, index); 1004 QFETCH(QString, expectedIconName); 1005 1006 QVERIFY(index.data(KFilePlacesModel::IconNameRole).toString().startsWith(expectedIconName)); 1007 } 1008 1009 void KFilePlacesModelTest::testMoveFunction() 1010 { 1011 QList<QVariant> args; 1012 QStringList urls = initialListOfUrls(); 1013 QSignalSpy rowsMoved(m_places, &KFilePlacesModel::rowsMoved); 1014 1015 // move item 0 to pos 1 1016 QVERIFY(m_places->movePlace(0, 2)); 1017 urls.move(0, 1); 1018 QTRY_COMPARE(rowsMoved.count(), 1); 1019 args = rowsMoved.takeFirst(); 1020 QCOMPARE(args.at(1).toInt(), 0); // start 1021 QCOMPARE(args.at(2).toInt(), 0); // end 1022 QCOMPARE(args.at(4).toInt(), 2); // row (destination) 1023 QCOMPARE(placesUrls(), urls); 1024 rowsMoved.clear(); 1025 1026 // move it back 1027 QVERIFY(m_places->movePlace(1, 0)); 1028 urls.move(1, 0); 1029 QTRY_COMPARE(rowsMoved.count(), 1); 1030 args = rowsMoved.takeFirst(); 1031 QCOMPARE(args.at(1).toInt(), 1); // start 1032 QCOMPARE(args.at(2).toInt(), 1); // end 1033 QCOMPARE(args.at(4).toInt(), 0); // row (destination) 1034 QCOMPARE(placesUrls(), urls); 1035 rowsMoved.clear(); 1036 1037 // target position is greater than model rows 1038 // will move to the end of the first group 1039 QVERIFY(m_places->movePlace(0, 20)); 1040 urls.move(0, 1); 1041 QTRY_COMPARE(rowsMoved.count(), 1); 1042 args = rowsMoved.takeFirst(); 1043 QCOMPARE(args.at(1).toInt(), 0); // start 1044 QCOMPARE(args.at(2).toInt(), 0); // end 1045 QCOMPARE(args.at(4).toInt(), 2); // row (destination) 1046 QCOMPARE(placesUrls(), urls); 1047 rowsMoved.clear(); 1048 1049 // move it back 1050 QVERIFY(m_places->movePlace(1, 0)); 1051 urls.move(1, 0); 1052 QTRY_COMPARE(rowsMoved.count(), 1); 1053 args = rowsMoved.takeFirst(); 1054 QCOMPARE(args.at(1).toInt(), 1); // start 1055 QCOMPARE(args.at(2).toInt(), 1); // end 1056 QCOMPARE(args.at(4).toInt(), 0); // row (destination) 1057 QCOMPARE(placesUrls(), urls); 1058 rowsMoved.clear(); 1059 1060 QVERIFY(m_places->movePlace(m_hasRecentlyUsedKio ? 8 : 7, m_hasRecentlyUsedKio ? 6 : 5)); 1061 urls.move(m_hasRecentlyUsedKio ? 8 : 7, m_hasRecentlyUsedKio ? 6 : 5); 1062 QTRY_COMPARE(rowsMoved.count(), 1); 1063 args = rowsMoved.takeFirst(); 1064 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 8 : 7); // start 1065 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 8 : 7); // end 1066 QCOMPARE(args.at(4).toInt(), m_hasRecentlyUsedKio ? 6 : 5); // row (destination) 1067 QCOMPARE(placesUrls(), urls); 1068 rowsMoved.clear(); 1069 1070 // move it back 1071 QVERIFY(m_places->movePlace(m_hasRecentlyUsedKio ? 6 : 5, m_hasRecentlyUsedKio ? 9 : 8)); 1072 urls.move(m_hasRecentlyUsedKio ? 6 : 5, m_hasRecentlyUsedKio ? 8 : 7); 1073 QTRY_COMPARE(rowsMoved.count(), 1); 1074 args = rowsMoved.takeFirst(); 1075 QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 6 : 5); // start 1076 QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 6 : 5); // end 1077 QCOMPARE(args.at(4).toInt(), m_hasRecentlyUsedKio ? 9 : 8); // row (destination) 1078 QCOMPARE(placesUrls(), urls); 1079 rowsMoved.clear(); 1080 1081 // use a invalid start position 1082 QVERIFY(!m_places->movePlace(100, 20)); 1083 QCOMPARE(rowsMoved.count(), 0); 1084 1085 // use same start and target position 1086 QVERIFY(!m_places->movePlace(1, 1)); 1087 QCOMPARE(rowsMoved.count(), 0); 1088 } 1089 1090 void KFilePlacesModelTest::testPlaceGroupHidden() 1091 { 1092 // GIVEN 1093 QCOMPARE(m_places->hiddenCount(), 0); 1094 1095 QStringList urls; 1096 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 1097 CHECK_PLACES_URLS(urls); 1098 QVector<QModelIndex> indexesHidden; 1099 1100 // WHEN 1101 m_places->setGroupHidden(KFilePlacesModel::PlacesType, true); 1102 1103 // THEN 1104 for (int row = 0; row < m_places->rowCount(); ++row) { 1105 QModelIndex index = m_places->index(row, 0); 1106 if (m_places->groupType(index) == KFilePlacesModel::PlacesType) { 1107 QVERIFY(m_places->isHidden(index)); 1108 indexesHidden << index; 1109 } 1110 } 1111 QCOMPARE(indexesHidden.count(), initialListOfPlaces().size()); 1112 QCOMPARE(m_places->hiddenCount(), indexesHidden.size()); 1113 1114 // and GIVEN 1115 QVector<QModelIndex> indexesShown; 1116 1117 // WHEN 1118 m_places->setGroupHidden(KFilePlacesModel::PlacesType, false); 1119 1120 // THEN 1121 for (int row = 0; row < m_places->rowCount(); ++row) { 1122 QModelIndex index = m_places->index(row, 0); 1123 if (m_places->groupType(index) == KFilePlacesModel::PlacesType) { 1124 QVERIFY(!m_places->isHidden(index)); 1125 indexesShown << index; 1126 } 1127 } 1128 QCOMPARE(m_places->hiddenCount(), 0); 1129 QCOMPARE(indexesShown.count(), initialListOfPlaces().size()); 1130 } 1131 1132 void KFilePlacesModelTest::testPlaceGroupHiddenVsPlaceChildShown() 1133 { 1134 // GIVEN 1135 for (int row = 0; row < m_places->rowCount(); ++row) { 1136 QModelIndex index = m_places->index(row, 0); 1137 QVERIFY(!m_places->isHidden(index)); 1138 } 1139 m_places->setGroupHidden(KFilePlacesModel::PlacesType, true); 1140 1141 QModelIndex firstIndex = m_places->index(0, 0); 1142 const int amountOfPlaces = initialListOfPlaces().size(); 1143 for (int row = 0; row < amountOfPlaces; ++row) { 1144 QModelIndex index = m_places->index(row, 0); 1145 QVERIFY(m_places->isHidden(index)); 1146 } 1147 // WHEN 1148 m_places->setPlaceHidden(firstIndex, false); 1149 1150 // THEN 1151 QVERIFY(m_places->isHidden(firstIndex)); // a child cannot show against its parent state 1152 1153 // leaving in a clean state 1154 m_places->setGroupHidden(KFilePlacesModel::PlacesType, false); 1155 } 1156 1157 void KFilePlacesModelTest::testPlaceGroupHiddenAndShownWithHiddenChild() 1158 { 1159 // GIVEN 1160 QCOMPARE(m_places->hiddenCount(), 0); 1161 1162 QStringList urls; 1163 urls << initialListOfPlaces() << initialListOfShared() << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); 1164 CHECK_PLACES_URLS(urls); 1165 1166 QModelIndex firstIndexHidden = m_places->index(0, 0); 1167 m_places->setPlaceHidden(firstIndexHidden, true); // first place index is hidden within an hidden parent 1168 m_places->setGroupHidden(KFilePlacesModel::PlacesType, true); 1169 QCOMPARE(m_places->hiddenCount(), initialListOfPlaces().size()); 1170 1171 // WHEN 1172 m_places->setGroupHidden(KFilePlacesModel::PlacesType, false); 1173 1174 // THEN 1175 QVector<QModelIndex> indexesShown; 1176 for (int row = 0; row < m_places->rowCount(); ++row) { 1177 QModelIndex index = m_places->index(row, 0); 1178 if (index == firstIndexHidden) { 1179 QVERIFY(m_places->isHidden(firstIndexHidden)); 1180 continue; 1181 } 1182 if (m_places->groupType(index) == KFilePlacesModel::PlacesType) { 1183 QVERIFY(!m_places->isHidden(index)); 1184 indexesShown << index; 1185 } 1186 } 1187 QCOMPARE(m_places->hiddenCount(), 1); 1188 QCOMPARE(indexesShown.count(), initialListOfPlaces().size() - 1 /*first child remains hidden*/); 1189 1190 // leaving in a clean state 1191 m_places->setPlaceHidden(firstIndexHidden, false); 1192 } 1193 1194 void KFilePlacesModelTest::testPlaceGroupHiddenGroupIndexesIntegrity() 1195 { 1196 // GIVEN 1197 m_places->setGroupHidden(KFilePlacesModel::PlacesType, true); 1198 QVERIFY(m_places->groupIndexes(KFilePlacesModel::UnknownType).isEmpty()); 1199 QVERIFY(m_places->isGroupHidden(KFilePlacesModel::PlacesType)); 1200 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::PlacesType).count(), initialListOfPlaces().count()); 1201 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), m_hasRecentlyUsedKio ? 2 : 0); 1202 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::SearchForType).count(), 0); 1203 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::DevicesType).count(), initialListOfDevices().count()); 1204 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RemovableDevicesType).count(), initialListOfRemovableDevices().count()); 1205 1206 // WHEN 1207 m_places->setGroupHidden(KFilePlacesModel::PlacesType, false); 1208 1209 // THEN 1210 // Make sure that hidden place group doesn't change model 1211 QVERIFY(!m_places->isGroupHidden(KFilePlacesModel::PlacesType)); 1212 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::PlacesType).count(), initialListOfPlaces().count()); 1213 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), m_hasRecentlyUsedKio ? 2 : 0); 1214 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::SearchForType).count(), 0); 1215 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::DevicesType).count(), initialListOfDevices().count()); 1216 QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RemovableDevicesType).count(), initialListOfRemovableDevices().count()); 1217 } 1218 1219 void KFilePlacesModelTest::testPlaceGroupHiddenSignal() 1220 { 1221 QSignalSpy groupHiddenSignal(m_places, &KFilePlacesModel::groupHiddenChanged); 1222 m_places->setGroupHidden(KFilePlacesModel::SearchForType, true); 1223 1224 // hide SearchForType group 1225 QTRY_COMPARE(groupHiddenSignal.count(), 1); 1226 QList<QVariant> args = groupHiddenSignal.takeFirst(); 1227 QCOMPARE(args.at(0).toInt(), static_cast<int>(KFilePlacesModel::SearchForType)); 1228 QCOMPARE(args.at(1).toBool(), true); 1229 groupHiddenSignal.clear(); 1230 1231 // try hide SearchForType which is already hidden 1232 m_places->setGroupHidden(KFilePlacesModel::SearchForType, true); 1233 QCOMPARE(groupHiddenSignal.count(), 0); 1234 1235 // show SearchForType group 1236 m_places->setGroupHidden(KFilePlacesModel::SearchForType, false); 1237 QTRY_COMPARE(groupHiddenSignal.count(), 1); 1238 args = groupHiddenSignal.takeFirst(); 1239 QCOMPARE(args.at(0).toInt(), static_cast<int>(KFilePlacesModel::SearchForType)); 1240 QCOMPARE(args.at(1).toBool(), false); 1241 } 1242 1243 void KFilePlacesModelTest::testPlaceGroupHiddenRole() 1244 { 1245 // on startup all groups are visible 1246 for (int r = 0, rMax = m_places->rowCount(); r < rMax; r++) { 1247 const QModelIndex index = m_places->index(r, 0); 1248 QCOMPARE(index.data(KFilePlacesModel::GroupHiddenRole).toBool(), false); 1249 } 1250 1251 // set SearchFor group hidden 1252 m_places->setGroupHidden(KFilePlacesModel::SearchForType, true); 1253 for (auto groupType : {KFilePlacesModel::PlacesType, 1254 KFilePlacesModel::RemoteType, 1255 KFilePlacesModel::RecentlySavedType, 1256 KFilePlacesModel::SearchForType, 1257 KFilePlacesModel::DevicesType, 1258 KFilePlacesModel::RemovableDevicesType}) { 1259 const bool groupShouldBeHidden = (groupType == KFilePlacesModel::SearchForType); 1260 const QModelIndexList indexes = m_places->groupIndexes(groupType); 1261 for (const QModelIndex &index : indexes) { 1262 QCOMPARE(index.data(KFilePlacesModel::GroupHiddenRole).toBool(), groupShouldBeHidden); 1263 } 1264 } 1265 1266 // set SearchFor group visible again 1267 m_places->setGroupHidden(KFilePlacesModel::SearchForType, false); 1268 for (int r = 0, rMax = m_places->rowCount(); r < rMax; r++) { 1269 const QModelIndex index = m_places->index(r, 0); 1270 QCOMPARE(index.data(KFilePlacesModel::GroupHiddenRole).toBool(), false); 1271 } 1272 } 1273 1274 void KFilePlacesModelTest::testFilterWithAlternativeApplicationName() 1275 { 1276 const QStringList urls = initialListOfUrls(); 1277 const QString alternativeApplicationName = QStringLiteral("kfile_places_model_test"); 1278 1279 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces")); 1280 KBookmarkGroup root = bookmarkManager->root(); 1281 1282 // create a new entry with alternative application name 1283 KBookmark bookmark = root.addBookmark(QStringLiteral("Extra entry"), QUrl(QStringLiteral("search:/videos-alternative")), {}); 1284 const QString id = QUuid::createUuid().toString(); 1285 bookmark.setMetaDataItem(QStringLiteral("ID"), id); 1286 bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), alternativeApplicationName); 1287 bookmarkManager->emitChanged(bookmarkManager->root()); 1288 1289 // make sure that the entry is not visible on the original model 1290 CHECK_PLACES_URLS(urls); 1291 1292 // create a new model with alternativeApplicationName 1293 KFilePlacesModel *newModel = new KFilePlacesModel(alternativeApplicationName); 1294 QTRY_COMPARE(placesUrls(newModel).count(QStringLiteral("search:/videos-alternative")), 1); 1295 delete newModel; 1296 } 1297 1298 void KFilePlacesModelTest::testSupportedSchemes() 1299 { 1300 QCoreApplication::processEvents(); // support running this test on its own 1301 1302 QCOMPARE(m_places->supportedSchemes(), QStringList()); 1303 QCOMPARE(placesUrls(), initialListOfUrls()); 1304 m_places->setSupportedSchemes({"trash"}); 1305 QCOMPARE(m_places->supportedSchemes(), QStringList("trash")); 1306 QCOMPARE(placesUrls(), QStringList("trash:/")); 1307 m_places->setSupportedSchemes({}); 1308 QCOMPARE(m_places->supportedSchemes(), QStringList()); 1309 QCOMPARE(placesUrls(), initialListOfUrls()); 1310 } 1311 1312 QTEST_MAIN(KFilePlacesModelTest) 1313 1314 #include "kfileplacesmodeltest.moc"