1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module 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#include <QList>
31#include <Qt3DCore/private/qhandle_p.h>
32#include <Qt3DCore/private/qresourcemanager_p.h>
33
34class tst_QResourceManager : public QObject
35{
36 Q_OBJECT
37public:
38 tst_QResourceManager() {}
39 ~tst_QResourceManager() {}
40
41private slots:
42 void createResourcesManager();
43 void acquireResources();
44 void getResources();
45 void registerResourcesResize();
46 void removeResource();
47 void lookupResource();
48 void releaseResource();
49 void heavyDutyMultiThreadedAccess();
50 void heavyDutyMultiThreadedAccessRelease();
51 void collectResources();
52 void activeHandles();
53 void checkCleanup();
54};
55
56class tst_ArrayResource
57{
58public:
59 tst_ArrayResource() : m_value(0)
60 {}
61
62 void cleanup() { m_value = 0; }
63
64 QAtomicInt m_value;
65};
66
67QT_BEGIN_NAMESPACE
68Q_DECLARE_RESOURCE_INFO(tst_ArrayResource, Q_REQUIRES_CLEANUP)
69QT_END_NAMESPACE
70
71typedef Qt3DCore::QHandle<tst_ArrayResource> tHandle;
72
73void tst_QResourceManager::createResourcesManager()
74{
75 Qt3DCore::QResourceManager<tst_ArrayResource, int> manager;
76}
77
78/*!
79 * Check that the handles returned when a registering resources
80 * have a correct index and counter.
81 */
82void tst_QResourceManager::acquireResources()
83{
84 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
85
86 QList<tHandle> handles;
87
88 for (int i = 0; i < 5; i++) {
89 handles << manager.acquire();
90 }
91
92 for (uint i = 0; i < 5; i++) {
93 QVERIFY(!handles.at(i).isNull());
94 if (i > 0)
95 QVERIFY(handles.at(i) != handles.at(i-1));
96 }
97}
98
99/*!
100 * Test that values can be properly retrieved.
101 */
102void tst_QResourceManager::getResources()
103{
104
105 Qt3DCore::QResourceManager<tst_ArrayResource, int> manager;
106 QList<tst_ArrayResource *> resources;
107 QList<tHandle> handles;
108
109 for (int i = 0; i < 5; i++) {
110 handles << manager.acquire();
111 }
112
113 for (uint i = 0; i < 5; i++) {
114 resources << manager.data(handle: handles.at(i));
115 QVERIFY(resources.at(i) != nullptr);
116 resources.at(i)->m_value = i;
117 }
118
119 for (int i = 0; i < 5; i++)
120 QVERIFY(manager.data(handles.at(i))->m_value == i);
121
122 // Check that an invalid resource returns NULL
123 tHandle iHandle;
124 QVERIFY(manager.data(iHandle) == nullptr);
125
126}
127
128/*!
129 * Test that when a resize of the data vectors in the manager occurs,
130 * everything behaves correctly.
131 */
132void tst_QResourceManager::registerResourcesResize()
133{
134 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
135 QList<tHandle> handles;
136
137 for (uint i = 0; i < 2; i++) {
138 handles << manager.acquire();
139 manager.data(handle: handles.at(i))->m_value = i + 2;
140 }
141
142 for (uint i = 0; i < 5; i++) {
143 handles << manager.acquire();
144 manager.data(handle: handles.at(i: i + 2))->m_value = i + 2 + 5;
145 }
146
147 for (int i = 0; i < 7; i++) {
148 if (i < 2)
149 QVERIFY(manager.data(handles.at(i))->m_value == i + 2);
150 else
151 QVERIFY(manager.data(handles.at(i))->m_value == i + 5);
152 }
153}
154
155/*!
156 * Checks for the removal of resources.
157 */
158void tst_QResourceManager::removeResource()
159{
160 Qt3DCore::QResourceManager<tst_ArrayResource, int> manager;
161
162 QList<tHandle> handles;
163
164 for (int i = 0; i < 32; i++) {
165 handles << manager.acquire();
166 }
167
168
169 tst_ArrayResource *resource = handles.at(i: 2).data();
170 QVERIFY(resource != nullptr);
171
172 manager.release(handle: handles.at(i: 2));
173 QVERIFY(manager.data(handles.at(2)) == nullptr);
174 // Triggers QASSERT so commented
175 // manager.release(handles.at(2));
176
177 tHandle nHandle = manager.acquire();
178 QVERIFY(manager.data(nHandle) != nullptr);
179}
180
181void tst_QResourceManager::lookupResource()
182{
183 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
184
185 QList<tst_ArrayResource *> resources;
186 QList<tHandle> handles;
187
188 for (int i = 0; i < 5; i++) {
189 handles << manager.acquire();
190 resources << manager.data(handle: handles.at(i));
191 resources.at(i)->m_value = 4;
192 }
193
194 tHandle t = manager.lookupHandle(id: 2);
195 QVERIFY(t.handle() == 0);
196 QVERIFY(manager.data(t) == nullptr);
197 tst_ArrayResource *resource = manager.getOrCreateResource(id: 2);
198 QVERIFY(resource != nullptr);
199 t = manager.lookupHandle(id: 2);
200 QVERIFY(manager.data(t) == manager.lookupResource(2));
201 QVERIFY(t == manager.getOrAcquireHandle(2));
202 QVERIFY(resource == manager.getOrCreateResource(2));
203 QVERIFY(manager.data(t) == resource);
204}
205
206void tst_QResourceManager::releaseResource()
207{
208 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
209 QList<tst_ArrayResource *> resources;
210
211 for (int i = 0; i < 5; i++) {
212 resources << manager.getOrCreateResource(id: i);
213 }
214
215 for (int i = 0; i < 5; i++) {
216 QVERIFY(resources.at(i) == manager.lookupResource(i));
217 }
218
219 for (int i = 0; i < 5; i++) {
220 manager.releaseResource(id: i);
221 QVERIFY(manager.lookupResource(i) == nullptr);
222 }
223}
224
225class tst_Thread : public QThread
226{
227 Q_OBJECT
228public:
229
230 typedef Qt3DCore::QResourceManager<tst_ArrayResource,
231 int,
232 Qt3DCore::ObjectLevelLockingPolicy> Manager;
233
234 tst_Thread()
235 : QThread()
236 {
237 }
238
239 void setManager(Manager *manager)
240 {
241 m_manager = manager;
242 }
243
244 // QThread interface
245protected:
246 void run()
247 {
248 int i = 0;
249 int max = 65535;
250 while (i < max) {
251 tst_ArrayResource *r = m_manager->getOrCreateResource(id: i);
252 i++;
253 QVERIFY(r != nullptr);
254 r->m_value.fetchAndAddOrdered(valueToAdd: +1);
255 }
256 qDebug() << QThread::currentThread() << "Done";
257 }
258
259 Manager *m_manager;
260};
261
262void tst_QResourceManager::heavyDutyMultiThreadedAccess()
263{
264 tst_Thread::Manager *manager = new tst_Thread::Manager();
265
266 QList<tst_Thread *> threads;
267
268 int iterations = 8;
269 int max = 65535;
270
271 for (int i = 0; i < iterations; i++) {
272 tst_Thread *thread = new tst_Thread();
273 thread->setManager(manager);
274 threads << thread;
275 }
276
277 for (int i = 0; i < iterations; i++) {
278 threads[i]->start();
279 }
280
281 for (int i = 0; i < iterations; i++) {
282 threads[i]->wait();
283 }
284
285 for (int i = 0; i < max; i++) {
286 QVERIFY(manager->lookupResource(i) != nullptr);
287 QVERIFY(manager->lookupResource(i)->m_value = iterations);
288 }
289
290 qDeleteAll(c: threads);
291 delete manager;
292}
293
294class tst_Thread2 : public QThread
295{
296 Q_OBJECT
297public:
298
299 typedef Qt3DCore::QResourceManager<tst_ArrayResource,
300 int,
301 Qt3DCore::ObjectLevelLockingPolicy> Manager;
302
303 tst_Thread2(int releaseAbove = 7)
304 : QThread()
305 , m_releaseAbove(releaseAbove)
306 {
307 }
308
309 void setManager(Manager *manager)
310 {
311 m_manager = manager;
312 }
313
314 // QThread interface
315protected:
316 void run()
317 {
318 int i = 0;
319 int max = 65535;
320 while (i < max) {
321 tst_ArrayResource *r = m_manager->getOrCreateResource(id: i);
322 QVERIFY(r != nullptr);
323 int oldValue = r->m_value.fetchAndAddOrdered(valueToAdd: +1);
324 if (oldValue == m_releaseAbove)
325 m_manager->releaseResource(id: i);
326 i++;
327 }
328 qDebug() << QThread::currentThread() << "Done";
329 }
330
331 Manager *m_manager;
332 int m_releaseAbove;
333};
334
335void tst_QResourceManager::heavyDutyMultiThreadedAccessRelease()
336{
337 tst_Thread2::Manager *manager = new tst_Thread2::Manager();
338
339 QList<tst_Thread2 *> threads;
340
341 int iterations = 8;
342 int max = 65535;
343
344 for (int u = 0; u < 2; u++) {
345
346 for (int i = 0; i < iterations; i++) {
347 tst_Thread2 *thread = new tst_Thread2();
348 thread->setManager(manager);
349 threads << thread;
350 }
351
352 for (int i = 0; i < iterations; i++) {
353 threads[i]->start();
354 }
355
356 for (int i = 0; i < iterations; i++) {
357 threads[i]->wait();
358 }
359
360 for (int i = 0; i < max; i++) {
361 QVERIFY(manager->lookupResource(i) == nullptr);
362 }
363
364 qDeleteAll(c: threads);
365 threads.clear();
366 }
367
368 delete manager;
369}
370
371void tst_QResourceManager::collectResources()
372{
373 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
374
375 QList<tst_ArrayResource *> resources;
376 QList<tHandle> handles;
377
378 for (int i = 0; i < 65536; i++) {
379 handles << manager.acquire();
380 resources << manager.data(handle: handles.at(i));
381 resources.at(i)->m_value = 4;
382 }
383 for (auto h : handles) {
384 manager.release(handle: h);
385 }
386 Q_ASSERT(manager.count() == 0);
387 handles.clear();
388 manager.acquire();
389 Q_ASSERT(manager.count() == 1);
390}
391
392void tst_QResourceManager::activeHandles()
393{
394 // GIVEN
395 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
396
397 {
398 // WHEN
399 const tHandle newHandle = manager.getOrAcquireHandle(id: 883U);
400 // THEN
401 QCOMPARE(manager.activeHandles().size(), 1);
402 QCOMPARE(manager.activeHandles()[0], newHandle);
403 }
404
405 {
406 // WHEN
407 manager.releaseResource(id: 883U);
408 // THEN
409 QVERIFY(manager.activeHandles().empty());
410 }
411
412 {
413 // WHEN
414 const tHandle newHandle = manager.acquire();
415 // THEN
416 QCOMPARE(manager.activeHandles().size(), 1);
417 QCOMPARE(manager.activeHandles()[0], newHandle);
418
419 // WHEN
420 manager.release(handle: newHandle);
421 // THEN
422 QVERIFY(manager.activeHandles().empty());
423 }
424}
425
426void tst_QResourceManager::checkCleanup()
427{
428 // GIVEN
429 Qt3DCore::QResourceManager<tst_ArrayResource, uint> manager;
430
431 // WHEN
432 tHandle newHandle = manager.getOrAcquireHandle(id: 883U);
433 tst_ArrayResource *data = manager.data(handle: newHandle);
434
435 data->m_value.ref();
436 // THEN
437 QCOMPARE(data->m_value.load(), 1);
438
439 // WHEN
440 manager.release(handle: newHandle);
441
442 // THEN
443 QCOMPARE(data->m_value.load(), 0);
444}
445
446
447
448
449QTEST_APPLESS_MAIN(tst_QResourceManager)
450
451#include "tst_qresourcemanager.moc"
452

source code of qt3d/tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp