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