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