]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/placesitemmodeltest.cpp
5eb65e076dd914e48a6e59fb6073f1894f027658
[dolphin.git] / src / tests / placesitemmodeltest.cpp
1 /***************************************************************************
2 * Copyright (C) 2017 by Renato Araujo Oliveira <renato.araujo@kdab.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include <QTest>
21 #include <QSignalSpy>
22 #include <QDebug>
23 #include <QList>
24 #include <QByteArray>
25 #include <QStandardPaths>
26 #include <QAction>
27 #include <QDBusInterface>
28
29 #include <KBookmarkManager>
30 #include <KConfig>
31 #include <KConfigGroup>
32 #include <KAboutData>
33
34 #include "panels/places/placesitemmodel.h"
35 #include "panels/places/placesitem.h"
36 #include "views/viewproperties.h"
37 #include "kitemviews/kitemrange.h"
38
39 Q_DECLARE_METATYPE(KItemRangeList)
40 Q_DECLARE_METATYPE(PlacesItem::GroupType)
41
42 #ifdef Q_OS_WIN
43 //c:\ as root for windows
44 #define KDE_ROOT_PATH "C:\\"
45 #else
46 #define KDE_ROOT_PATH "/"
47 #endif
48
49 static QString bookmarksFile()
50 {
51 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/user-places.xbel";
52 }
53
54 class PlacesItemModelTest : public QObject
55 {
56 Q_OBJECT
57
58 private slots:
59 void init();
60 void cleanup();
61
62 void initTestCase();
63 void cleanupTestCase();
64
65 void testModelSort();
66 void testModelMove();
67 void testGroups();
68 void testPlaceItem_data();
69 void testPlaceItem();
70 void testTearDownDevice();
71 void testDefaultViewProperties_data();
72 void testDefaultViewProperties();
73 void testClear();
74 void testHideItem();
75 void testSystemItems();
76 void testEditBookmark();
77 void testEditAfterCreation();
78 void testEditMetadata();
79
80 private:
81 PlacesItemModel* m_model;
82 QMap<QString, QDBusInterface *> m_interfacesMap;
83
84 void setBalooEnabled(bool enabled);
85 int indexOf(const QUrl &url);
86 QDBusInterface *fakeManager();
87 QDBusInterface *fakeDevice(const QString &udi);
88 QStringList placesUrls() const;
89 QStringList initialUrls() const;
90 void createPlaceItem(const QString &text, const QUrl &url, const QString &icon);
91 };
92
93 #define CHECK_PLACES_URLS(urls) \
94 QStringList tmp(urls); \
95 QStringList places = placesUrls(); \
96 while(!places.isEmpty()) { \
97 tmp.removeOne(places.takeFirst()); \
98 } \
99 if (!tmp.isEmpty()) { \
100 qWarning() << "Expected:" << urls; \
101 qWarning() << "Got:" << places; \
102 QCOMPARE(places, urls); \
103 }
104
105 void PlacesItemModelTest::setBalooEnabled(bool enabled)
106 {
107 KConfig config(QStringLiteral("baloofilerc"));
108 KConfigGroup basicSettings = config.group("Basic Settings");
109 basicSettings.writeEntry("Indexing-Enabled", enabled);
110 config.sync();
111 }
112
113 int PlacesItemModelTest::indexOf(const QUrl &url)
114 {
115 for (int r = 0; r < m_model->count(); r++) {
116 if (m_model->placesItem(r)->url() == url) {
117 return r;
118 }
119 }
120 return -1;
121 }
122
123 QDBusInterface *PlacesItemModelTest::fakeManager()
124 {
125 return fakeDevice(QStringLiteral("/org/kde/solid/fakehw"));
126 }
127
128 QDBusInterface *PlacesItemModelTest::fakeDevice(const QString &udi)
129 {
130 if (m_interfacesMap.contains(udi)) {
131 return m_interfacesMap[udi];
132 }
133
134 QDBusInterface *iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), udi);
135 m_interfacesMap[udi] = iface;
136
137 return iface;
138 }
139
140 QStringList PlacesItemModelTest::placesUrls() const
141 {
142 QStringList urls;
143 for (int row = 0; row < m_model->count(); ++row) {
144 urls << m_model->placesItem(row)->url().toDisplayString(QUrl::PreferLocalFile);
145 }
146 return urls;
147 }
148
149 void PlacesItemModelTest::createPlaceItem(const QString &text, const QUrl &url, const QString &icon)
150 {
151 PlacesItem *item = m_model->createPlacesItem(text,
152 url,
153 icon);
154 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
155 m_model->appendItemToGroup(item);
156 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
157 }
158
159 void PlacesItemModelTest::init()
160 {
161 m_model = new PlacesItemModel();
162 // WORKAROUND: need to wait for bookmark to load, check: PlacesItemModel::updateBookmarks
163 QTest::qWait(300);
164 QCOMPARE(m_model->count(), 17);
165 }
166
167 void PlacesItemModelTest::cleanup()
168 {
169 delete m_model;
170 m_model = nullptr;
171 }
172
173 void PlacesItemModelTest::initTestCase()
174 {
175 QStandardPaths::setTestModeEnabled(true);
176
177 const QString fakeHw = QFINDTESTDATA("data/fakecomputer.xml");
178 QVERIFY(!fakeHw.isEmpty());
179 qputenv("SOLID_FAKEHW", QFile::encodeName(fakeHw));
180
181 setBalooEnabled(true);
182 const QString bookmarsFileName = bookmarksFile();
183 if (QFileInfo::exists(bookmarsFileName)) {
184 // Ensure we'll have a clean bookmark file to start
185 QVERIFY(QFile::remove(bookmarsFileName));
186 }
187
188 qRegisterMetaType<KItemRangeList>();
189 }
190
191 void PlacesItemModelTest::cleanupTestCase()
192 {
193 qDeleteAll(m_interfacesMap);
194 QFile::remove(bookmarksFile());
195 }
196
197 QStringList PlacesItemModelTest::initialUrls() const
198 {
199 QStringList urls;
200
201 urls << QDir::homePath() << QStringLiteral("remote:/") << QStringLiteral(KDE_ROOT_PATH) << QStringLiteral("trash:/")
202 << QStringLiteral("timeline:/today") << QStringLiteral("timeline:/yesterday") << QStringLiteral("timeline:/thismonth") << QStringLiteral("timeline:/lastmonth")
203 << QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
204 << QStringLiteral("/media/cdrom") << QStringLiteral("/foreign") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/nfs") << QStringLiteral("/media/floppy0");
205
206 return urls;
207 }
208
209 void PlacesItemModelTest::testModelSort()
210 {
211 CHECK_PLACES_URLS(initialUrls());
212 }
213
214 void PlacesItemModelTest::testModelMove()
215 {
216 QStringList urls = initialUrls();
217 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces"));
218 KBookmarkGroup root = bookmarkManager->root();
219 KBookmark systemRoot = m_model->placesItem(1)->bookmark();
220 KBookmark last = m_model->placesItem(m_model->count() - 1)->bookmark();
221
222 // try to move the "root" path to the end of the list
223 root.moveBookmark(systemRoot, last);
224 bookmarkManager->emitChanged(root);
225
226 // make sure that the items still grouped and the "root" item was moved to the end of places group instead
227 urls.move(1, 2);
228 CHECK_PLACES_URLS(urls);
229 }
230
231 void PlacesItemModelTest::testGroups()
232 {
233 const auto groups = m_model->groups();
234
235 QCOMPARE(groups.size(), 4);
236 QCOMPARE(groups.at(0).first, 0);
237 QCOMPARE(groups.at(0).second.toString(), QStringLiteral("Places"));
238 QCOMPARE(groups.at(1).first, 4);
239 QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Recently Saved"));
240 QCOMPARE(groups.at(2).first, 8);
241 QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Search For"));
242 QCOMPARE(groups.at(3).first, 12);
243 QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Devices"));
244 }
245
246 void PlacesItemModelTest::testPlaceItem_data()
247 {
248 QTest::addColumn<QUrl>("url");
249 QTest::addColumn<bool>("expectedIsHidden");
250 QTest::addColumn<bool>("expectedIsSystemItem");
251 QTest::addColumn<PlacesItem::GroupType>("expectedGroupType");
252 QTest::addColumn<bool>("expectedStorageSetupNeeded");
253
254 // places
255 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << false << true << PlacesItem::PlacesType << false;
256
257 // baloo -search
258 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << PlacesItem::SearchForType << false;
259
260 // baloo - timeline
261 QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") << false << true << PlacesItem::RecentlySavedType << false;
262
263 // devices
264 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << PlacesItem::DevicesType << false;
265 }
266
267 void PlacesItemModelTest::testPlaceItem()
268 {
269 QFETCH(QUrl, url);
270 QFETCH(bool, expectedIsHidden);
271 QFETCH(bool, expectedIsSystemItem);
272 QFETCH(PlacesItem::GroupType, expectedGroupType);
273 QFETCH(bool, expectedStorageSetupNeeded);
274
275 const int index = indexOf(url);
276 PlacesItem *item = m_model->placesItem(index);
277 QCOMPARE(item->url(), url);
278 QCOMPARE(item->isHidden(), expectedIsHidden);
279 QCOMPARE(item->isSystemItem(), expectedIsSystemItem);
280 QCOMPARE(item->groupType(), expectedGroupType);
281 QCOMPARE(item->storageSetupNeeded(), expectedStorageSetupNeeded);
282 }
283
284 void PlacesItemModelTest::testTearDownDevice()
285 {
286 const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
287 int index = indexOf(mediaUrl);
288 QVERIFY(index != -1);
289
290 auto ejectAction = m_model->ejectAction(index);
291 QVERIFY(!ejectAction);
292
293 auto teardownAction = m_model->teardownAction(index);
294 QVERIFY(teardownAction);
295
296 QCOMPARE(m_model->count(), 17);
297
298 QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
299 fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
300 QTRY_COMPARE(m_model->count(), 16);
301 QCOMPARE(spyItemsRemoved.count(), 1);
302 const QList<QVariant> spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
303 const KItemRangeList removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
304 QCOMPARE(removedRange.size(), 1);
305 QCOMPARE(removedRange.first().index, index);
306 QCOMPARE(removedRange.first().count, 1);
307
308 QCOMPARE(indexOf(mediaUrl), -1);
309
310 QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
311 fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
312 QTRY_COMPARE(m_model->count(), 17);
313 QCOMPARE(spyItemsInserted.count(), 1);
314 index = indexOf(mediaUrl);
315
316 const QList<QVariant> args = spyItemsInserted.takeFirst();
317 const KItemRangeList insertedRange = args.at(0).value<KItemRangeList>();
318 QCOMPARE(insertedRange.size(), 1);
319 QCOMPARE(insertedRange.first().index, index);
320 QCOMPARE(insertedRange.first().count, 1);
321 }
322
323 void PlacesItemModelTest::testDefaultViewProperties_data()
324 {
325 QTest::addColumn<QUrl>("url");
326 QTest::addColumn<DolphinView::Mode>("expectedViewMode");
327 QTest::addColumn<bool>("expectedPreviewShow");
328 QTest::addColumn<QList<QByteArray> >("expectedVisibleRole");
329
330 // places
331 QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << DolphinView::IconsView << true << QList<QByteArray>({"text"});
332
333 // baloo -search
334 QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "path"});
335
336 // audio files
337 QTest::newRow("Places - Audio") << QUrl("search:/audio") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "artist", "album"});
338
339 // baloo - timeline
340 QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") << DolphinView::DetailsView << true << QList<QByteArray>({"text", "modificationtime"});
341
342 // devices
343 QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << DolphinView::IconsView << true << QList<QByteArray>({"text"});
344
345 }
346
347 void PlacesItemModelTest::testDefaultViewProperties()
348 {
349 QFETCH(QUrl, url);
350 QFETCH(DolphinView::Mode, expectedViewMode);
351 QFETCH(bool, expectedPreviewShow);
352 QFETCH(QList<QByteArray>, expectedVisibleRole);
353
354 ViewProperties properties(m_model->convertedUrl(url));
355 QCOMPARE(properties.viewMode(), expectedViewMode);
356 QCOMPARE(properties.previewsShown(), expectedPreviewShow);
357 QCOMPARE(properties.visibleRoles(), expectedVisibleRole);
358 }
359
360 void PlacesItemModelTest::testClear()
361 {
362 QCOMPARE(m_model->count(), 17);
363 m_model->clear();
364 QCOMPARE(m_model->count(), 0);
365 QCOMPARE(m_model->hiddenCount(), 0);
366 }
367
368 void PlacesItemModelTest::testHideItem()
369 {
370 const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
371 const int index = indexOf(mediaUrl);
372
373 PlacesItem *item = m_model->placesItem(index);
374
375 QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
376 QList<QVariant> spyItemsRemovedArgs;
377 KItemRangeList removedRange;
378
379 QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
380 QList<QVariant> spyItemsInsertedArgs;
381 KItemRangeList insertedRange;
382 QVERIFY(item);
383
384 // hide an item
385 item->setHidden(true);
386
387 // check if items removed was fired
388 QTRY_COMPARE(m_model->count(), 16);
389 QCOMPARE(spyItemsRemoved.count(), 1);
390 spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
391 removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
392 QCOMPARE(removedRange.size(), 1);
393 QCOMPARE(removedRange.first().index, index);
394 QCOMPARE(removedRange.first().count, 1);
395
396 // allow model to show hidden items
397 m_model->setHiddenItemsShown(true);
398
399 // check if the items inserted was fired
400 spyItemsInsertedArgs = spyItemsInserted.takeFirst();
401 insertedRange = spyItemsInsertedArgs.at(0).value<KItemRangeList>();
402 QCOMPARE(insertedRange.size(), 1);
403 QCOMPARE(insertedRange.first().index, index);
404 QCOMPARE(insertedRange.first().count, 1);
405
406 // mark item as visible
407 item = m_model->placesItem(index);
408 item->setHidden(false);
409
410 // mark model to hide invisible items
411 m_model->setHiddenItemsShown(true);
412
413 QTRY_COMPARE(m_model->count(), 17);
414 }
415
416 void PlacesItemModelTest::testSystemItems()
417 {
418 QCOMPARE(m_model->count(), 17);
419 for (int r = 0; r < m_model->count(); r++) {
420 QCOMPARE(m_model->placesItem(r)->isSystemItem(), !m_model->placesItem(r)->device().isValid());
421 }
422
423 // create a new entry (non system item)
424 PlacesItem *item = m_model->createPlacesItem(QStringLiteral("Temporary Dir"),
425 QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)),
426 QString());
427
428 QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
429 m_model->appendItemToGroup(item);
430
431 // check if the new entry was created
432 QTRY_COMPARE(itemsInsertedSpy.count(), 1);
433 QList<QVariant> args = itemsInsertedSpy.takeFirst();
434 KItemRangeList range = args.at(0).value<KItemRangeList>();
435 QCOMPARE(range.first().index, 4);
436 QCOMPARE(range.first().count, 1);
437 QVERIFY(!m_model->placesItem(4)->isSystemItem());
438 QCOMPARE(m_model->count(), 18);
439
440 // remove new entry
441 QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
442 m_model->removeItem(4);
443 m_model->saveBookmarks();
444 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
445 args = itemsRemovedSpy.takeFirst();
446 range = args.at(0).value<KItemRangeList>();
447 QCOMPARE(range.first().index, 4);
448 QCOMPARE(range.first().count, 1);
449 QTRY_COMPARE(m_model->count(), 17);
450 }
451
452 void PlacesItemModelTest::testEditBookmark()
453 {
454 QScopedPointer<PlacesItemModel> other(new PlacesItemModel());
455
456 createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
457
458 QSignalSpy itemsChangedSply(m_model, &PlacesItemModel::itemsChanged);
459 m_model->item(4)->setText(QStringLiteral("Renamed place"));
460 m_model->saveBookmarks();
461 QTRY_COMPARE(itemsChangedSply.count(), 1);
462 QList<QVariant> args = itemsChangedSply.takeFirst();
463 KItemRangeList range = args.at(0).value<KItemRangeList>();
464 QCOMPARE(range.first().index, 4);
465 QCOMPARE(range.first().count, 1);
466 QSet<QByteArray> roles = args.at(1).value<QSet<QByteArray> >();
467 QCOMPARE(roles.size(), 1);
468 QCOMPARE(*roles.begin(), QByteArrayLiteral("text"));
469 QCOMPARE(m_model->item(4)->text(), QStringLiteral("Renamed place"));
470
471 // check if the item was updated in the other model
472 QTRY_COMPARE(other->item(4)->text(), QStringLiteral("Renamed place"));
473
474 // remove new entry
475 QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
476 m_model->removeItem(4);
477 m_model->saveBookmarks();
478 QTRY_COMPARE(itemsRemovedSpy.count(), 1);
479 args = itemsRemovedSpy.takeFirst();
480 range = args.at(0).value<KItemRangeList>();
481 QCOMPARE(range.first().index, 4);
482 QCOMPARE(range.first().count, 1);
483 QTRY_COMPARE(m_model->count(), 17);
484 }
485
486 void PlacesItemModelTest::testEditAfterCreation()
487 {
488 createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
489
490 PlacesItemModel *model = new PlacesItemModel();
491 QTRY_COMPARE(model->count(), m_model->count());
492
493 PlacesItem *item = m_model->placesItem(4);
494 item->setText(QStringLiteral("Renamed place"));
495 m_model->saveBookmarks();
496
497 QTRY_COMPARE(model->count(), m_model->count());
498 QTRY_COMPARE(model->placesItem(4)->text(), m_model->placesItem(4)->text());
499 QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
500 m_model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
501 QTRY_COMPARE(model->placesItem(4)->icon(), m_model->placesItem(4)->icon());
502 QTRY_COMPARE(model->placesItem(4)->url(), m_model->placesItem(4)->url());
503
504 m_model->removeItem(4);
505 m_model->saveBookmarks();
506 QTRY_COMPARE(model->count(), m_model->count());
507 }
508
509 void PlacesItemModelTest::testEditMetadata()
510 {
511 createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
512
513 PlacesItemModel *model = new PlacesItemModel();
514 QTRY_COMPARE(model->count(), m_model->count());
515
516 PlacesItem *item = m_model->placesItem(4);
517 item->bookmark().setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
518 m_model->saveBookmarks();
519
520 QTRY_COMPARE(model->count(), m_model->count());
521 QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
522 KAboutData::applicationData().componentName());
523 QTRY_COMPARE(model->placesItem(4)->text(), m_model->placesItem(4)->text());
524 QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
525 m_model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
526 QTRY_COMPARE(model->placesItem(4)->icon(), m_model->placesItem(4)->icon());
527 QTRY_COMPARE(model->placesItem(4)->url(), m_model->placesItem(4)->url());
528
529 m_model->removeItem(4);
530 m_model->saveBookmarks();
531 QTRY_COMPARE(model->count(), m_model->count());
532 }
533
534 QTEST_MAIN(PlacesItemModelTest)
535
536 #include "placesitemmodeltest.moc"