]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/kitemlistselectionmanagertest.cpp
7f79197a90229d71fe5f59eb361899f95b198628
[dolphin.git] / src / tests / kitemlistselectionmanagertest.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * Copyright (C) 2011 by Frank Reininghaus <frank78ac@googlemail.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include <qtest_kde.h>
22
23 #include "kitemviews/kitemmodelbase.h"
24 #include "kitemviews/kitemlistselectionmanager.h"
25
26 class DummyModel : public KItemModelBase
27 {
28 public:
29 DummyModel();
30 void setCount(int count);
31 virtual int count() const;
32 virtual QHash<QByteArray, QVariant> data(int index) const;
33
34 private:
35 int m_count;
36 };
37
38 DummyModel::DummyModel() :
39 KItemModelBase(),
40 m_count(100)
41 {
42 }
43
44 void DummyModel::setCount(int count)
45 {
46 m_count = count;
47 }
48
49 int DummyModel::count() const
50 {
51 return m_count;
52 }
53
54 QHash<QByteArray, QVariant> DummyModel::data(int index) const
55 {
56 Q_UNUSED(index);
57 return QHash<QByteArray, QVariant>();
58 }
59
60
61 class KItemListSelectionManagerTest : public QObject
62 {
63 Q_OBJECT
64
65 private slots:
66 void init();
67 void cleanup();
68
69 void testConstructor();
70
71 void testCurrentItemAnchorItem();
72 void testSetSelected_data();
73 void testSetSelected();
74 void testItemsInserted();
75 void testItemsRemoved();
76 void testAnchoredSelection();
77 void testChangeSelection_data();
78 void testChangeSelection();
79 void testDeleteCurrentItem_data();
80 void testDeleteCurrentItem();
81
82 private:
83 void verifySelectionChange(QSignalSpy& spy, const QSet<int>& currentSelection, const QSet<int>& previousSelection) const;
84
85 KItemListSelectionManager* m_selectionManager;
86 DummyModel* m_model;
87 };
88
89 void KItemListSelectionManagerTest::init()
90 {
91 m_model = new DummyModel();
92 m_selectionManager = new KItemListSelectionManager();
93 m_selectionManager->setModel(m_model);
94 }
95
96 void KItemListSelectionManagerTest::cleanup()
97 {
98 delete m_selectionManager;
99 m_selectionManager = 0;
100
101 delete m_model;
102 m_model = 0;
103 }
104
105 void KItemListSelectionManagerTest::testConstructor()
106 {
107 QVERIFY(!m_selectionManager->hasSelection());
108 QCOMPARE(m_selectionManager->selectedItems().count(), 0);
109 QCOMPARE(m_selectionManager->currentItem(), 0);
110 QCOMPARE(m_selectionManager->m_anchorItem, -1);
111 }
112
113 void KItemListSelectionManagerTest::testCurrentItemAnchorItem()
114 {
115 QSignalSpy spyCurrent(m_selectionManager, SIGNAL(currentChanged(int,int)));
116
117 // Set current item and check that the selection manager emits the currentChanged(int,int) signal correctly.
118 m_selectionManager->setCurrentItem(4);
119 QCOMPARE(m_selectionManager->currentItem(), 4);
120 QCOMPARE(spyCurrent.count(), 1);
121 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(0)), 4);
122 spyCurrent.takeFirst();
123
124 // Begin an anchored selection.
125 m_selectionManager->beginAnchoredSelection(5);
126 QVERIFY(m_selectionManager->isAnchoredSelectionActive());
127 QCOMPARE(m_selectionManager->m_anchorItem, 5);
128
129 // Items between current and anchor should be selected now
130 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 4 << 5);
131 QVERIFY(m_selectionManager->hasSelection());
132
133 // Change current item again and check the selection
134 m_selectionManager->setCurrentItem(2);
135 QCOMPARE(m_selectionManager->currentItem(), 2);
136 QCOMPARE(spyCurrent.count(), 1);
137 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(0)), 2);
138 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(1)), 4);
139 spyCurrent.takeFirst();
140
141 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 2 << 3 << 4 << 5);
142 QVERIFY(m_selectionManager->hasSelection());
143
144 // Inserting items should update current item and anchor item.
145 m_selectionManager->itemsInserted(KItemRangeList() <<
146 KItemRange(0, 1) <<
147 KItemRange(2, 2) <<
148 KItemRange(6, 3));
149
150 QCOMPARE(m_selectionManager->currentItem(), 5);
151 QCOMPARE(spyCurrent.count(), 1);
152 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(0)), 5);
153 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(1)), 2);
154 spyCurrent.takeFirst();
155
156 QCOMPARE(m_selectionManager->m_anchorItem, 8);
157
158 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7 << 8);
159 QVERIFY(m_selectionManager->hasSelection());
160
161 // Removing items should update current item and anchor item.
162 m_selectionManager->itemsRemoved(KItemRangeList() <<
163 KItemRange(0, 2) <<
164 KItemRange(2, 1) <<
165 KItemRange(9, 2));
166
167 QCOMPARE(m_selectionManager->currentItem(), 2);
168 QCOMPARE(spyCurrent.count(), 1);
169 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(0)), 2);
170 QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(1)), 5);
171 spyCurrent.takeFirst();
172
173 QCOMPARE(m_selectionManager->m_anchorItem, 5);
174
175 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 2 << 3 << 4 << 5);
176 QVERIFY(m_selectionManager->hasSelection());
177
178 // Verify that clearSelection() also clears the anchored selection.
179 m_selectionManager->clearSelection();
180 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>());
181 QVERIFY(!m_selectionManager->hasSelection());
182
183 m_selectionManager->endAnchoredSelection();
184 QVERIFY(!m_selectionManager->isAnchoredSelectionActive());
185 }
186
187 void KItemListSelectionManagerTest::testSetSelected_data()
188 {
189 QTest::addColumn<int>("index");
190 QTest::addColumn<int>("count");
191 QTest::addColumn<int>("expectedSelectionCount");
192
193 QTest::newRow("Select all") << 0 << 100 << 100;
194 QTest::newRow("Sub selection 15 items") << 20 << 15 << 15;
195 QTest::newRow("Sub selection 1 item") << 20 << 1 << 1;
196 QTest::newRow("Too small index") << -1 << 100 << 0;
197 QTest::newRow("Too large index") << 100 << 100 << 0;
198 QTest::newRow("Too large count") << 0 << 100000 << 100;
199 QTest::newRow("Too small count") << 0 << 0 << 0;
200 }
201
202 void KItemListSelectionManagerTest::testSetSelected()
203 {
204 QFETCH(int, index);
205 QFETCH(int, count);
206 QFETCH(int, expectedSelectionCount);
207 m_selectionManager->setSelected(index, count);
208 QCOMPARE(m_selectionManager->selectedItems().count(), expectedSelectionCount);
209 }
210
211 void KItemListSelectionManagerTest::testItemsInserted()
212 {
213 // Select items 10 to 12
214 m_selectionManager->setSelected(10, 3);
215 QSet<int> selectedItems = m_selectionManager->selectedItems();
216 QCOMPARE(selectedItems.count(), 3);
217 QVERIFY(selectedItems.contains(10));
218 QVERIFY(selectedItems.contains(11));
219 QVERIFY(selectedItems.contains(12));
220
221 // Insert items 0 to 4 -> selection must be 15 to 17
222 m_selectionManager->itemsInserted(KItemRangeList() << KItemRange(0, 5));
223 selectedItems = m_selectionManager->selectedItems();
224 QCOMPARE(selectedItems.count(), 3);
225 QVERIFY(selectedItems.contains(15));
226 QVERIFY(selectedItems.contains(16));
227 QVERIFY(selectedItems.contains(17));
228
229 // Insert 3 items between the selections
230 m_selectionManager->itemsInserted(KItemRangeList() <<
231 KItemRange(15, 1) <<
232 KItemRange(16, 1) <<
233 KItemRange(17, 1));
234 selectedItems = m_selectionManager->selectedItems();
235 QCOMPARE(selectedItems.count(), 3);
236 QVERIFY(selectedItems.contains(16));
237 QVERIFY(selectedItems.contains(18));
238 QVERIFY(selectedItems.contains(20));
239 }
240
241 void KItemListSelectionManagerTest::testItemsRemoved()
242 {
243 // Select items 10 to 15
244 m_selectionManager->setSelected(10, 6);
245 QSet<int> selectedItems = m_selectionManager->selectedItems();
246 QCOMPARE(selectedItems.count(), 6);
247 for (int i = 10; i <= 15; ++i) {
248 QVERIFY(selectedItems.contains(i));
249 }
250
251 // Remove items 0 to 4 -> selection must be 5 to 10
252 m_selectionManager->itemsRemoved(KItemRangeList() << KItemRange(0, 5));
253 selectedItems = m_selectionManager->selectedItems();
254 QCOMPARE(selectedItems.count(), 6);
255 for (int i = 5; i <= 10; ++i) {
256 QVERIFY(selectedItems.contains(i));
257 }
258
259 // Remove the items 6 , 8 and 10
260 m_selectionManager->itemsRemoved(KItemRangeList() <<
261 KItemRange(6, 1) <<
262 KItemRange(8, 1) <<
263 KItemRange(10, 1));
264 selectedItems = m_selectionManager->selectedItems();
265 QCOMPARE(selectedItems.count(), 3);
266 QVERIFY(selectedItems.contains(5));
267 QVERIFY(selectedItems.contains(6));
268 QVERIFY(selectedItems.contains(7));
269 }
270
271 void KItemListSelectionManagerTest::testAnchoredSelection()
272 {
273 m_selectionManager->beginAnchoredSelection(5);
274 QVERIFY(m_selectionManager->isAnchoredSelectionActive());
275 QCOMPARE(m_selectionManager->m_anchorItem, 5);
276
277 m_selectionManager->setCurrentItem(6);
278 QCOMPARE(m_selectionManager->currentItem(), 6);
279 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6);
280
281 m_selectionManager->setCurrentItem(4);
282 QCOMPARE(m_selectionManager->currentItem(), 4);
283 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 4 << 5);
284
285 m_selectionManager->setCurrentItem(7);
286 QCOMPARE(m_selectionManager->currentItem(), 7);
287 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7);
288
289 // Ending the anchored selection should not change the selected items.
290 m_selectionManager->endAnchoredSelection();
291 QVERIFY(!m_selectionManager->isAnchoredSelectionActive());
292 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7);
293
294 // Start a new anchored selection that overlaps the previous one
295 m_selectionManager->beginAnchoredSelection(9);
296 QVERIFY(m_selectionManager->isAnchoredSelectionActive());
297 QCOMPARE(m_selectionManager->m_anchorItem, 9);
298
299 m_selectionManager->setCurrentItem(6);
300 QCOMPARE(m_selectionManager->currentItem(), 6);
301 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7 << 8 << 9);
302
303 m_selectionManager->setCurrentItem(10);
304 QCOMPARE(m_selectionManager->currentItem(), 10);
305 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7 << 9 << 10);
306
307 m_selectionManager->endAnchoredSelection();
308 QVERIFY(!m_selectionManager->isAnchoredSelectionActive());
309 QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6 << 7 << 9 << 10);
310 }
311
312 namespace {
313 enum ChangeType {
314 NoChange,
315 InsertItems,
316 RemoveItems,
317 MoveItems,
318 EndAnchoredSelection,
319 SetSelected
320 };
321 }
322
323 Q_DECLARE_METATYPE(QSet<int>);
324 Q_DECLARE_METATYPE(ChangeType);
325 Q_DECLARE_METATYPE(KItemRange);
326 Q_DECLARE_METATYPE(KItemRangeList);
327 Q_DECLARE_METATYPE(KItemListSelectionManager::SelectionMode);
328 Q_DECLARE_METATYPE(QList<int>);
329
330 /**
331 * The following function provides a generic way to test the selection functionality.
332 *
333 * The test is data-driven and takes the following arguments:
334 *
335 * \param initialSelection The selection at the beginning.
336 * \param anchor This item will be the anchor item.
337 * \param current This item will be the current item.
338 * \param expectedSelection Expected selection after anchor and current are set.
339 * \param changeType Type of the change that is done then:
340 * - NoChange
341 * - InsertItems -> data.at(0) provides the KItemRangeList. \sa KItemListSelectionManager::itemsInserted()
342 * - RemoveItems -> data.at(0) provides the KItemRangeList. \sa KItemListSelectionManager::itemsRemoved()
343 * - MoveItems -> data.at(0) provides the KItemRange containing the original indices,
344 * data.at(1) provides the list containing the new indices
345 * \sa KItemListSelectionManager::itemsMoved(), KItemModelBase::itemsMoved()
346 * - EndAnchoredSelection
347 * - SetSelected -> data.at(0) provides the index where the selection process starts,
348 * data.at(1) provides the number of indices to be selected,
349 * data.at(2) provides the selection mode.
350 * \sa KItemListSelectionManager::setSelected()
351 * \param data A list of QVariants which will be cast to the arguments needed for the chosen ChangeType (see above).
352 * \param finalSelection The expected final selection.
353 *
354 */
355
356 void KItemListSelectionManagerTest::testChangeSelection_data()
357 {
358 QTest::addColumn<QSet<int> >("initialSelection");
359 QTest::addColumn<int>("anchor");
360 QTest::addColumn<int>("current");
361 QTest::addColumn<QSet<int> >("expectedSelection");
362 QTest::addColumn<ChangeType>("changeType");
363 QTest::addColumn<QList<QVariant> >("data");
364 QTest::addColumn<QSet<int> >("finalSelection");
365
366 QTest::newRow("No change")
367 << (QSet<int>() << 5 << 6)
368 << 2 << 3
369 << (QSet<int>() << 2 << 3 << 5 << 6)
370 << NoChange
371 << QList<QVariant>()
372 << (QSet<int>() << 2 << 3 << 5 << 6);
373
374 QTest::newRow("Insert Items")
375 << (QSet<int>() << 5 << 6)
376 << 2 << 3
377 << (QSet<int>() << 2 << 3 << 5 << 6)
378 << InsertItems
379 << (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(5, 2) << KItemRange(10, 5)))
380 << (QSet<int>() << 3 << 4 << 8 << 9);
381
382 QTest::newRow("Remove Items")
383 << (QSet<int>() << 5 << 6)
384 << 2 << 3
385 << (QSet<int>() << 2 << 3 << 5 << 6)
386 << RemoveItems
387 << (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(3, 1) << KItemRange(10, 5)))
388 << (QSet<int>() << 1 << 2 << 3 << 4);
389
390 QTest::newRow("Empty Anchored Selection")
391 << QSet<int>()
392 << 2 << 2
393 << QSet<int>()
394 << EndAnchoredSelection
395 << QList<QVariant>()
396 << QSet<int>();
397
398 QTest::newRow("Toggle selection")
399 << (QSet<int>() << 1 << 3 << 4)
400 << 6 << 8
401 << (QSet<int>() << 1 << 3 << 4 << 6 << 7 << 8)
402 << SetSelected
403 << (QList<QVariant>() << 0 << 10 << QVariant::fromValue(KItemListSelectionManager::Toggle))
404 << (QSet<int>() << 0 << 2 << 5 << 9);
405
406 // Swap items 2, 3 and 4, 5
407 QTest::newRow("Move items")
408 << (QSet<int>() << 0 << 1 << 2 << 3)
409 << -1 << -1
410 << (QSet<int>() << 0 << 1 << 2 << 3)
411 << MoveItems
412 << (QList<QVariant>() << QVariant::fromValue(KItemRange(2, 4))
413 << QVariant::fromValue(QList<int>() << 4 << 5 << 2 << 3))
414 << (QSet<int>() << 0 << 1 << 4 << 5);
415
416 // Revert sort order
417 QTest::newRow("Revert sort order")
418 << (QSet<int>() << 0 << 1)
419 << 3 << 4
420 << (QSet<int>() << 0 << 1 << 3 << 4)
421 << MoveItems
422 << (QList<QVariant>() << QVariant::fromValue(KItemRange(0, 10))
423 << QVariant::fromValue(QList<int>() << 9 << 8 << 7 << 6 << 5 << 4 << 3 << 2 << 1 << 0))
424 << (QSet<int>() << 5 << 6 << 8 << 9);
425 }
426
427 void KItemListSelectionManagerTest::testChangeSelection()
428 {
429 QFETCH(QSet<int>, initialSelection);
430 QFETCH(int, anchor);
431 QFETCH(int, current);
432 QFETCH(QSet<int>, expectedSelection);
433 QFETCH(ChangeType, changeType);
434 QFETCH(QList<QVariant>, data);
435 QFETCH(QSet<int>, finalSelection);
436
437 QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)));
438
439 // Initial selection should be empty
440 QVERIFY(!m_selectionManager->hasSelection());
441 QVERIFY(m_selectionManager->selectedItems().isEmpty());
442
443 // Perform the initial selectiion
444 m_selectionManager->setSelectedItems(initialSelection);
445
446 verifySelectionChange(spySelectionChanged, initialSelection, QSet<int>());
447
448 // Perform an anchored selection.
449 // Note that current and anchor index are equal first because this is the case in typical uses of the
450 // selection manager, and because this makes it easier to test the correctness of the signal's arguments.
451 m_selectionManager->setCurrentItem(anchor);
452 m_selectionManager->beginAnchoredSelection(anchor);
453 m_selectionManager->setCurrentItem(current);
454 QCOMPARE(m_selectionManager->m_anchorItem, anchor);
455 QCOMPARE(m_selectionManager->currentItem(), current);
456
457 verifySelectionChange(spySelectionChanged, expectedSelection, initialSelection);
458
459 // Change the model by inserting or removing items.
460 switch (changeType) {
461 case InsertItems:
462 m_selectionManager->itemsInserted(data.at(0).value<KItemRangeList>());
463 break;
464 case RemoveItems:
465 m_selectionManager->itemsRemoved(data.at(0).value<KItemRangeList>());
466 break;
467 case MoveItems:
468 m_selectionManager->itemsMoved(data.at(0).value<KItemRange>(),
469 data.at(1).value<QList<int> >());
470 break;
471 case EndAnchoredSelection:
472 m_selectionManager->endAnchoredSelection();
473 QVERIFY(!m_selectionManager->isAnchoredSelectionActive());
474 break;
475 case SetSelected:
476 m_selectionManager->setSelected(data.at(0).value<int>(), // index
477 data.at(1).value<int>(), // count
478 data.at(2).value<KItemListSelectionManager::SelectionMode>());
479 break;
480 case NoChange:
481 break;
482 }
483
484 verifySelectionChange(spySelectionChanged, finalSelection, expectedSelection);
485
486 // Finally, clear the selection
487 m_selectionManager->clearSelection();
488
489 verifySelectionChange(spySelectionChanged, QSet<int>(), finalSelection);
490 }
491
492 void KItemListSelectionManagerTest::testDeleteCurrentItem_data()
493 {
494 QTest::addColumn<int>("oldCurrentItemIndex");
495 QTest::addColumn<int>("removeIndex");
496 QTest::addColumn<int>("removeCount");
497 QTest::addColumn<int>("newCurrentItemIndex");
498
499 QTest::newRow("Remove before") << 50 << 0 << 10 << 40;
500 QTest::newRow("Remove after") << 50 << 51 << 10 << 50;
501 QTest::newRow("Remove exactly current item") << 50 << 50 << 1 << 50;
502 QTest::newRow("Remove around current item") << 50 << 45 << 10 << 50;
503 QTest::newRow("Remove all except one item") << 50 << 1 << 99 << 0;
504 }
505
506 void KItemListSelectionManagerTest::testDeleteCurrentItem()
507 {
508 QFETCH(int, oldCurrentItemIndex);
509 QFETCH(int, removeIndex);
510 QFETCH(int, removeCount);
511 QFETCH(int, newCurrentItemIndex);
512
513 m_selectionManager->setCurrentItem(oldCurrentItemIndex);
514
515 const int newCount = m_model->count() - removeCount;
516 m_model->setCount(newCount);
517 m_selectionManager->itemsRemoved(KItemRangeList() << KItemRange(removeIndex, removeCount));
518
519 QCOMPARE(m_selectionManager->currentItem(), newCurrentItemIndex);
520 }
521
522 void KItemListSelectionManagerTest::verifySelectionChange(QSignalSpy& spy,
523 const QSet<int>& currentSelection,
524 const QSet<int>& previousSelection) const
525 {
526 QCOMPARE(m_selectionManager->selectedItems(), currentSelection);
527 QCOMPARE(m_selectionManager->hasSelection(), !currentSelection.isEmpty());
528 for (int index = 0; index < m_selectionManager->model()->count(); ++index) {
529 if (currentSelection.contains(index)) {
530 QVERIFY(m_selectionManager->isSelected(index));
531 }
532 else {
533 QVERIFY(!m_selectionManager->isSelected(index));
534 }
535 }
536
537 if (currentSelection == previousSelection) {
538 QCOMPARE(spy.count(), 0);
539 }
540 else {
541 QCOMPARE(spy.count(), 1);
542 QList<QVariant> arguments = spy.takeFirst();
543 QCOMPARE(qvariant_cast<QSet<int> >(arguments.at(0)), currentSelection);
544 QCOMPARE(qvariant_cast<QSet<int> >(arguments.at(1)), previousSelection);
545 }
546 }
547
548 QTEST_KDEMAIN(KItemListSelectionManagerTest, NoGUI)
549
550 #include "kitemlistselectionmanagertest.moc"