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