1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QObject>
30#include <QTest>
31#include <QCache>
32#include <QContiguousCache>
33
34#include <QDebug>
35#include <stdio.h>
36
37class tst_QContiguousCache : public QObject
38{
39 Q_OBJECT
40private slots:
41 void assignment();
42
43 void empty();
44 void swap();
45
46 void append_data();
47 void append();
48
49 void prepend_data();
50 void prepend();
51
52 void complexType();
53
54 void operatorAt();
55
56 void setCapacity();
57
58 void zeroCapacity();
59 void modifyZeroCapacityCache();
60};
61
62QTEST_MAIN(tst_QContiguousCache)
63
64void tst_QContiguousCache::assignment()
65{
66 // compile-only test: QTBUG-45783
67 QContiguousCache<int> cc1, cc2;
68 // copy:
69 cc1 = cc2;
70 // move:
71 cc1 = std::move(cc2);
72}
73
74void tst_QContiguousCache::empty()
75{
76 QContiguousCache<int> c(10);
77 QCOMPARE(c.capacity(), 10);
78 QCOMPARE(c.count(), 0);
79 QVERIFY(c.isEmpty());
80 c.append(value: 1);
81 QCOMPARE(c.count(), 1);
82 QVERIFY(!c.isEmpty());
83 c.clear();
84 QCOMPARE(c.capacity(), 10);
85 QCOMPARE(c.count(), 0);
86 QVERIFY(c.isEmpty());
87 c.prepend(value: 1);
88 QCOMPARE(c.count(), 1);
89 QVERIFY(!c.isEmpty());
90 c.clear();
91 QCOMPARE(c.count(), 0);
92 QVERIFY(c.isEmpty());
93 QCOMPARE(c.capacity(), 10);
94}
95
96void tst_QContiguousCache::swap()
97{
98 QContiguousCache<int> c1(10), c2(100);
99 c1.append(value: 1);
100 c1.swap(other&: c2);
101 QCOMPARE(c1.capacity(), 100);
102 QCOMPARE(c1.count(), 0 );
103 QCOMPARE(c2.capacity(), 10 );
104 QCOMPARE(c2.count(), 1 );
105}
106
107void tst_QContiguousCache::append_data()
108{
109 QTest::addColumn<int>(name: "start");
110 QTest::addColumn<int>(name: "count");
111 QTest::addColumn<int>(name: "cacheSize");
112 QTest::addColumn<bool>(name: "invalidIndexes");
113
114 QTest::newRow(dataTag: "0+30[10]") << 0 << 30 << 10 << false;
115 QTest::newRow(dataTag: "300+30[10]") << 300 << 30 << 10 << false;
116 QTest::newRow(dataTag: "MAX-10+30[10]") << INT_MAX-10 << 30 << 10 << true;
117}
118
119void tst_QContiguousCache::append()
120{
121 QFETCH(int, start);
122 QFETCH(int, count);
123 QFETCH(int, cacheSize);
124 QFETCH(bool, invalidIndexes);
125
126 int i, j;
127 QContiguousCache<int> c(cacheSize);
128
129 i = 1;
130 QCOMPARE(c.available(), cacheSize);
131 if (start == 0)
132 c.append(value: i++);
133 else
134 c.insert(pos: start, value: i++);
135 while (i < count) {
136 c.append(value: i);
137 QCOMPARE(c.available(), qMax(0, cacheSize - i));
138 QCOMPARE(c.first(), qMax(1, i-cacheSize+1));
139 QCOMPARE(c.last(), i);
140 QCOMPARE(c.count(), qMin(i, cacheSize));
141 QCOMPARE(c.isFull(), i >= cacheSize);
142 i++;
143 }
144
145 QCOMPARE(c.areIndexesValid(), !invalidIndexes);
146 if (invalidIndexes)
147 c.normalizeIndexes();
148 QVERIFY(c.areIndexesValid());
149
150 // test taking from end until empty.
151 for (j = 0; j < cacheSize; j++, i--) {
152 QCOMPARE(c.takeLast(), i-1);
153 QCOMPARE(c.count(), cacheSize-j-1);
154 QCOMPARE(c.available(), j+1);
155 QVERIFY(!c.isFull());
156 QCOMPARE(c.isEmpty(), j==cacheSize-1);
157 }
158
159}
160
161void tst_QContiguousCache::prepend_data()
162{
163 QTest::addColumn<int>(name: "start");
164 QTest::addColumn<int>(name: "count");
165 QTest::addColumn<int>(name: "cacheSize");
166 QTest::addColumn<bool>(name: "invalidIndexes");
167
168 QTest::newRow(dataTag: "30-30[10]") << 30 << 30 << 10 << false;
169 QTest::newRow(dataTag: "300-30[10]") << 300 << 30 << 10 << false;
170 QTest::newRow(dataTag: "10-30[10]") << 10 << 30 << 10 << true;
171}
172
173void tst_QContiguousCache::prepend()
174{
175 QFETCH(int, start);
176 QFETCH(int, count);
177 QFETCH(int, cacheSize);
178 QFETCH(bool, invalidIndexes);
179
180 int i, j;
181 QContiguousCache<int> c(cacheSize);
182
183 i = 1;
184 QCOMPARE(c.available(), cacheSize);
185 c.insert(pos: start, value: i++);
186 while(i < count) {
187 c.prepend(value: i);
188 QCOMPARE(c.available(), qMax(0, cacheSize - i));
189 QCOMPARE(c.last(), qMax(1, i-cacheSize+1));
190 QCOMPARE(c.first(), i);
191 QCOMPARE(c.count(), qMin(i, cacheSize));
192 QCOMPARE(c.isFull(), i >= cacheSize);
193 i++;
194 }
195
196 QCOMPARE(c.areIndexesValid(), !invalidIndexes);
197 if (invalidIndexes)
198 c.normalizeIndexes();
199 QVERIFY(c.areIndexesValid());
200
201 // test taking from start until empty.
202 for (j = 0; j < cacheSize; j++, i--) {
203 QCOMPARE(c.takeFirst(), i-1);
204 QCOMPARE(c.count(), cacheSize-j-1);
205 QCOMPARE(c.available(), j+1);
206 QVERIFY(!c.isFull());
207 QCOMPARE(c.isEmpty(), j==cacheSize-1);
208 }
209}
210
211struct RefCountingClassData
212{
213 QBasicAtomicInt ref;
214 static RefCountingClassData shared_null;
215};
216
217RefCountingClassData RefCountingClassData::shared_null = {
218 Q_BASIC_ATOMIC_INITIALIZER(1)
219};
220
221class RefCountingClass
222{
223public:
224 RefCountingClass() : d(&RefCountingClassData::shared_null) { d->ref.ref(); }
225
226 RefCountingClass(const RefCountingClass &other)
227 {
228 d = other.d;
229 d->ref.ref();
230 }
231
232 ~RefCountingClass()
233 {
234 if (!d->ref.deref())
235 delete d;
236 }
237
238 RefCountingClass &operator=(const RefCountingClass &other)
239 {
240 if (!d->ref.deref())
241 delete d;
242 d = other.d;
243 d->ref.ref();
244 return *this;
245 }
246
247 int refCount() const { return d->ref.loadRelaxed(); }
248private:
249 RefCountingClassData *d;
250};
251
252void tst_QContiguousCache::complexType()
253{
254 RefCountingClass original;
255
256 QContiguousCache<RefCountingClass> contiguousCache(10);
257 contiguousCache.append(value: original);
258 QCOMPARE(original.refCount(), 3);
259 contiguousCache.removeFirst();
260 QCOMPARE(original.refCount(), 2); // shared null, 'original'.
261 contiguousCache.append(value: original);
262 QCOMPARE(original.refCount(), 3);
263 contiguousCache.clear();
264 QCOMPARE(original.refCount(), 2);
265
266 for(int i = 0; i < 100; ++i)
267 contiguousCache.insert(pos: i, value: original);
268
269 QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
270
271 contiguousCache.clear();
272 QCOMPARE(original.refCount(), 2);
273 for (int i = 0; i < 100; i++)
274 contiguousCache.append(value: original);
275
276 QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
277 contiguousCache.clear();
278 QCOMPARE(original.refCount(), 2);
279
280 for (int i = 0; i < 100; i++)
281 contiguousCache.prepend(value: original);
282
283 QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
284 contiguousCache.clear();
285 QCOMPARE(original.refCount(), 2);
286
287 for (int i = 0; i < 100; i++)
288 contiguousCache.append(value: original);
289
290 contiguousCache.takeLast();
291 QCOMPARE(original.refCount(), 11);
292
293 contiguousCache.takeFirst();
294 QCOMPARE(original.refCount(), 10);
295}
296
297void tst_QContiguousCache::operatorAt()
298{
299 RefCountingClass original;
300 QContiguousCache<RefCountingClass> contiguousCache(10);
301
302 for (int i = 25; i < 35; ++i)
303 contiguousCache[i] = original;
304
305 QCOMPARE(original.refCount(), 12); // shared null, orig, items in cache
306
307 // verify const access does not copy items.
308 const QContiguousCache<RefCountingClass> copy(contiguousCache);
309 for (int i = 25; i < 35; ++i)
310 QCOMPARE(copy[i].refCount(), 12);
311
312 // verify modifying the original increments ref count (e.g. does a detach)
313 contiguousCache[25] = original;
314 QCOMPARE(original.refCount(), 22);
315}
316
317void tst_QContiguousCache::setCapacity()
318{
319 int i;
320 QContiguousCache<int> contiguousCache(100);
321 for (i = 280; i < 310; ++i)
322 contiguousCache.insert(pos: i, value: i);
323 QCOMPARE(contiguousCache.capacity(), 100);
324 QCOMPARE(contiguousCache.count(), 30);
325 QCOMPARE(contiguousCache.firstIndex(), 280);
326 QCOMPARE(contiguousCache.lastIndex(), 309);
327
328 for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
329 QVERIFY(contiguousCache.containsIndex(i));
330 QCOMPARE(contiguousCache.at(i), i);
331 }
332
333 contiguousCache.setCapacity(150);
334
335 QCOMPARE(contiguousCache.capacity(), 150);
336 QCOMPARE(contiguousCache.count(), 30);
337 QCOMPARE(contiguousCache.firstIndex(), 280);
338 QCOMPARE(contiguousCache.lastIndex(), 309);
339
340 for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
341 QVERIFY(contiguousCache.containsIndex(i));
342 QCOMPARE(contiguousCache.at(i), i);
343 }
344
345 contiguousCache.setCapacity(20);
346
347 QCOMPARE(contiguousCache.capacity(), 20);
348 QCOMPARE(contiguousCache.count(), 20);
349 QCOMPARE(contiguousCache.firstIndex(), 290);
350 QCOMPARE(contiguousCache.lastIndex(), 309);
351
352 for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
353 QVERIFY(contiguousCache.containsIndex(i));
354 QCOMPARE(contiguousCache.at(i), i);
355 }
356}
357
358void tst_QContiguousCache::zeroCapacity()
359{
360 QContiguousCache<int> contiguousCache;
361 QCOMPARE(contiguousCache.capacity(),0);
362 contiguousCache.setCapacity(10);
363 QCOMPARE(contiguousCache.capacity(),10);
364 contiguousCache.setCapacity(0);
365 QCOMPARE(contiguousCache.capacity(),0);
366}
367
368void tst_QContiguousCache::modifyZeroCapacityCache()
369{
370 {
371 QContiguousCache<int> contiguousCache;
372 contiguousCache.insert(pos: 0, value: 42);
373 }
374 {
375 QContiguousCache<int> contiguousCache;
376 contiguousCache.insert(pos: 1, value: 42);
377 }
378 {
379 QContiguousCache<int> contiguousCache;
380 contiguousCache.append(value: 42);
381 }
382 {
383 QContiguousCache<int> contiguousCache;
384 contiguousCache.prepend(value: 42);
385 }
386}
387
388#include "tst_qcontiguouscache.moc"
389

source code of qtbase/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp