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