]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/placesitemmodeltest.cpp
Add Flatpak patches to Dolphin depending on CMake definition
[dolphin.git] / src / tests / placesitemmodeltest.cpp
1 /*
2 * SPDX-FileCopyrightText: 2017 Renato Araujo Oliveira <renato.araujo@kdab.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include <QTest>
8 #include <QSignalSpy>
9 #include <QStandardPaths>
10 #include <QAction>
11 #include <QDBusInterface>
12
13 #include <KBookmarkManager>
14 #include <KConfig>
15 #include <KConfigGroup>
16 #include <KAboutData>
17 #include <KFilePlacesModel>
18 #include <KProtocolInfo>
19
20 #include "dolphin_generalsettings.h"
21 #include "panels/places/placesitemmodel.h"
22 #include "panels/places/placesitem.h"
23 #include "views/viewproperties.h"
24
25 Q_DECLARE_METATYPE(KItemRangeList)
26 Q_DECLARE_METATYPE(KItemRange)
27
28 static QString bookmarksFile()
29 {
30 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/user-places.xbel";
31 }
32
33 class PlacesItemModelTest : public QObject
34 {
35 Q_OBJECT
36
37 private Q_SLOTS:
38 void init();
39 void cleanup();
40
41 void initTestCase();
42 void cleanupTestCase();
43
44 void testModelSort();
45 void testGroups();
46 void testDeletePlace();
47 void testPlaceItem_data();
48 void testPlaceItem();
49 void testTearDownDevice();
50 void testDefaultViewProperties_data();
51 void testDefaultViewProperties();
52 void testClear();
53 void testHideItem();
54 void testSystemItems();
55 void testEditBookmark();
56 void testEditAfterCreation();
57 void testEditMetadata();
58 void testRefresh();
59 void testIcons_data();
60 void testIcons();
61 void testDragAndDrop();
62 void testHideDevices();
63 void testDuplicatedEntries();
64 void renameAfterCreation();
65
66 private:
67 PlacesItemModel* m_model;
68 QSet<int> m_tobeRemoved;
69 QMap<QString, QDBusInterface *> m_interfacesMap;
70 int m_expectedModelCount = 14;
71 bool m_hasDesktopFolder = false;
72 bool m_hasDocumentsFolder = false;
73 bool m_hasDownloadsFolder = false;
74 bool m_hasMusicFolder = false;
75 bool m_hasPicturesFolder = false;
76 bool m_hasVideosFolder = false;
77
78 void setBalooEnabled(bool enabled);
79 int indexOf(const QUrl &url);
80 QDBusInterface *fakeManager();
81 QDBusInterface *fakeDevice(const QString &udi);
82 QStringList placesUrls(PlacesItemModel *model = nullptr) const;
83 QStringList initialUrls() const;
84 void createPlaceItem(const QString &text, const QUrl &url, const QString &icon);
85 void schedulePlaceRemoval(int index);
86 void cancelPlaceRemoval(int index);
87 QMimeData *createMimeData(const QList<int> &indexes) const;
88 void increaseIndexIfNeeded(int &index) const;
89 QTemporaryDir m_tempHomeDir;
90 };
91
92 #define CHECK_PLACES_URLS(urls) \
93 { \
94 QStringList places = placesUrls(); \
95 if (places != urls) { \
96 qWarning() << "Expected:" << urls; \
97 qWarning() << "Got:" << places; \
98 QCOMPARE(places, urls); \
99 } \
100 }
101
102 void PlacesItemModelTest::setBalooEnabled(bool enabled)
103 {
104 KConfig config(QStringLiteral("baloofilerc"));
105 KConfigGroup basicSettings = config.group("Basic Settings");
106 basicSettings.writeEntry("Indexing-Enabled", enabled);
107 config.sync();
108 }
109
110 int PlacesItemModelTest::indexOf(const QUrl &url)
111 {
112 for (int r = 0; r < m_model->count(); r++) {
113 if (m_model->placesItem(r)->url() == url) {
114 return r;
115 }
116 }
117 return -1;
118 }
119
120 QDBusInterface *PlacesItemModelTest::fakeManager()
121 {
122 return fakeDevice(QStringLiteral("/org/kde/solid/fakehw"));
123 }
124
125 QDBusInterface *PlacesItemModelTest::fakeDevice(const QString &udi)
126 {
127 if (m_interfacesMap.contains(udi)) {
128 return m_interfacesMap[udi];
129 }
130
131 QDBusInterface *iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), udi);
132 m_interfacesMap[udi] = iface;
133
134 return iface;
135 }
136
137 QStringList PlacesItemModelTest::placesUrls(PlacesItemModel *model) const
138 {
139 QStringList urls;
140 if (!model) {
141 model = m_model;
142 }
143
144 for (int row = 0; row < model->count(); ++row) {
145 urls << model->placesItem(row)->url().toDisplayString(QUrl::PreferLocalFile);
146 }
147 return urls;
148 }
149
150 QStringList PlacesItemModelTest::initialUrls() const
151 {
152 static QStringList urls;
153 if (urls.isEmpty()) {
154 urls << QDir::homePath();
155
156 if (m_hasDesktopFolder) {
157 urls << QDir::homePath() + QStringLiteral("/Desktop");
158 }
159
160 if (m_hasDocumentsFolder) {
161 urls << QDir::homePath() + QStringLiteral("/Documents");
162 }
163
164 if (m_hasDownloadsFolder) {
165 urls << QDir::homePath() + QStringLiteral("/Downloads");
166 }
167
168 if (m_hasMusicFolder) {
169 urls << QDir::homePath() + QStringLiteral("/Music");
170 }
171
172 if (m_hasPicturesFolder) {
173 urls << QDir::homePath() + QStringLiteral("/Pictures");
174 }
175
176 if (m_hasVideosFolder) {
177 urls << QDir::homePath() + QStringLiteral("/Videos");
178 }
179
180 urls << QStringLiteral("trash:/")
181 << QStringLiteral("remote:/")
182 << QStringLiteral("/media/nfs");
183
184 if (qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) {
185 urls << QStringLiteral("recentlyused:/files");
186 urls << QStringLiteral("recentlyused:/locations");
187 } else {
188 urls << QStringLiteral("timeline:/today")
189 << QStringLiteral("timeline:/yesterday");
190 }
191
192 urls << QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
193 << QStringLiteral("/foreign")
194 << QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom");
195 }
196 return urls;
197 }
198
199 void PlacesItemModelTest::createPlaceItem(const QString &text, const QUrl &url, const QString &icon)
200 {
201 m_model->createPlacesItem(text, url, icon);
202 }
203
204 void PlacesItemModelTest::schedulePlaceRemoval(int index)
205 {
206 m_tobeRemoved.insert(index);
207 }
208
209 void PlacesItemModelTest::cancelPlaceRemoval(int index)
210 {
211 m_tobeRemoved.remove(index);
212 }
213
214 QMimeData *PlacesItemModelTest::createMimeData(const QList<int> &indexes) const
215 {
216 QByteArray itemData;
217 QDataStream stream(&itemData, QIODevice::WriteOnly);
218 QList<QUrl> urls;
219
220 for (int index : indexes) {
221 const QUrl itemUrl = m_model->placesItem(index)->url();
222 if (itemUrl.isValid()) {
223 urls << itemUrl;
224 }
225 stream << index;
226 }
227
228 QMimeData* mimeData = new QMimeData();
229 mimeData->setUrls(urls);
230 // copied from PlacesItemModel::internalMimeType()
231 const QString internalMimeType = "application/x-dolphinplacesmodel-" +
232 QString::number((qptrdiff)m_model);
233 mimeData->setData(internalMimeType, itemData);
234 return mimeData;
235 }
236
237 void PlacesItemModelTest::increaseIndexIfNeeded(int &index) const
238 {
239 if (m_hasDesktopFolder) {
240 index++;
241 }
242 if (m_hasDocumentsFolder) {
243 index++;
244 }
245 if (m_hasDownloadsFolder) {
246 index++;
247 }
248 if (m_hasMusicFolder) {
249 index++;
250 }
251 if (m_hasPicturesFolder) {
252 index++;
253 }
254 if (m_hasVideosFolder) {
255 index++;
256 }
257 }
258
259 void PlacesItemModelTest::init()
260 {
261 m_model = new PlacesItemModel();
262 // WORKAROUND: need to wait for bookmark to load
263 QTest::qWait(300);
264 QCOMPARE(m_model->count(), m_expectedModelCount);
265 }
266
267 void PlacesItemModelTest::cleanup()
268 {
269 const auto tobeRemoved = m_tobeRemoved;
270 for (const int i : tobeRemoved) {
271 int before = m_model->count();
272 m_model->deleteItem(i);
273 QTRY_COMPARE(m_model->count(), before - 1);
274 }
275 m_tobeRemoved.clear();
276 delete m_model;
277 m_model = nullptr;
278 }
279
280 void PlacesItemModelTest::initTestCase()
281 {
282 QVERIFY(m_tempHomeDir.isValid());
283 QVERIFY(qputenv("HOME", m_tempHomeDir.path().toUtf8()));
284 QVERIFY(qputenv("KDE_FORK_SLAVES", "yes"));
285
286 QStandardPaths::setTestModeEnabled(true);
287
288 const QString fakeHw = QFINDTESTDATA("data/fakecomputer.xml");
289 QVERIFY(!fakeHw.isEmpty());
290 qputenv("SOLID_FAKEHW", QFile::encodeName(fakeHw));
291
292 setBalooEnabled(true);
293 const QString bookmarsFileName = bookmarksFile();
294 if (QFileInfo::exists(bookmarsFileName)) {
295 // Ensure we'll have a clean bookmark file to start
296 QVERIFY(QFile::remove(bookmarsFileName));
297 }
298
299 if (QDir(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).exists()) {
300 m_hasDesktopFolder = true;
301 m_expectedModelCount++;
302 }
303
304 if (QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).exists()) {
305 m_hasDocumentsFolder = true;
306 m_expectedModelCount++;
307 }
308
309 if (QDir(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)).exists()) {
310 m_hasDownloadsFolder = true;
311 m_expectedModelCount++;
312 }
313
314 if (QDir(QStandardPaths::writableLocation(QStandardPaths::MusicLocation)).exists()) {
315 m_hasMusicFolder = true;
316 m_expectedModelCount++;
317 }
318
319 if (QDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)).exists()) {
320 m_hasPicturesFolder = true;
321 m_expectedModelCount++;
322 }
323
324 if (QDir(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).exists()) {
325 m_hasVideosFolder = true;
326 m_expectedModelCount++;
327 }
328
329 qRegisterMetaType<KItemRangeList>();
330 qRegisterMetaType<KItemRange>();
331 }
332
333 void PlacesItemModelTest::cleanupTestCase()
334 {
335 qDeleteAll(m_interfacesMap);
336 QFile::remove(bookmarksFile());
337 }
338
339 void PlacesItemModelTest::testModelSort()
340 {
341 CHECK_PLACES_URLS(initialUrls());
342 }
343
344 void PlacesItemModelTest::testGroups()
345 {
346 const auto groups = m_model->groups();
347 int expectedRemoteIndex = 2;
348 increaseIndexIfNeeded(expectedRemoteIndex);
349
350 QCOMPARE(groups.size(), 6);
351
352 QCOMPARE(groups.at(0).first, 0);
353 QCOMPARE(groups.at(0).second.toString(), QStringLiteral("Places"));
354
355 QCOMPARE(groups.at(1).first, expectedRemoteIndex);
356 QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Remote"));
357
358 QCOMPARE(groups.at(2).first, expectedRemoteIndex + 2);
359 QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Recent"));
360
361 QCOMPARE(groups.at(3).first, expectedRemoteIndex + 4);
362 QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Search For"));
363
364 QCOMPARE(groups.at(4).first, expectedRemoteIndex + 8);
365 QCOMPARE(groups.at(4).second.toString(), QStringLiteral("Devices"));
366
367 QCOMPARE(groups.at(5).first, expectedRemoteIndex + 9);
368 QCOMPARE(groups.at(5).second.toString(), QStringLiteral("Removable Devices"));
369 }
370
371 void PlacesItemModelTest::testPlaceItem_data()
372 {
373 QTest::addColumn<QUrl>("url");
374 QTest::addColumn<bool>("expectedIsHidden");
375 QTest::addColumn<bool>("expectedIsSystemItem");
376 QTest::addColumn<QString>("expectedGroup");
377 QTest::addColumn<bool>("expectedStorageSetupNeeded");
378
379 // places
380 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << false << true << QStringLiteral("Places") << false;
381
382 // baloo -search
383 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << QStringLiteral("Search For") << false;
384
385 // devices
386 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << QStringLiteral("Removable Devices") << false;
387 }
388
389 void PlacesItemModelTest::testPlaceItem()
390 {
391 QFETCH(QUrl, url);
392 QFETCH(bool, expectedIsHidden);
393 QFETCH(bool, expectedIsSystemItem);
394 QFETCH(QString, expectedGroup);
395 QFETCH(bool, expectedStorageSetupNeeded);
396
397 const int index = indexOf(url);
398 PlacesItem *item = m_model->placesItem(index);
399 QCOMPARE(item->url(), url);
400 QCOMPARE(item->isHidden(), expectedIsHidden);
401 QCOMPARE(item->isSystemItem(), expectedIsSystemItem);
402 QCOMPARE(item->group(), expectedGroup);
403 QCOMPARE(item->storageSetupNeeded(), expectedStorageSetupNeeded);
404 }
405
406 void PlacesItemModelTest::testDeletePlace()
407 {
408 const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
409 QStringList urls = initialUrls();
410 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
411 QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
412
413 PlacesItemModel *model = new PlacesItemModel();
414
415 int tempDirIndex = 2;
416 increaseIndexIfNeeded(tempDirIndex);
417
418 // create a new place
419 createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
420 urls.insert(tempDirIndex, tempUrl.toLocalFile());
421
422 // check if the new entry was created
423 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
424 CHECK_PLACES_URLS(urls);
425 QTRY_COMPARE(model->count(), m_model->count());
426
427 // delete item
428 m_model->deleteItem(tempDirIndex);
429
430 // make sure that the new item is removed
431 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
432 QTRY_COMPARE(m_model->count(), m_expectedModelCount);
433 CHECK_PLACES_URLS(initialUrls());
434 QTRY_COMPARE(model->count(), m_model->count());
435 }
436
437 void PlacesItemModelTest::testTearDownDevice()
438 {
439 const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
440 int index = indexOf(mediaUrl);
441 QVERIFY(index != -1);
442
443 auto ejectAction = m_model->ejectAction(index);
444 QVERIFY(!ejectAction);
445
446 auto teardownAction = m_model->teardownAction(index);
447 QVERIFY(teardownAction);
448
449 QCOMPARE(m_model->count(), m_expectedModelCount);
450
451 QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
452 fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
453 QTRY_COMPARE(m_model->count(), m_expectedModelCount - 1);
454 QCOMPARE(spyItemsRemoved.count(), 1);
455 const QList<QVariant> spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
456 const KItemRangeList removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
457 QCOMPARE(removedRange.size(), 1);
458 QCOMPARE(removedRange.first().index, index);
459 QCOMPARE(removedRange.first().count, 1);
460
461 QCOMPARE(indexOf(mediaUrl), -1);
462
463 QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
464 fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
465 QTRY_COMPARE(m_model->count(), m_expectedModelCount);
466 QCOMPARE(spyItemsInserted.count(), 1);
467 index = indexOf(mediaUrl);
468
469 const QList<QVariant> args = spyItemsInserted.takeFirst();
470 const KItemRangeList insertedRange = args.at(0).value<KItemRangeList>();
471 QCOMPARE(insertedRange.size(), 1);
472 QCOMPARE(insertedRange.first().index, index);
473 QCOMPARE(insertedRange.first().count, 1);
474 }
475
476 void PlacesItemModelTest::testDefaultViewProperties_data()
477 {
478 QTest::addColumn<QUrl>("url");
479 QTest::addColumn<DolphinView::Mode>("expectedViewMode");
480 QTest::addColumn<bool>("expectedPreviewShow");
481 QTest::addColumn<QList<QByteArray> >("expectedVisibleRole");
482
483 // places
484 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << DolphinView::IconsView << true << QList<QByteArray>({"text"});
485
486 // baloo -search
487 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "path"});
488
489 // audio files
490 QTest::newRow("Places - Audio") << QUrl("search:/audio") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "artist", "album"});
491
492 // devices
493 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << DolphinView::IconsView << true << QList<QByteArray>({"text"});
494
495 }
496
497 void PlacesItemModelTest::testDefaultViewProperties()
498 {
499 QFETCH(QUrl, url);
500 QFETCH(DolphinView::Mode, expectedViewMode);
501 QFETCH(bool, expectedPreviewShow);
502 QFETCH(QList<QByteArray>, expectedVisibleRole);
503
504 // In order to test the default view properties, turn off the global view properties and re-init the test to reload the model.
505 GeneralSettings* settings = GeneralSettings::self();
506 settings->setGlobalViewProps(false);
507 settings->save();
508 cleanup();
509 init();
510
511 ViewProperties properties(KFilePlacesModel::convertedUrl(url));
512 QCOMPARE(properties.viewMode(), expectedViewMode);
513 QCOMPARE(properties.previewsShown(), expectedPreviewShow);
514 QCOMPARE(properties.visibleRoles(), expectedVisibleRole);
515
516 settings->setGlobalViewProps(true);
517 settings->save();
518 }
519
520 void PlacesItemModelTest::testClear()
521 {
522 QCOMPARE(m_model->count(), m_expectedModelCount);
523 m_model->clear();
524 QCOMPARE(m_model->count(), 0);
525 QCOMPARE(m_model->hiddenCount(), 0);
526 m_model->refresh();
527 QTRY_COMPARE(m_model->count(), m_expectedModelCount);
528 }
529
530 void PlacesItemModelTest::testHideItem()
531 {
532 const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
533 const int index = indexOf(mediaUrl);
534
535 PlacesItem *item = m_model->placesItem(index);
536
537 QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
538 QList<QVariant> spyItemsRemovedArgs;
539 KItemRangeList removedRange;
540
541 QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
542 QList<QVariant> spyItemsInsertedArgs;
543 KItemRangeList insertedRange;
544 QVERIFY(item);
545
546 // hide an item
547 item->setHidden(true);
548
549 // check if items removed was fired
550 QTRY_COMPARE(m_model->count(), m_expectedModelCount - 1);
551 QCOMPARE(spyItemsRemoved.count(), 1);
552 spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
553 removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
554 QCOMPARE(removedRange.size(), 1);
555 QCOMPARE(removedRange.first().index, index);
556 QCOMPARE(removedRange.first().count, 1);
557
558 // allow model to show hidden items
559 m_model->setHiddenItemsShown(true);
560
561 // check if the items inserted was fired
562 spyItemsInsertedArgs = spyItemsInserted.takeFirst();
563 insertedRange = spyItemsInsertedArgs.at(0).value<KItemRangeList>();
564 QCOMPARE(insertedRange.size(), 1);
565 QCOMPARE(insertedRange.first().index, index);
566 QCOMPARE(insertedRange.first().count, 1);
567
568 // mark item as visible
569 item = m_model->placesItem(index);
570 item->setHidden(false);
571
572 // mark model to hide invisible items
573 m_model->setHiddenItemsShown(true);
574
575 QTRY_COMPARE(m_model->count(), m_expectedModelCount);
576 }
577
578 void PlacesItemModelTest::testSystemItems()
579 {
580 int tempDirIndex = 2;
581 increaseIndexIfNeeded(tempDirIndex);
582
583 QCOMPARE(m_model->count(), m_expectedModelCount);
584 for (int r = 0; r < m_model->count(); r++) {
585 QCOMPARE(m_model->placesItem(r)->isSystemItem(), !m_model->placesItem(r)->device().isValid());
586 }
587
588 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
589
590 // create a new entry (non system item)
591 createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
592
593 // check if the new entry was created
594 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
595
596 // make sure the new place get removed
597 schedulePlaceRemoval(tempDirIndex);
598
599 QList<QVariant> args = itemsInsertedSpy.takeFirst();
600 KItemRangeList range = args.at(0).value<KItemRangeList>();
601 QCOMPARE(range.first().index, tempDirIndex);
602 QCOMPARE(range.first().count, 1);
603 QVERIFY(!m_model->placesItem(tempDirIndex)->isSystemItem());
604 QCOMPARE(m_model->count(), m_expectedModelCount + 1);
605
606 QTest::qWait(300);
607 // check if the removal signal is correct
608 QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
609 m_model->deleteItem(tempDirIndex);
610 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
611 args = itemsRemovedSpy.takeFirst();
612 range = args.at(0).value<KItemRangeList>();
613 QCOMPARE(range.first().index, tempDirIndex);
614 QCOMPARE(range.first().count, 1);
615 QTRY_COMPARE(m_model->count(), m_expectedModelCount);
616
617 //cancel removal (it was removed above)
618 cancelPlaceRemoval(tempDirIndex);
619 }
620
621 void PlacesItemModelTest::testEditBookmark()
622 {
623 int tempDirIndex = 2;
624 increaseIndexIfNeeded(tempDirIndex);
625
626 QScopedPointer<PlacesItemModel> other(new PlacesItemModel());
627
628 createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
629
630 // make sure that the new item will be removed later
631 schedulePlaceRemoval(tempDirIndex);
632
633 QSignalSpy itemsChangedSply(m_model, &PlacesItemModel::itemsChanged);
634
635 // modify place text
636 m_model->item(tempDirIndex)->setText(QStringLiteral("Renamed place"));
637 m_model->refresh();
638
639 // check if the correct signal was fired
640 QTRY_COMPARE(itemsChangedSply.count(), 1);
641 QList<QVariant> args = itemsChangedSply.takeFirst();
642 KItemRangeList range = args.at(0).value<KItemRangeList>();
643 QCOMPARE(range.first().index, tempDirIndex);
644 QCOMPARE(range.first().count, 1);
645 QSet<QByteArray> roles = args.at(1).value<QSet<QByteArray> >();
646 QCOMPARE(roles.size(), 1);
647 QCOMPARE(*roles.begin(), QByteArrayLiteral("text"));
648 QCOMPARE(m_model->item(tempDirIndex)->text(), QStringLiteral("Renamed place"));
649
650 // check if the item was updated in the other model
651 QTRY_COMPARE(other->item(tempDirIndex)->text(), QStringLiteral("Renamed place"));
652 }
653
654 void PlacesItemModelTest::testEditAfterCreation()
655 {
656 int tempDirIndex = 2;
657 increaseIndexIfNeeded(tempDirIndex);
658
659 const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
660 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
661
662 // create a new place
663 createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
664 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
665
666 PlacesItemModel *model = new PlacesItemModel();
667 QTRY_COMPARE(model->count(), m_model->count());
668
669 // make sure that the new item will be removed later
670 schedulePlaceRemoval(tempDirIndex);
671
672 // modify place text
673 PlacesItem *item = m_model->placesItem(tempDirIndex);
674 item->setText(QStringLiteral("Renamed place"));
675 m_model->refresh();
676
677 // check if the second model got the changes
678 QTRY_COMPARE(model->count(), m_model->count());
679 QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), m_model->placesItem(tempDirIndex)->text());
680 QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
681 m_model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
682 QTRY_COMPARE(model->placesItem(tempDirIndex)->icon(), m_model->placesItem(tempDirIndex)->icon());
683 QTRY_COMPARE(model->placesItem(tempDirIndex)->url(), m_model->placesItem(tempDirIndex)->url());
684 }
685
686 void PlacesItemModelTest::testEditMetadata()
687 {
688 int tempDirIndex = 2;
689 increaseIndexIfNeeded(tempDirIndex);
690
691 const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
692 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
693
694 // create a new place
695 createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
696 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
697
698 // check if the new entry was created
699 PlacesItemModel *model = new PlacesItemModel();
700 QTRY_COMPARE(model->count(), m_model->count());
701
702 // make sure that the new item will be removed later
703 schedulePlaceRemoval(tempDirIndex);
704
705 // modify place metadata
706 auto bookmark = m_model->placesItem(tempDirIndex)->bookmark();
707 bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
708 m_model->refresh();
709
710 // check if the place was modified in both models
711 QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
712 KAboutData::applicationData().componentName());
713 QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), m_model->placesItem(tempDirIndex)->text());
714 QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
715 m_model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
716 QTRY_COMPARE(model->placesItem(tempDirIndex)->icon(), m_model->placesItem(tempDirIndex)->icon());
717 QTRY_COMPARE(model->placesItem(tempDirIndex)->url(), m_model->placesItem(tempDirIndex)->url());
718 }
719
720 void PlacesItemModelTest::testRefresh()
721 {
722 int tempDirIndex = 2;
723 increaseIndexIfNeeded(tempDirIndex);
724
725 const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
726 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
727
728 // create a new place
729 createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
730 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
731
732 PlacesItemModel *model = new PlacesItemModel();
733 QTRY_COMPARE(model->count(), m_model->count());
734
735 // make sure that the new item will be removed later
736 schedulePlaceRemoval(tempDirIndex);
737
738 PlacesItem *item = m_model->placesItem(tempDirIndex);
739 PlacesItem *sameItem = model->placesItem(tempDirIndex);
740 QCOMPARE(item->text(), sameItem->text());
741
742 // modify place text
743 item->setText(QStringLiteral("Renamed place"));
744
745 // item from another model is not affected at the moment
746 QVERIFY(item->text() != sameItem->text());
747
748 // propagate change
749 m_model->refresh();
750
751 // item must be equal
752 QTRY_COMPARE(item->text(), sameItem->text());
753 }
754
755 void PlacesItemModelTest::testIcons_data()
756 {
757 QTest::addColumn<QUrl>("url");
758 QTest::addColumn<QString>("expectedIconName");
759
760 // places
761 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << QStringLiteral("user-home");
762
763 // baloo -search
764 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << QStringLiteral("folder-text");
765
766 // devices
767 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << QStringLiteral("blockdevice");
768 }
769
770 void PlacesItemModelTest::testIcons()
771 {
772 QFETCH(QUrl, url);
773 QFETCH(QString, expectedIconName);
774
775 PlacesItem *item = m_model->placesItem(indexOf(url));
776 QCOMPARE(item->icon(), expectedIconName);
777
778 for (int r = 0; r < m_model->count(); r++) {
779 QVERIFY(!m_model->placesItem(r)->icon().isEmpty());
780 }
781 }
782
783 void PlacesItemModelTest::testDragAndDrop()
784 {
785 int lastIndex = 1; // last index of places group
786 increaseIndexIfNeeded(lastIndex);
787
788 QList<QVariant> args;
789 KItemRangeList range;
790 QStringList urls = initialUrls();
791
792 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
793 QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
794
795 CHECK_PLACES_URLS(initialUrls());
796 // Move the home directory to the end of the places group
797 QMimeData *dropData = createMimeData(QList<int>() << 0);
798 m_model->dropMimeDataBefore(m_model->count() - 1, dropData);
799 urls.move(0, lastIndex);
800 delete dropData;
801
802 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
803 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
804
805 // remove item from actual position
806 args = itemsRemovedSpy.takeFirst();
807 range = args.at(0).value<KItemRangeList>();
808 QCOMPARE(range.size(), 1);
809 QCOMPARE(range.at(0).count, 1);
810 QCOMPARE(range.at(0).index, 0);
811
812 // insert intem in his group
813 args = itemsInsertedSpy.takeFirst();
814 range = args.at(0).value<KItemRangeList>();
815 QCOMPARE(range.size(), 1);
816 QCOMPARE(range.at(0).count, 1);
817 QCOMPARE(range.at(0).index, lastIndex);
818
819 CHECK_PLACES_URLS(urls);
820
821 itemsInsertedSpy.clear();
822 itemsRemovedSpy.clear();
823
824 // Move home directory item back to its original position
825 dropData = createMimeData(QList<int>() << lastIndex);
826 m_model->dropMimeDataBefore(0, dropData);
827 urls.move(lastIndex, 0);
828 delete dropData;
829
830 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
831 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
832
833 // remove item from actual position
834 args = itemsRemovedSpy.takeFirst();
835 range = args.at(0).value<KItemRangeList>();
836 QCOMPARE(range.size(), 1);
837 QCOMPARE(range.at(0).count, 1);
838 QCOMPARE(range.at(0).index, lastIndex);
839
840 // insert intem in the requested position
841 args = itemsInsertedSpy.takeFirst();
842 range = args.at(0).value<KItemRangeList>();
843 QCOMPARE(range.size(), 1);
844 QCOMPARE(range.at(0).count, 1);
845 QCOMPARE(range.at(0).index, 0);
846
847 CHECK_PLACES_URLS(urls);
848 }
849
850 void PlacesItemModelTest::testHideDevices()
851 {
852 QSignalSpy itemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
853 QStringList urls = initialUrls();
854
855 m_model->setGroupHidden(KFilePlacesModel::RemovableDevicesType, true);
856 QTRY_VERIFY(m_model->isGroupHidden(KFilePlacesModel::RemovableDevicesType));
857 QTRY_COMPARE(itemsRemoved.count(), 3);
858
859 // remove removable-devices
860 urls.removeOne(QStringLiteral("/media/floppy0"));
861 urls.removeOne(QStringLiteral("/media/XO-Y4"));
862 urls.removeOne(QStringLiteral("/media/cdrom"));
863
864 // check if the correct urls was removed
865 CHECK_PLACES_URLS(urls);
866
867 delete m_model;
868 m_model = new PlacesItemModel();
869 QTRY_COMPARE(m_model->count(), urls.count());
870 CHECK_PLACES_URLS(urls);
871
872 // revert changes
873 m_model->setGroupHidden(KFilePlacesModel::RemovableDevicesType, false);
874 urls = initialUrls();
875 QTRY_COMPARE(m_model->count(), urls.count());
876 CHECK_PLACES_URLS(urls);
877 }
878
879 void PlacesItemModelTest::testDuplicatedEntries()
880 {
881 QStringList urls = initialUrls();
882 // create a duplicated entry on bookmark
883 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces"));
884 KBookmarkGroup root = bookmarkManager->root();
885 KBookmark bookmark = root.addBookmark(QStringLiteral("Duplicated Search Videos"), QUrl("search:/videos"), {});
886
887 const QString id = QUuid::createUuid().toString();
888 bookmark.setMetaDataItem(QStringLiteral("ID"), id);
889 bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
890 bookmarkManager->emitChanged(bookmarkManager->root());
891
892 PlacesItemModel *newModel = new PlacesItemModel();
893 QTRY_COMPARE(placesUrls(newModel).count(QStringLiteral("search:/videos")), 1);
894 QTRY_COMPARE(urls, placesUrls(newModel));
895 delete newModel;
896 }
897
898 void PlacesItemModelTest::renameAfterCreation()
899 {
900 int tempDirIndex = 2;
901 increaseIndexIfNeeded(tempDirIndex);
902
903 const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
904 QStringList urls = initialUrls();
905 PlacesItemModel *model = new PlacesItemModel();
906
907 CHECK_PLACES_URLS(urls);
908 QTRY_COMPARE(model->count(), m_model->count());
909
910 // create a new place
911 createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
912 urls.insert(tempDirIndex, tempUrl.toLocalFile());
913
914 // make sure that the new item will be removed later
915 schedulePlaceRemoval(tempDirIndex);
916
917 CHECK_PLACES_URLS(urls);
918 QCOMPARE(model->count(), m_model->count());
919
920
921 // modify place text
922 QSignalSpy changedSpy(m_model, &PlacesItemModel::itemsChanged);
923
924 PlacesItem *item = m_model->placesItem(tempDirIndex);
925 item->setText(QStringLiteral("New Temporary Dir"));
926 item->setUrl(item->url());
927 item->setIcon(item->icon());
928 m_model->refresh();
929
930 QTRY_COMPARE(changedSpy.count(), 1);
931
932 // check if the place was modified in both models
933 QTRY_COMPARE(m_model->placesItem(tempDirIndex)->text(), QStringLiteral("New Temporary Dir"));
934 QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), QStringLiteral("New Temporary Dir"));
935 }
936
937 QTEST_MAIN(PlacesItemModelTest)
938
939 #include "placesitemmodeltest.moc"