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