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