1 /***************************************************************************
2 * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
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. *
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. *
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 ***************************************************************************/
20 #include "kitemviews/kitemset.h"
24 Q_DECLARE_METATYPE(KItemRangeList
)
27 * Converts a KItemRangeList to a KItemSet.
29 KItemSet
KItemRangeList2KItemSet(const KItemRangeList
& itemRanges
)
32 foreach (const KItemRange
& range
, itemRanges
) {
33 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
41 * Converts a KItemRangeList to a QSet<int>.
43 QSet
<int> KItemRangeList2QSet(const KItemRangeList
& itemRanges
)
46 foreach (const KItemRange
& range
, itemRanges
) {
47 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
55 * Converts a KItemRangeList to a QVector<int>.
57 QVector
<int> KItemRangeList2QVector(const KItemRangeList
& itemRanges
)
60 foreach (const KItemRange
& range
, itemRanges
) {
61 for (int i
= range
.index
; i
< range
.index
+ range
.count
; ++i
) {
69 * Converts a KItemSet to a QSet<int>.
71 static QSet
<int> KItemSet2QSet(const KItemSet
& itemSet
)
74 for (int i
: itemSet
) {
78 // Check that the conversion was successful.
79 Q_ASSERT(itemSet
.count() == result
.count());
81 for (int i
: itemSet
) {
82 Q_ASSERT(result
.contains(i
));
85 foreach (int i
, result
) {
86 Q_ASSERT(itemSet
.contains(i
));
94 * The main test class.
96 class KItemSetTest
: public QObject
103 void testConstruction_data();
104 void testConstruction();
105 void testIterators_data();
106 void testIterators();
107 void testFind_data();
109 void testChangingOneItem_data();
110 void testChangingOneItem();
111 void testAddSets_data();
114 void testSubtractSets_data();
115 void testSubtractSets();
117 void testSymmetricDifference_data();
118 void testSymmetricDifference();
121 QHash
<const char*, KItemRangeList
> m_testCases
;
124 void KItemSetTest::initTestCase()
126 m_testCases
.insert("empty", KItemRangeList());
127 m_testCases
.insert("[0]", KItemRangeList() << KItemRange(0, 1));
128 m_testCases
.insert("[1]", KItemRangeList() << KItemRange(1, 1));
129 m_testCases
.insert("[1, 2]", KItemRangeList() << KItemRange(1, 2));
130 m_testCases
.insert("[1, 2] [5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(5, 1));
131 m_testCases
.insert("[1] [4, 5]", KItemRangeList() << KItemRange(1, 1) << KItemRange(4, 2));
132 m_testCases
.insert("[1, 2] [4, 5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2));
133 m_testCases
.insert("[1, 5]", KItemRangeList() << KItemRange(1, 5));
134 m_testCases
.insert("[1, 2] [4, 5] [7] [9, 10] [13] [20, 25] [30]",
135 KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2) << KItemRange(7, 1) << KItemRange(9, 2) << KItemRange(20, 6) << KItemRange(30, 1));
136 m_testCases
.insert("[-10, -1]", KItemRangeList() << KItemRange(-10, 10));
137 m_testCases
.insert("[-10, 0]", KItemRangeList() << KItemRange(-10, 11));
138 m_testCases
.insert("[-10, 1]", KItemRangeList() << KItemRange(-10, 12));
139 m_testCases
.insert("[0, 9]", KItemRangeList() << KItemRange(0, 10));
140 m_testCases
.insert("[0, 19]", KItemRangeList() << KItemRange(0, 10));
143 void KItemSetTest::testConstruction_data()
145 QTest::addColumn
<KItemRangeList
>("itemRanges");
147 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
148 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
151 QTest::newRow(it
.key()) << it
.value();
156 void KItemSetTest::testConstruction()
158 QFETCH(KItemRangeList
, itemRanges
);
160 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
161 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
163 QVERIFY(itemSet
.isValid());
164 QVERIFY(itemSet
.count() == itemsQSet
.count());
165 QCOMPARE(KItemSet2QSet(itemSet
), itemsQSet
);
167 // Test copy constructor.
168 KItemSet
copy(itemSet
);
169 QCOMPARE(itemSet
, copy
);
171 QVERIFY(itemSet
!= copy
|| itemSet
.isEmpty());
175 QVERIFY(itemSet
.isEmpty());
176 QCOMPARE(itemSet
.count(), 0);
179 void KItemSetTest::testIterators_data()
181 QTest::addColumn
<KItemRangeList
>("itemRanges");
183 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
184 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
187 QTest::newRow(it
.key()) << it
.value();
193 * Verify that the iterators work exactly like their counterparts for the
194 * equivalent QVector<int>.
196 void KItemSetTest::testIterators()
198 QFETCH(KItemRangeList
, itemRanges
);
200 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
201 QVector
<int> itemsQVector
= KItemRangeList2QVector(itemRanges
);
203 QVERIFY(itemSet
.isValid());
204 QVERIFY(itemSet
.count() == itemsQVector
.count());
206 if (itemSet
.isEmpty()) {
207 QVERIFY(itemSet
.isEmpty());
208 QVERIFY(itemSet
.begin() == itemSet
.end());
209 QVERIFY(itemSet
.constBegin() == itemSet
.constEnd());
211 QVERIFY(!itemSet
.isEmpty());
212 QVERIFY(itemSet
.begin() != itemSet
.end());
213 QVERIFY(itemSet
.constBegin() != itemSet
.constEnd());
215 const int min
= itemsQVector
.first();
216 const int max
= itemsQVector
.last();
218 QCOMPARE(*itemSet
.begin(), min
);
219 QCOMPARE(*itemSet
.constBegin(), min
);
220 QCOMPARE(itemSet
.first(), min
);
222 QCOMPARE(*(--itemSet
.end()), max
);
223 QCOMPARE(*(--itemSet
.constEnd()), max
);
224 QCOMPARE(itemSet
.last(), max
);
227 // Test iterating using the different iterators.
228 QVector
<int> testQVector
;
229 for (KItemSet::iterator it
= itemSet
.begin(), end
= itemSet
.end(); it
!= end
; ++it
) {
230 testQVector
.append(*it
);
232 QCOMPARE(testQVector
, itemsQVector
);
235 for (KItemSet::const_iterator it
= itemSet
.constBegin(), end
= itemSet
.constEnd(); it
!= end
; ++it
) {
236 testQVector
.append(*it
);
238 QCOMPARE(testQVector
, itemsQVector
);
241 for (int i
: itemSet
) {
242 testQVector
.append(i
);
244 QCOMPARE(testQVector
, itemsQVector
);
246 // Verify that both variants of the (const)iterator's operator++ and
247 // operator-- functions behave exactly like their QVector equivalents.
248 KItemSet::iterator it1
= itemSet
.begin();
249 KItemSet::iterator it2
= itemSet
.begin();
250 KItemSet::const_iterator constIt1
= itemSet
.constBegin();
251 KItemSet::const_iterator constIt2
= itemSet
.constBegin();
252 QVector
<int>::iterator vectorIt1
= itemsQVector
.begin();
253 QVector
<int>::iterator vectorIt2
= itemsQVector
.begin();
254 QVector
<int>::const_iterator vectorConstIt1
= itemsQVector
.constBegin();
255 QVector
<int>::const_iterator vectorConstIt2
= itemsQVector
.constBegin();
257 while (it1
!= itemSet
.end()) {
258 if (it1
!= --itemSet
.end()) {
259 QCOMPARE(*(++it1
), *(++vectorIt1
));
260 QCOMPARE(*(++constIt1
), *(++vectorConstIt1
));
262 QCOMPARE(++it1
, itemSet
.end());
263 QCOMPARE(++vectorIt1
, itemsQVector
.end());
264 QCOMPARE(++constIt1
, itemSet
.constEnd());
265 QCOMPARE(++vectorConstIt1
, itemsQVector
.constEnd());
268 QCOMPARE(*(it2
++), *(vectorIt2
++));
269 QCOMPARE(*(constIt2
++), *(vectorConstIt2
++));
272 QCOMPARE(constIt1
, constIt2
);
273 QCOMPARE(KItemSet::const_iterator(it1
), constIt1
);
276 QCOMPARE(it1
, itemSet
.end());
277 QCOMPARE(it2
, itemSet
.end());
278 QCOMPARE(constIt1
, itemSet
.constEnd());
279 QCOMPARE(constIt2
, itemSet
.constEnd());
280 QCOMPARE(vectorIt1
, itemsQVector
.end());
281 QCOMPARE(vectorIt2
, itemsQVector
.end());
282 QCOMPARE(vectorConstIt1
, itemsQVector
.constEnd());
283 QCOMPARE(vectorConstIt2
, itemsQVector
.constEnd());
285 while (it1
!= itemSet
.begin()) {
286 QCOMPARE(*(--it1
), *(--vectorIt1
));
287 QCOMPARE(*(--constIt1
), *(--vectorConstIt1
));
289 if (it2
!= itemSet
.end()) {
290 QCOMPARE(*(it2
--), *(vectorIt2
--));
291 QCOMPARE(*(constIt2
--), *(vectorConstIt2
--));
293 QCOMPARE(it2
--, itemSet
.end());
294 QCOMPARE(vectorIt2
--, itemsQVector
.end());
295 QCOMPARE(constIt2
--, itemSet
.constEnd());
296 QCOMPARE(vectorConstIt2
--, itemsQVector
.constEnd());
300 QCOMPARE(constIt1
, constIt2
);
301 QCOMPARE(KItemSet::const_iterator(it1
), constIt1
);
304 QCOMPARE(it1
, itemSet
.begin());
305 QCOMPARE(it2
, itemSet
.begin());
306 QCOMPARE(constIt1
, itemSet
.constBegin());
307 QCOMPARE(constIt2
, itemSet
.constBegin());
308 QCOMPARE(vectorIt1
, itemsQVector
.begin());
309 QCOMPARE(vectorIt2
, itemsQVector
.begin());
310 QCOMPARE(vectorConstIt1
, itemsQVector
.constBegin());
311 QCOMPARE(vectorConstIt2
, itemsQVector
.constBegin());
314 void KItemSetTest::testFind_data()
316 QTest::addColumn
<KItemRangeList
>("itemRanges");
318 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
319 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
322 QTest::newRow(it
.key()) << it
.value();
328 * Test all functions that find items:
329 * contains(int), find(int), constFind(int)
331 void KItemSetTest::testFind()
333 QFETCH(KItemRangeList
, itemRanges
);
335 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
336 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
338 QVERIFY(itemSet
.isValid());
339 QVERIFY(itemSet
.count() == itemsQSet
.count());
341 // Find the minimum and maximum items.
345 if (itemSet
.isEmpty()) {
346 // Use some arbitrary values for the upcoming tests.
350 min
= *itemSet
.begin();
351 max
= *(--itemSet
.end());
354 // Test contains(int), find(int), and constFind(int)
355 // for items between min - 2 and max + 2.
356 for (int i
= min
- 2; i
<= max
+ 2; ++i
) {
357 const KItemSet::iterator it
= itemSet
.find(i
);
358 const KItemSet::const_iterator constIt
= itemSet
.constFind(i
);
359 QCOMPARE(KItemSet::const_iterator(it
), constIt
);
361 if (itemsQSet
.contains(i
)) {
362 QVERIFY(itemSet
.contains(i
));
364 QCOMPARE(*constIt
, i
);
366 QVERIFY(!itemSet
.contains(i
));
367 QCOMPARE(it
, itemSet
.end());
368 QCOMPARE(constIt
, itemSet
.constEnd());
373 void KItemSetTest::testChangingOneItem_data()
375 QTest::addColumn
<KItemRangeList
>("itemRanges");
377 QHash
<const char*, KItemRangeList
>::const_iterator it
= m_testCases
.constBegin();
378 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
381 QTest::newRow(it
.key()) << it
.value();
387 * Test all functions that change a single item:
388 * insert(int), remove(int), erase(KItemSet::iterator)
390 void KItemSetTest::testChangingOneItem()
392 QFETCH(KItemRangeList
, itemRanges
);
394 KItemSet itemSet
= KItemRangeList2KItemSet(itemRanges
);
395 QSet
<int> itemsQSet
= KItemRangeList2QSet(itemRanges
);
397 QVERIFY(itemSet
.isValid());
398 QVERIFY(itemSet
.count() == itemsQSet
.count());
400 // Find the minimum and maximum items.
404 if (itemSet
.isEmpty()) {
405 // Use some arbitrary values for the upcoming tests.
409 min
= *itemSet
.begin();
410 max
= *(--itemSet
.end());
413 // Test insert(int), remove(int), and erase(KItemSet::iterator)
414 // for items between min - 2 and max + 2.
415 for (int i
= min
- 2; i
<= max
+ 2; ++i
) {
419 KItemSet
tmp(itemSet
);
420 const KItemSet::iterator insertedIt
= tmp
.insert(i
);
421 QCOMPARE(*insertedIt
, i
);
423 QVERIFY(tmp
.isValid());
424 QVERIFY(tmp
.contains(i
));
426 QSet
<int> expectedQSet
= itemsQSet
;
427 expectedQSet
.insert(i
);
428 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
430 if (!itemSet
.contains(i
)) {
431 QVERIFY(itemSet
!= tmp
);
432 QCOMPARE(tmp
.count(), itemSet
.count() + 1);
434 QCOMPARE(itemSet
, tmp
);
437 QCOMPARE(i
, *tmp
.find(i
));
438 QCOMPARE(i
, *tmp
.constFind(i
));
440 // Erase the new item and check that we get the old KItemSet back.
441 tmp
.erase(tmp
.find(i
));
442 QVERIFY(tmp
.isValid());
443 QVERIFY(!tmp
.contains(i
));
445 if (!itemSet
.contains(i
)) {
446 QCOMPARE(itemSet
, tmp
);
449 expectedQSet
.remove(i
);
450 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
455 KItemSet
tmp(itemSet
);
456 const bool removed
= tmp
.remove(i
);
458 QCOMPARE(removed
, itemSet
.contains(i
));
460 QVERIFY(tmp
.isValid());
461 QVERIFY(!tmp
.contains(i
));
463 QSet
<int> expectedQSet
= itemsQSet
;
464 expectedQSet
.remove(i
);
465 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
467 if (itemSet
.contains(i
)) {
468 QVERIFY(itemSet
!= tmp
);
469 QCOMPARE(tmp
.count(), itemSet
.count() - 1);
471 QCOMPARE(itemSet
, tmp
);
474 QCOMPARE(tmp
.end(), tmp
.find(i
));
475 QCOMPARE(tmp
.constEnd(), tmp
.constFind(i
));
478 // Test erase(KItemSet::iterator).
479 if (itemSet
.contains(i
)) {
480 KItemSet
tmp(itemSet
);
481 KItemSet::iterator it
= tmp
.find(i
);
484 QVERIFY(tmp
.isValid());
485 QVERIFY(!tmp
.contains(i
));
487 QSet
<int> expectedQSet
= itemsQSet
;
488 expectedQSet
.remove(i
);
489 QCOMPARE(KItemSet2QSet(tmp
), expectedQSet
);
491 if (itemSet
.contains(i
)) {
492 QVERIFY(itemSet
!= tmp
);
493 QCOMPARE(tmp
.count(), itemSet
.count() - 1);
495 QCOMPARE(itemSet
, tmp
);
498 QCOMPARE(tmp
.end(), tmp
.find(i
));
499 QCOMPARE(tmp
.constEnd(), tmp
.constFind(i
));
501 // Check the returned value, now contained in 'it'.
503 QCOMPARE(it
, tmp
.end());
505 // it now points to the next item.
506 QVERIFY(tmp
.contains(*it
));
507 for (int j
= i
; j
< *it
; ++j
) {
508 QVERIFY(!tmp
.contains(j
));
516 QVERIFY(itemSet
.isEmpty());
517 QCOMPARE(itemSet
.count(), 0);
520 void KItemSetTest::testAddSets_data()
522 QTest::addColumn
<KItemRangeList
>("itemRanges1");
523 QTest::addColumn
<KItemRangeList
>("itemRanges2");
525 QHash
<const char*, KItemRangeList
>::const_iterator it1
= m_testCases
.constBegin();
526 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
529 QHash
<const char*, KItemRangeList
>::const_iterator it2
= m_testCases
.constBegin();
532 QByteArray name
= it1
.key() + QByteArray(" + ") + it2
.key();
533 QTest::newRow(name
) << it1
.value() << it2
.value();
541 void KItemSetTest::testAddSets()
543 QFETCH(KItemRangeList
, itemRanges1
);
544 QFETCH(KItemRangeList
, itemRanges2
);
546 KItemSet itemSet1
= KItemRangeList2KItemSet(itemRanges1
);
547 QSet
<int> itemsQSet1
= KItemRangeList2QSet(itemRanges1
);
549 KItemSet itemSet2
= KItemRangeList2KItemSet(itemRanges2
);
550 QSet
<int> itemsQSet2
= KItemRangeList2QSet(itemRanges2
);
552 KItemSet sum
= itemSet1
+ itemSet2
;
553 QSet
<int> sumQSet
= itemsQSet1
+ itemsQSet2
;
555 QCOMPARE(sum
.count(), sumQSet
.count());
556 QCOMPARE(KItemSet2QSet(sum
), sumQSet
);
559 void KItemSetTest::testSymmetricDifference_data()
561 QTest::addColumn
<KItemRangeList
>("itemRanges1");
562 QTest::addColumn
<KItemRangeList
>("itemRanges2");
564 QHash
<const char*, KItemRangeList
>::const_iterator it1
= m_testCases
.constBegin();
565 const QHash
<const char*, KItemRangeList
>::const_iterator end
= m_testCases
.constEnd();
568 QHash
<const char*, KItemRangeList
>::const_iterator it2
= m_testCases
.constBegin();
571 QByteArray name
= it1
.key() + QByteArray(" ^ ") + it2
.key();
572 QTest::newRow(name
) << it1
.value() << it2
.value();
580 void KItemSetTest::testSymmetricDifference()
582 QFETCH(KItemRangeList
, itemRanges1
);
583 QFETCH(KItemRangeList
, itemRanges2
);
585 KItemSet itemSet1
= KItemRangeList2KItemSet(itemRanges1
);
586 QSet
<int> itemsQSet1
= KItemRangeList2QSet(itemRanges1
);
588 KItemSet itemSet2
= KItemRangeList2KItemSet(itemRanges2
);
589 QSet
<int> itemsQSet2
= KItemRangeList2QSet(itemRanges2
);
591 KItemSet symmetricDifference
= itemSet1
^ itemSet2
;
592 QSet
<int> symmetricDifferenceQSet
= (itemsQSet1
- itemsQSet2
) + (itemsQSet2
- itemsQSet1
);
594 QCOMPARE(symmetricDifference
.count(), symmetricDifferenceQSet
.count());
595 QCOMPARE(KItemSet2QSet(symmetricDifference
), symmetricDifferenceQSet
);
597 // Check commutativity.
598 QCOMPARE(itemSet2
^ itemSet1
, symmetricDifference
);
601 // itemSet1 ^ symmetricDifference == itemSet2,
602 // itemSet2 ^ symmetricDifference == itemSet1.
603 QCOMPARE(itemSet1
^ symmetricDifference
, itemSet2
);
604 QCOMPARE(itemSet2
^ symmetricDifference
, itemSet1
);
608 QTEST_GUILESS_MAIN(KItemSetTest
)
610 #include "kitemsettest.moc"