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