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