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 <QtTest/QtTest>
30
31#include <qcache.h>
32
33class tst_QCache : public QObject
34{
35 Q_OBJECT
36public slots:
37 void initTestCase();
38 void cleanupTestCase();
39private slots:
40 void maxCost();
41 void setMaxCost();
42 void totalCost();
43 void clear();
44 void insert();
45 void contains();
46 void operator_bracket_bracket();
47 void remove();
48 void take();
49 void axioms_on_key_type();
50};
51
52
53struct Foo {
54 static int count;
55 Foo():c(count) { ++count; }
56 Foo(const Foo& o):c(o.c) { ++count; }
57 ~Foo() { --count; }
58 int c;
59 int data[8];
60};
61
62int Foo::count = 0;
63
64void tst_QCache::initTestCase()
65{
66 Foo::count = 0;
67}
68
69void tst_QCache::cleanupTestCase()
70{
71 // always check for memory leaks
72 QCOMPARE(Foo::count, 0);
73}
74
75void tst_QCache::maxCost()
76{
77 QCache<QString, int> cache1, cache2(100), cache3(200), cache4(-50);
78 QCOMPARE(cache1.maxCost(), 100);
79 QCOMPARE(cache2.maxCost(), 100);
80 QCOMPARE(cache3.maxCost(), 200);
81 QCOMPARE(cache4.maxCost(), -50); // 0 would also make sense
82
83 cache1.setMaxCost(101);
84 QCOMPARE(cache1.maxCost(), 101);
85
86 cache1.insert(akey: "one", aobject: new int(1), acost: 1);
87 cache1.insert(akey: "two", aobject: new int(2), acost: 1);
88 QCOMPARE(cache1.totalCost(), 2);
89 QCOMPARE(cache1.size(), 2);
90 QCOMPARE(cache1.maxCost(), 101);
91
92 cache1.insert(akey: "three", aobject: new int(3), acost: 98);
93 QCOMPARE(cache1.totalCost(), 100);
94 QCOMPARE(cache1.size(), 3);
95 QCOMPARE(cache1.maxCost(), 101);
96
97 cache1.insert(akey: "four", aobject: new int(4), acost: 1);
98 QCOMPARE(cache1.totalCost(), 101);
99 QCOMPARE(cache1.size(), 4);
100 QCOMPARE(cache1.maxCost(), 101);
101
102 cache1.insert(akey: "five", aobject: new int(4), acost: 1);
103 QVERIFY(cache1.totalCost() <= 101);
104 QVERIFY(cache1.size() == 4);
105 QCOMPARE(cache1.maxCost(), 101);
106
107 cache1.setMaxCost(-1);
108 QCOMPARE(cache1.totalCost(), 0);
109 QCOMPARE(cache1.maxCost(), -1);
110
111 cache2.setMaxCost(202);
112 QCOMPARE(cache2.maxCost(), 202);
113
114 cache3.setMaxCost(-50);
115 QCOMPARE(cache3.maxCost(), -50);
116}
117
118void tst_QCache::setMaxCost()
119{
120 QCache<int, Foo> cache;
121 cache.setMaxCost(2);
122 cache.insert(akey: 1, aobject: new Foo);
123 cache.insert(akey: 2, aobject: new Foo);
124 QCOMPARE(cache.totalCost(), 2);
125 QCOMPARE(Foo::count, 2);
126
127 cache.insert(akey: 3, aobject: new Foo);
128 QCOMPARE(cache.totalCost(), 2);
129 QCOMPARE(Foo::count, 2);
130
131 cache.setMaxCost(3);
132 QCOMPARE(cache.totalCost(), 2);
133 QCOMPARE(Foo::count, 2);
134
135 cache.setMaxCost(2);
136 QCOMPARE(cache.totalCost(), 2);
137 QCOMPARE(Foo::count, 2);
138
139 cache.setMaxCost(1);
140 QCOMPARE(cache.totalCost(), 1);
141 QCOMPARE(Foo::count, 1);
142
143 cache.setMaxCost(0);
144 QCOMPARE(cache.totalCost(), 0);
145 QCOMPARE(Foo::count, 0);
146
147 cache.setMaxCost(-1);
148 QCOMPARE(cache.totalCost(), 0);
149 QCOMPARE(Foo::count, 0);
150}
151
152void tst_QCache::totalCost()
153{
154 QCache<QString, int> cache;
155 QCOMPARE(cache.totalCost(), 0);
156
157 cache.insert(akey: "one", aobject: new int(1), acost: 0);
158 QCOMPARE(cache.totalCost(), 0);
159
160 cache.insert(akey: "two", aobject: new int(2), acost: 1);
161 QCOMPARE(cache.totalCost(), 1);
162
163 cache.insert(akey: "three", aobject: new int(3), acost: 2);
164 QCOMPARE(cache.totalCost(), 3);
165
166 cache.insert(akey: "four", aobject: new int(4), acost: 10000);
167 QCOMPARE(cache.totalCost(), 3);
168 QVERIFY(!cache.contains("four"));
169
170 cache.insert(akey: "five", aobject: new int(5), acost: -5);
171 QCOMPARE(cache.totalCost(), -2);
172
173 cache.insert(akey: "six", aobject: new int(6), acost: 101);
174 QCOMPARE(cache.totalCost(), -2);
175
176 cache.insert(akey: "seven", aobject: new int(7), acost: 100);
177 QCOMPARE(cache.totalCost(), 98);
178 QCOMPARE(cache.size(), 5);
179
180 cache.insert(akey: "eight", aobject: new int(8), acost: 2);
181 QCOMPARE(cache.totalCost(), 100);
182 QCOMPARE(cache.size(), 6);
183}
184
185void tst_QCache::clear()
186{
187 {
188 QCache<QString, Foo> cache(200);
189 QCOMPARE(cache.totalCost(), 0);
190
191 for (int i = -3; i < 9; ++i)
192 cache.insert(akey: QString::number(i), aobject: new Foo, acost: i);
193 QCOMPARE(cache.totalCost(), 30);
194
195 QCOMPARE(cache.size(), 12);
196 QVERIFY(!cache.isEmpty());
197 cache.setMaxCost(300);
198
199 for (int j = 0; j < 3; ++j) {
200 cache.clear();
201 QCOMPARE(cache.totalCost(), 0);
202 QCOMPARE(cache.size(), 0);
203 QVERIFY(cache.isEmpty());
204 QCOMPARE(Foo::count, 0);
205 QCOMPARE(cache.maxCost(), 300);
206 }
207 cache.insert(akey: "10", aobject: new Foo, acost: 10);
208 QCOMPARE(cache.size(), 1);
209 cache.setMaxCost(9);
210 QCOMPARE(cache.size(), 0);
211
212 cache.insert(akey: "11", aobject: new Foo, acost: 9);
213 QCOMPARE(cache.size(), 1);
214 QCOMPARE(Foo::count, 1);
215 }
216 QCOMPARE(Foo::count, 0);
217}
218
219void tst_QCache::insert()
220{
221 QCache<QString, Foo> cache;
222
223 Foo *f1 = new Foo;
224 cache.insert(akey: "one", aobject: f1, acost: 1);
225 QVERIFY(cache.contains("one"));
226
227 Foo *f2 = new Foo;
228 cache.insert(akey: "two", aobject: f2, acost: 2);
229 QVERIFY(cache.contains("two"));
230 QCOMPARE(cache.size(), 2);
231
232 Foo *f3 = new Foo;
233 cache.insert(akey: "two", aobject: f3, acost: 2);
234 QVERIFY(cache.contains("two"));
235 QCOMPARE(cache.size(), 2);
236
237 QVERIFY(cache["two"] == f3);
238 QCOMPARE(Foo::count, 2);
239
240 /*
241 If the new item is too big, any item with the same name in
242 the cache must still be removed, otherwise the application
243 might get bad results.
244 */
245 Foo *f4 = new Foo;
246 cache.insert(akey: "two", aobject: f4, acost: 10000);
247 QVERIFY(!cache.contains("two"));
248 QCOMPARE(cache.size(), 1);
249 QCOMPARE(Foo::count, 1);
250}
251
252void tst_QCache::contains()
253{
254 QCache<int, int> cache;
255 QVERIFY(!cache.contains(0));
256 QVERIFY(!cache.contains(1));
257
258 cache.insert(akey: 1, aobject: new int(1), acost: 1);
259 QVERIFY(!cache.contains(0));
260 QVERIFY(cache.contains(1));
261
262 cache.remove(key: 0);
263 cache.remove(key: 1);
264 QVERIFY(!cache.contains(0));
265 QVERIFY(!cache.contains(1));
266
267 cache.insert(akey: 1, aobject: new int(1), acost: 1);
268 QVERIFY(!cache.contains(0));
269 QVERIFY(cache.contains(1));
270
271 cache.clear();
272 QVERIFY(!cache.contains(0));
273 QVERIFY(!cache.contains(1));
274}
275
276void tst_QCache::operator_bracket_bracket()
277{
278 QCache<int, int> cache;
279 cache.insert(akey: 1, aobject: new int(2));
280 QVERIFY(cache[0] == 0);
281 QVERIFY(cache[1] != 0);
282 QCOMPARE(*cache[1], 2);
283
284 cache.insert(akey: 1, aobject: new int(4));
285 QVERIFY(cache[1] != 0);
286 QCOMPARE(*cache[1], 4);
287
288 // check that operator[] doesn't remove the item
289 QVERIFY(cache[1] != 0);
290 QCOMPARE(*cache[1], 4);
291
292 cache.remove(key: 1);
293 QVERIFY(cache[1] == 0);
294}
295
296void tst_QCache::remove()
297{
298 QCache<QString, Foo> cache;
299 cache.remove(key: QString());
300 cache.remove(key: "alpha");
301 QVERIFY(cache.isEmpty());
302
303 cache.insert(akey: "alpha", aobject: new Foo, acost: 10);
304 QCOMPARE(cache.size(), 1);
305
306 cache.insert(akey: "beta", aobject: new Foo, acost: 20);
307 QCOMPARE(cache.size(), 2);
308
309 for (int i = 0; i < 10; ++i) {
310 cache.remove(key: "alpha");
311 QCOMPARE(cache.size(), 1);
312 QCOMPARE(cache.totalCost(), 20);
313 }
314
315 cache.setMaxCost(1);
316 QCOMPARE(cache.size(), 0);
317 cache.remove(key: "beta");
318 QCOMPARE(cache.size(), 0);
319}
320
321void tst_QCache::take()
322{
323 QCache<QString, Foo> cache;
324 QCOMPARE(cache.take(QString()), (Foo*)0);
325 QCOMPARE(cache.take("alpha"), (Foo*)0);
326 QVERIFY(cache.isEmpty());
327
328 Foo *f1 = new Foo;
329 cache.insert(akey: "alpha", aobject: f1, acost: 10);
330 QCOMPARE(cache.size(), 1);
331 QVERIFY(cache["alpha"] == f1);
332
333 cache.insert(akey: "beta", aobject: new Foo, acost: 20);
334 QCOMPARE(cache.size(), 2);
335
336 QCOMPARE(cache.take("alpha"), f1);
337 QCOMPARE(cache.size(), 1);
338 QCOMPARE(cache.totalCost(), 20);
339 QCOMPARE(Foo::count, 2);
340 delete f1;
341 QCOMPARE(Foo::count, 1);
342
343 QCOMPARE(cache.take("alpha"), (Foo*)0);
344 QCOMPARE(Foo::count, 1);
345 QCOMPARE(cache.size(), 1);
346 QCOMPARE(cache.totalCost(), 20);
347
348 cache.setMaxCost(1);
349 QCOMPARE(cache.size(), 0);
350 QCOMPARE(cache.take("beta"), (Foo*)0);
351 QCOMPARE(cache.size(), 0);
352}
353
354struct KeyType
355{
356 int foo;
357
358 KeyType(int x) : foo(x) {}
359
360private:
361 KeyType &operator=(const KeyType &);
362};
363
364struct ValueType
365{
366 int foo;
367
368 ValueType(int x) : foo(x) {}
369
370private:
371 ValueType(const ValueType &);
372 ValueType &operator=(const ValueType &);
373};
374
375bool operator==(const KeyType &key1, const KeyType &key2)
376{
377 return key1.foo == key2.foo;
378}
379
380uint qHash(const KeyType &key)
381{
382 return qHash(key: key.foo);
383}
384
385void tst_QCache::axioms_on_key_type()
386{
387 QCache<KeyType, ValueType> foo;
388 foo.setMaxCost(1);
389 foo.clear();
390 foo.insert(akey: KeyType(123), aobject: new ValueType(123));
391 foo.object(key: KeyType(123));
392 foo.contains(key: KeyType(456));
393 foo[KeyType(456)];
394 foo.remove(key: KeyType(456));
395 foo.remove(key: KeyType(123));
396 foo.take(key: KeyType(789));
397// If this fails, contact the maintaner
398 QVERIFY(sizeof(QHash<int, int>) == sizeof(void *));
399}
400
401QTEST_APPLESS_MAIN(tst_QCache)
402#include "tst_qcache.moc"
403

source code of qtbase/tests/auto/corelib/tools/qcache/tst_qcache.cpp