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 | |
33 | class tst_QCache : public QObject |
34 | { |
35 | Q_OBJECT |
36 | public slots: |
37 | void initTestCase(); |
38 | void cleanupTestCase(); |
39 | private 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 | |
53 | struct 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 | |
62 | int Foo::count = 0; |
63 | |
64 | void tst_QCache::initTestCase() |
65 | { |
66 | Foo::count = 0; |
67 | } |
68 | |
69 | void tst_QCache::cleanupTestCase() |
70 | { |
71 | // always check for memory leaks |
72 | QCOMPARE(Foo::count, 0); |
73 | } |
74 | |
75 | void 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 | |
118 | void 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 | |
152 | void 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 | |
185 | void 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 | |
219 | void 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 | |
252 | void 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 | |
276 | void 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 | |
296 | void 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 | |
321 | void 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 | |
354 | struct KeyType |
355 | { |
356 | int foo; |
357 | |
358 | KeyType(int x) : foo(x) {} |
359 | |
360 | private: |
361 | KeyType &operator=(const KeyType &); |
362 | }; |
363 | |
364 | struct ValueType |
365 | { |
366 | int foo; |
367 | |
368 | ValueType(int x) : foo(x) {} |
369 | |
370 | private: |
371 | ValueType(const ValueType &); |
372 | ValueType &operator=(const ValueType &); |
373 | }; |
374 | |
375 | bool operator==(const KeyType &key1, const KeyType &key2) |
376 | { |
377 | return key1.foo == key2.foo; |
378 | } |
379 | |
380 | uint qHash(const KeyType &key) |
381 | { |
382 | return qHash(key: key.foo); |
383 | } |
384 | |
385 | void 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 | |
401 | QTEST_APPLESS_MAIN(tst_QCache) |
402 | #include "tst_qcache.moc" |
403 | |