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