2 * SPDX-FileCopyrightText: 2013 Frank Reininghaus <frank78ac@googlemail.com>
4 * SPDX-License-Identifier: GPL-2.0-or-later
7 #include "kitemviews/kitemset.h"
11 Q_DECLARE_METATYPE(KItemRangeList
)
14 * Converts a KItemRangeList to a KItemSet.
16 KItemSet
KItemRangeList2KItemSet(const KItemRangeList
& itemRanges
)
19 for (const KItemRange
& range
: itemRanges
) {
20 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
28 * Converts a KItemRangeList to a QSet<int>.
30 QSet
<int> KItemRangeList2QSet(const KItemRangeList
& itemRanges
)
33 for (const KItemRange
& range
: itemRanges
) {
34 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
42 * Converts a KItemRangeList to a QVector<int>.
44 QVector
<int> KItemRangeList2QVector(const KItemRangeList
& itemRanges
)
47 for (const KItemRange
& range
: itemRanges
) {
48 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
56 * Converts a KItemSet to a QSet<int>.
58 static QSet
<int> KItemSet2QSet(const KItemSet
& itemSet
)
61 for (int i
: itemSet
) {
65 // Check that the conversion was successful.
66 Q_ASSERT(itemSet
.count() == result
.count());
68 for (int i
: qAsConst(itemSet
)) {
69 Q_ASSERT(result
.contains(i
));
72 for (int i
: qAsConst(result
)) {
73 Q_ASSERT(itemSet
.contains(i
));
81 * The main test class.
83 class KItemSetTest
: public QObject
90 void testConstruction_data();
91 void testConstruction();
92 void testIterators_data();
96 void testChangingOneItem_data();
97 void testChangingOneItem();
98 void testAddSets_data();
101 void testSubtractSets_data();
102 void testSubtractSets();
104 void testSymmetricDifference_data();
105 void testSymmetricDifference();
108 QHash
<const char*, KItemRangeList
> m_testCases
;
111 void KItemSetTest::initTestCase()
113 m_testCases
.insert("empty", KItemRangeList());
114 m_testCases
.insert("[0]", KItemRangeList() << KItemRange(0, 1));
115 m_testCases
.insert("[1]", KItemRangeList() << KItemRange(1, 1));
116 m_testCases
.insert("[1, 2]", KItemRangeList() << KItemRange(1, 2));
117 m_testCases
.insert("[1, 2] [5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(5, 1));
118 m_testCases
.insert("[1] [4, 5]", KItemRangeList() << KItemRange(1, 1) << KItemRange(4, 2));
119 m_testCases
.insert("[1, 2] [4, 5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2));
120 m_testCases
.insert("[1, 5]", KItemRangeList() << KItemRange(1, 5));
121 m_testCases
.insert("[1, 2] [4, 5] [7] [9, 10] [13] [20, 25] [30]",
122 KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2) << KItemRange(7, 1) << KItemRange(9, 2) << KItemRange(20, 6) << KItemRange(30, 1));
123 m_testCases
.insert("[-10, -1]", KItemRangeList() << KItemRange(-10, 10));
124 m_testCases
.insert("[-10, 0]", KItemRangeList() << KItemRange(-10, 11));
125 m_testCases
.insert("[-10, 1]", KItemRangeList() << KItemRange(-10, 12));
126 m_testCases
.insert("[0, 9]", KItemRangeList() << KItemRange(0, 10));
127 m_testCases
.insert("[0, 19]", KItemRangeList() << KItemRange(0, 10));
130 void KItemSetTest::testConstruction_data()
132 QTest::addColumn
<KItemRangeList
>("itemRanges");
134 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
135 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
138 QTest::newRow(it
.key()) << it
.value();
143 void KItemSetTest::testConstruction()
145 QFETCH(KItemRangeList
, itemRanges
);
147 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
148 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
150 QVERIFY(itemSet
.isValid());
151 QVERIFY(itemSet
.count() == itemsQSet
.count());
152 QCOMPARE(KItemSet2QSet(itemSet
), itemsQSet
);
154 // Test copy constructor.
155 KItemSet
copy(itemSet
);
156 QCOMPARE(itemSet
, copy
);
158 QVERIFY(itemSet
!= copy
|| itemSet
.isEmpty());
162 QVERIFY(itemSet
.isEmpty());
163 QCOMPARE(itemSet
.count(), 0);
166 void KItemSetTest::testIterators_data()
168 QTest::addColumn
<KItemRangeList
>("itemRanges");
170 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
171 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
174 QTest::newRow(it
.key()) << it
.value();
180 * Verify that the iterators work exactly like their counterparts for the
181 * equivalent QVector<int>.
183 void KItemSetTest::testIterators()
185 QFETCH(KItemRangeList
, itemRanges
);
187 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
188 QVector
<int> itemsQVector
= KItemRangeList2QVector(itemRanges
);
190 QVERIFY(itemSet
.isValid());
191 QVERIFY(itemSet
.count() == itemsQVector
.count());
193 if (itemSet
.isEmpty()) {
194 QVERIFY(itemSet
.isEmpty());
195 QVERIFY(itemSet
.begin() == itemSet
.end());
196 QVERIFY(itemSet
.constBegin() == itemSet
.constEnd());
198 QVERIFY(!itemSet
.isEmpty());
199 QVERIFY(itemSet
.begin() != itemSet
.end());
200 QVERIFY(itemSet
.constBegin() != itemSet
.constEnd());
202 const int min
= itemsQVector
.first();
203 const int max
= itemsQVector
.last();
205 QCOMPARE(*itemSet
.begin(), min
);
206 QCOMPARE(*itemSet
.constBegin(), min
);
207 QCOMPARE(itemSet
.first(), min
);
209 QCOMPARE(*(--itemSet
.end()), max
);
210 QCOMPARE(*(--itemSet
.constEnd()), max
);
211 QCOMPARE(itemSet
.last(), max
);
214 // Test iterating using the different iterators.
215 QVector
<int> testQVector
;
216 for (KItemSet::iterator it
= itemSet
.begin(), end
= itemSet
.end(); it
!= end
; ++it
) {
217 testQVector
.append(*it
);
219 QCOMPARE(testQVector
, itemsQVector
);
222 for (KItemSet::const_iterator it
= itemSet
.constBegin(), end
= itemSet
.constEnd(); it
!= end
; ++it
) {
223 testQVector
.append(*it
);
225 QCOMPARE(testQVector
, itemsQVector
);
228 for (int i
: itemSet
) {
229 testQVector
.append(i
);
231 QCOMPARE(testQVector
, itemsQVector
);
233 // Verify that both variants of the (const)iterator's operator++ and
234 // operator-- functions behave exactly like their QVector equivalents.
235 KItemSet::iterator it1
= itemSet
.begin();
236 KItemSet::iterator it2
= itemSet
.begin();
237 KItemSet::const_iterator constIt1
= itemSet
.constBegin();
238 KItemSet::const_iterator constIt2
= itemSet
.constBegin();
239 QVector
<int>::iterator vectorIt1
= itemsQVector
.begin();
240 QVector
<int>::iterator vectorIt2
= itemsQVector
.begin();
241 QVector
<int>::const_iterator vectorConstIt1
= itemsQVector
.constBegin();
242 QVector
<int>::const_iterator vectorConstIt2
= itemsQVector
.constBegin();
244 while (it1
!= itemSet
.end()) {
245 if (it1
!= --itemSet
.end()) {
246 QCOMPARE(*(++it1
), *(++vectorIt1
));
247 QCOMPARE(*(++constIt1
), *(++vectorConstIt1
));
249 QCOMPARE(++it1
, itemSet
.end());
250 QCOMPARE(++vectorIt1
, itemsQVector
.end());
251 QCOMPARE(++constIt1
, itemSet
.constEnd());
252 QCOMPARE(++vectorConstIt1
, itemsQVector
.constEnd());
255 QCOMPARE(*(it2
++), *(vectorIt2
++));
256 QCOMPARE(*(constIt2
++), *(vectorConstIt2
++));
259 QCOMPARE(constIt1
, constIt2
);
260 QCOMPARE(KItemSet::const_iterator(it1
), constIt1
);
263 QCOMPARE(it1
, itemSet
.end());
264 QCOMPARE(it2
, itemSet
.end());
265 QCOMPARE(constIt1
, itemSet
.constEnd());
266 QCOMPARE(constIt2
, itemSet
.constEnd());
267 QCOMPARE(vectorIt1
, itemsQVector
.end());
268 QCOMPARE(vectorIt2
, itemsQVector
.end());
269 QCOMPARE(vectorConstIt1
, itemsQVector
.constEnd());
270 QCOMPARE(vectorConstIt2
, itemsQVector
.constEnd());
272 while (it1
!= itemSet
.begin()) {
273 QCOMPARE(*(--it1
), *(--vectorIt1
));
274 QCOMPARE(*(--constIt1
), *(--vectorConstIt1
));
276 if (it2
!= itemSet
.end()) {
277 QCOMPARE(*(it2
--), *(vectorIt2
--));
278 QCOMPARE(*(constIt2
--), *(vectorConstIt2
--));
280 QCOMPARE(it2
--, itemSet
.end());
281 QCOMPARE(vectorIt2
--, itemsQVector
.end());
282 QCOMPARE(constIt2
--, itemSet
.constEnd());
283 QCOMPARE(vectorConstIt2
--, itemsQVector
.constEnd());
287 QCOMPARE(constIt1
, constIt2
);
288 QCOMPARE(KItemSet::const_iterator(it1
), constIt1
);
291 QCOMPARE(it1
, itemSet
.begin());
292 QCOMPARE(it2
, itemSet
.begin());
293 QCOMPARE(constIt1
, itemSet
.constBegin());
294 QCOMPARE(constIt2
, itemSet
.constBegin());
295 QCOMPARE(vectorIt1
, itemsQVector
.begin());
296 QCOMPARE(vectorIt2
, itemsQVector
.begin());
297 QCOMPARE(vectorConstIt1
, itemsQVector
.constBegin());
298 QCOMPARE(vectorConstIt2
, itemsQVector
.constBegin());
301 void KItemSetTest::testFind_data()
303 QTest::addColumn
<KItemRangeList
>("itemRanges");
305 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
306 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
309 QTest::newRow(it
.key()) << it
.value();
315 * Test all functions that find items:
316 * contains(int), find(int), constFind(int)
318 void KItemSetTest::testFind()
320 QFETCH(KItemRangeList
, itemRanges
);
322 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
323 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
325 QVERIFY(itemSet
.isValid());
326 QVERIFY(itemSet
.count() == itemsQSet
.count());
328 // Find the minimum and maximum items.
332 if (itemSet
.isEmpty()) {
333 // Use some arbitrary values for the upcoming tests.
337 min
= *itemSet
.begin();
338 max
= *(--itemSet
.end());
341 // Test contains(int), find(int), and constFind(int)
342 // for items between min - 2 and max + 2.
343 for (int i
= min
- 2; i
<= max
+ 2; ++i
) {
344 const KItemSet::iterator it
= itemSet
.find(i
);
345 const KItemSet::const_iterator constIt
= itemSet
.constFind(i
);
346 QCOMPARE(KItemSet::const_iterator(it
), constIt
);
348 if (itemsQSet
.contains(i
)) {
349 QVERIFY(itemSet
.contains(i
));
351 QCOMPARE(*constIt
, i
);
353 QVERIFY(!itemSet
.contains(i
));
354 QCOMPARE(it
, itemSet
.end());
355 QCOMPARE(constIt
, itemSet
.constEnd());
360 void KItemSetTest::testChangingOneItem_data()
362 QTest::addColumn
<KItemRangeList
>("itemRanges");
364 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
365 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
368 QTest::newRow(it
.key()) << it
.value();
374 * Test all functions that change a single item:
375 * insert(int), remove(int), erase(KItemSet::iterator)
377 void KItemSetTest::testChangingOneItem()
379 QFETCH(KItemRangeList
, itemRanges
);
381 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
382 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
384 QVERIFY(itemSet
.isValid());
385 QVERIFY(itemSet
.count() == itemsQSet
.count());
387 // Find the minimum and maximum items.
391 if (itemSet
.isEmpty()) {
392 // Use some arbitrary values for the upcoming tests.
396 min
= *itemSet
.begin();
397 max
= *(--itemSet
.end());
400 // Test insert(int), remove(int), and erase(KItemSet::iterator)
401 // for items between min - 2 and max + 2.
402 for (int i
= min
- 2; i
<= max
+ 2; ++i
) {
406 KItemSet
tmp(itemSet
);
407 const KItemSet::iterator insertedIt
= tmp
.insert(i
);
408 QCOMPARE(*insertedIt
, i
);
410 QVERIFY(tmp
.isValid());
411 QVERIFY(tmp
.contains(i
));
413 QSet
<int> expectedQSet
= itemsQSet
;
414 expectedQSet
.insert(i
);
415 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
417 if (!itemSet
.contains(i
)) {
418 QVERIFY(itemSet
!= tmp
);
419 QCOMPARE(tmp
.count(), itemSet
.count() + 1);
421 QCOMPARE(itemSet
, tmp
);
424 QCOMPARE(i
, *tmp
.find(i
));
425 QCOMPARE(i
, *tmp
.constFind(i
));
427 // Erase the new item and check that we get the old KItemSet back.
428 tmp
.erase(tmp
.find(i
));
429 QVERIFY(tmp
.isValid());
430 QVERIFY(!tmp
.contains(i
));
432 if (!itemSet
.contains(i
)) {
433 QCOMPARE(itemSet
, tmp
);
436 expectedQSet
.remove(i
);
437 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
442 KItemSet
tmp(itemSet
);
443 const bool removed
= tmp
.remove(i
);
445 QCOMPARE(removed
, itemSet
.contains(i
));
447 QVERIFY(tmp
.isValid());
448 QVERIFY(!tmp
.contains(i
));
450 QSet
<int> expectedQSet
= itemsQSet
;
451 expectedQSet
.remove(i
);
452 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
454 if (itemSet
.contains(i
)) {
455 QVERIFY(itemSet
!= tmp
);
456 QCOMPARE(tmp
.count(), itemSet
.count() - 1);
458 QCOMPARE(itemSet
, tmp
);
461 QCOMPARE(tmp
.end(), tmp
.find(i
));
462 QCOMPARE(tmp
.constEnd(), tmp
.constFind(i
));
465 // Test erase(KItemSet::iterator).
466 if (itemSet
.contains(i
)) {
467 KItemSet
tmp(itemSet
);
468 KItemSet::iterator it
= tmp
.find(i
);
471 QVERIFY(tmp
.isValid());
472 QVERIFY(!tmp
.contains(i
));
474 QSet
<int> expectedQSet
= itemsQSet
;
475 expectedQSet
.remove(i
);
476 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
478 if (itemSet
.contains(i
)) {
479 QVERIFY(itemSet
!= tmp
);
480 QCOMPARE(tmp
.count(), itemSet
.count() - 1);
482 QCOMPARE(itemSet
, tmp
);
485 QCOMPARE(tmp
.end(), tmp
.find(i
));
486 QCOMPARE(tmp
.constEnd(), tmp
.constFind(i
));
488 // Check the returned value, now contained in 'it'.
490 QCOMPARE(it
, tmp
.end());
492 // it now points to the next item.
493 QVERIFY(tmp
.contains(*it
));
494 for (int j
= i
; j
< *it
; ++j
) {
495 QVERIFY(!tmp
.contains(j
));
503 QVERIFY(itemSet
.isEmpty());
504 QCOMPARE(itemSet
.count(), 0);
507 void KItemSetTest::testAddSets_data()
509 QTest::addColumn
<KItemRangeList
>("itemRanges1");
510 QTest::addColumn
<KItemRangeList
>("itemRanges2");
512 QHash
<const char*, KItemRangeList
>::const_iterator it1
= m_testCases
.constBegin();
513 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
516 QHash
<const char*, KItemRangeList
>::const_iterator it2
= m_testCases
.constBegin();
519 QByteArray name
= it1
.key() + QByteArray(" + ") + it2
.key();
520 QTest::newRow(name
) << it1
.value() << it2
.value();
528 void KItemSetTest::testAddSets()
530 QFETCH(KItemRangeList
, itemRanges1
);
531 QFETCH(KItemRangeList
, itemRanges2
);
533 KItemSet itemSet1
= KItemRangeList2KItemSet(itemRanges1
);
534 QSet
<int> itemsQSet1
= KItemRangeList2QSet(itemRanges1
);
536 KItemSet itemSet2
= KItemRangeList2KItemSet(itemRanges2
);
537 QSet
<int> itemsQSet2
= KItemRangeList2QSet(itemRanges2
);
539 KItemSet sum
= itemSet1
+ itemSet2
;
540 QSet
<int> sumQSet
= itemsQSet1
+ itemsQSet2
;
542 QCOMPARE(sum
.count(), sumQSet
.count());
543 QCOMPARE(KItemSet2QSet(sum
), sumQSet
);
546 void KItemSetTest::testSymmetricDifference_data()
548 QTest::addColumn
<KItemRangeList
>("itemRanges1");
549 QTest::addColumn
<KItemRangeList
>("itemRanges2");
551 QHash
<const char*, KItemRangeList
>::const_iterator it1
= m_testCases
.constBegin();
552 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
555 QHash
<const char*, KItemRangeList
>::const_iterator it2
= m_testCases
.constBegin();
558 QByteArray name
= it1
.key() + QByteArray(" ^ ") + it2
.key();
559 QTest::newRow(name
) << it1
.value() << it2
.value();
567 void KItemSetTest::testSymmetricDifference()
569 QFETCH(KItemRangeList
, itemRanges1
);
570 QFETCH(KItemRangeList
, itemRanges2
);
572 KItemSet itemSet1
= KItemRangeList2KItemSet(itemRanges1
);
573 QSet
<int> itemsQSet1
= KItemRangeList2QSet(itemRanges1
);
575 KItemSet itemSet2
= KItemRangeList2KItemSet(itemRanges2
);
576 QSet
<int> itemsQSet2
= KItemRangeList2QSet(itemRanges2
);
578 KItemSet symmetricDifference
= itemSet1
^ itemSet2
;
579 QSet
<int> symmetricDifferenceQSet
= (itemsQSet1
- itemsQSet2
) + (itemsQSet2
- itemsQSet1
);
581 QCOMPARE(symmetricDifference
.count(), symmetricDifferenceQSet
.count());
582 QCOMPARE(KItemSet2QSet(symmetricDifference
), symmetricDifferenceQSet
);
584 // Check commutativity.
585 QCOMPARE(itemSet2
^ itemSet1
, symmetricDifference
);
588 // itemSet1 ^ symmetricDifference == itemSet2,
589 // itemSet2 ^ symmetricDifference == itemSet1.
590 QCOMPARE(itemSet1
^ symmetricDifference
, itemSet2
);
591 QCOMPARE(itemSet2
^ symmetricDifference
, itemSet1
);
595 QTEST_GUILESS_MAIN(KItemSetTest
)
597 #include "kitemsettest.moc"