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