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 | // TODO Remove in Qt6 |
30 | #include <QtCore/qcompilerdetection.h> |
31 | QT_WARNING_DISABLE_DEPRECATED |
32 | |
33 | #include <QtTest/QtTest> |
34 | #include <Qt3DCore/qentity.h> |
35 | #include <Qt3DCore/private/qentity_p.h> |
36 | #include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> |
37 | #include <Qt3DCore/qcomponent.h> |
38 | #include <QtCore/qscopedpointer.h> |
39 | |
40 | using namespace Qt3DCore; |
41 | |
42 | class tst_Entity : public QObject |
43 | { |
44 | Q_OBJECT |
45 | public: |
46 | tst_Entity() : QObject() |
47 | { |
48 | qRegisterMetaType<Qt3DCore::QNode*>(); |
49 | } |
50 | ~tst_Entity() {} |
51 | |
52 | private slots: |
53 | void constructionDestruction(); |
54 | |
55 | void addComponentSingleParentSingleAggregation(); |
56 | void addComponentSingleParentSeveralAggregations(); |
57 | void addComponentsSeveralParentsSingleAggregations(); |
58 | void addComponentsSeveralParentsSeveralAggregations(); |
59 | |
60 | void retrieveSingleComponent(); |
61 | |
62 | void removeComponentSingleParentSingleAggregation(); |
63 | void removeComponentSingleParentSeveralAggregations(); |
64 | void removeComponentsSeveralParentsSingleAggreation(); |
65 | void removeComponentsSeveralParentsSeveralAggregations(); |
66 | |
67 | void addSeveralTimesSameComponent(); |
68 | void removeSeveralTimesSameComponent(); |
69 | |
70 | void checkCloning_data(); |
71 | void checkCloning(); |
72 | |
73 | void checkComponentBookkeeping(); |
74 | }; |
75 | |
76 | class MyQComponent : public Qt3DCore::QComponent |
77 | { |
78 | Q_OBJECT |
79 | public: |
80 | explicit MyQComponent(Qt3DCore::QNode *parent = nullptr) |
81 | : QComponent(parent) |
82 | {} |
83 | }; |
84 | |
85 | class MyQ2Component : public Qt3DCore::QComponent |
86 | { |
87 | Q_OBJECT |
88 | public: |
89 | explicit MyQ2Component(Qt3DCore::QNode *parent = 0) |
90 | : QComponent(parent) |
91 | {} |
92 | }; |
93 | |
94 | class MyEntity : public Qt3DCore::QEntity |
95 | { |
96 | public: |
97 | explicit MyEntity(Qt3DCore::QNode *parent = nullptr) |
98 | : QEntity(parent) |
99 | {} |
100 | }; |
101 | |
102 | void tst_Entity::constructionDestruction() |
103 | { |
104 | // GIVEN |
105 | QEntity *entity = nullptr; |
106 | // WHEN |
107 | entity = new QEntity; |
108 | // THEN |
109 | QVERIFY(entity != nullptr); |
110 | |
111 | delete entity; |
112 | |
113 | // GIVEN |
114 | QScopedPointer<QEntity> entity2(new QEntity); |
115 | // WHEN |
116 | entity2.reset(other: nullptr); |
117 | // THEN |
118 | // this should not crash |
119 | } |
120 | |
121 | void tst_Entity::addComponentSingleParentSingleAggregation() |
122 | { |
123 | // GIVEN |
124 | QScopedPointer<Qt3DCore::QEntity> entity(new QEntity()); |
125 | MyQComponent *comp = new MyQComponent(entity.data()); |
126 | QCoreApplication::processEvents(); |
127 | |
128 | // THEN |
129 | QVERIFY(comp->parent() == entity.data()); |
130 | QCOMPARE(entity->components().size(), 0); |
131 | QCOMPARE(entity->children().size(), 1); |
132 | QCOMPARE(comp->entities().size(), 0); |
133 | |
134 | // WHEN |
135 | entity->addComponent(comp); |
136 | |
137 | // THEN |
138 | QVERIFY(comp->parent() == entity.data()); |
139 | QCOMPARE(entity->components().size(), 1); |
140 | QCOMPARE(entity->children().size(), 1); |
141 | QCOMPARE(comp->entities().size(), 1); |
142 | } |
143 | |
144 | void tst_Entity::addComponentSingleParentSeveralAggregations() |
145 | { |
146 | // GIVEN |
147 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
148 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
149 | |
150 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
151 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
152 | MyQComponent *comp3 = new MyQComponent(entity1.data()); |
153 | QCoreApplication::processEvents(); |
154 | |
155 | // THEN |
156 | QVERIFY(comp1->parent() == entity1.data()); |
157 | QVERIFY(comp2->parent() == entity1.data()); |
158 | QVERIFY(comp3->parent() == entity1.data()); |
159 | |
160 | QCOMPARE(entity1->components().size(), 0); |
161 | QCOMPARE(entity2->components().size(), 0); |
162 | |
163 | QCOMPARE(entity1->children().size(), 3); |
164 | QCOMPARE(entity2->children().size(), 0); |
165 | |
166 | QCOMPARE(comp1->entities().size(), 0); |
167 | QCOMPARE(comp2->entities().size(), 0); |
168 | QCOMPARE(comp3->entities().size(), 0); |
169 | |
170 | // WHEN |
171 | entity1->addComponent(comp: comp1); |
172 | entity1->addComponent(comp: comp2); |
173 | entity1->addComponent(comp: comp3); |
174 | |
175 | entity2->addComponent(comp: comp1); |
176 | entity2->addComponent(comp: comp2); |
177 | entity2->addComponent(comp: comp3); |
178 | |
179 | // THEN |
180 | QVERIFY(comp1->parent() == entity1.data()); |
181 | QVERIFY(comp2->parent() == entity1.data()); |
182 | QVERIFY(comp3->parent() == entity1.data()); |
183 | |
184 | QCOMPARE(entity1->components().size(), 3); |
185 | QCOMPARE(entity2->components().size(), 3); |
186 | |
187 | QCOMPARE(entity1->children().size(), 3); |
188 | QCOMPARE(entity2->children().size(), 0); |
189 | |
190 | QCOMPARE(comp1->entities().size(), 2); |
191 | QCOMPARE(comp2->entities().size(), 2); |
192 | QCOMPARE(comp3->entities().size(), 2); |
193 | } |
194 | |
195 | void tst_Entity::addComponentsSeveralParentsSingleAggregations() |
196 | { |
197 | // GIVEN |
198 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
199 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
200 | |
201 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
202 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
203 | MyQComponent *comp3 = new MyQComponent(entity2.data()); |
204 | QCoreApplication::processEvents(); |
205 | |
206 | // THEN |
207 | QVERIFY(comp1->parent() == entity1.data()); |
208 | QVERIFY(comp2->parent() == entity1.data()); |
209 | QVERIFY(comp3->parent() == entity2.data()); |
210 | |
211 | QCOMPARE(entity1->components().size(), 0); |
212 | QCOMPARE(entity2->components().size(), 0); |
213 | |
214 | QCOMPARE(entity1->children().size(), 2); |
215 | QCOMPARE(entity2->children().size(), 1); |
216 | |
217 | QCOMPARE(comp1->entities().size(), 0); |
218 | QCOMPARE(comp2->entities().size(), 0); |
219 | QCOMPARE(comp3->entities().size(), 0); |
220 | |
221 | // WHEN |
222 | entity1->addComponent(comp: comp1); |
223 | entity1->addComponent(comp: comp2); |
224 | |
225 | entity2->addComponent(comp: comp3); |
226 | |
227 | // THEN |
228 | QVERIFY(comp1->parent() == entity1.data()); |
229 | QVERIFY(comp2->parent() == entity1.data()); |
230 | QVERIFY(comp3->parent() == entity2.data()); |
231 | |
232 | QCOMPARE(entity1->components().size(), 2); |
233 | QCOMPARE(entity2->components().size(), 1); |
234 | |
235 | QCOMPARE(entity1->children().size(), 2); |
236 | QCOMPARE(entity2->children().size(), 1); |
237 | |
238 | QCOMPARE(comp1->entities().size(), 1); |
239 | QCOMPARE(comp2->entities().size(), 1); |
240 | QCOMPARE(comp3->entities().size(), 1); |
241 | } |
242 | |
243 | void tst_Entity::addComponentsSeveralParentsSeveralAggregations() |
244 | { |
245 | // GIVEN |
246 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
247 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
248 | |
249 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
250 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
251 | MyQComponent *comp3 = new MyQComponent(entity2.data()); |
252 | QCoreApplication::processEvents(); |
253 | |
254 | // THEN |
255 | QVERIFY(comp1->parent() == entity1.data()); |
256 | QVERIFY(comp2->parent() == entity1.data()); |
257 | QVERIFY(comp3->parent() == entity2.data()); |
258 | |
259 | QCOMPARE(entity1->components().size(), 0); |
260 | QCOMPARE(entity2->components().size(), 0); |
261 | |
262 | QCOMPARE(entity1->children().size(), 2); |
263 | QCOMPARE(entity2->children().size(), 1); |
264 | |
265 | QCOMPARE(comp1->entities().size(), 0); |
266 | QCOMPARE(comp2->entities().size(), 0); |
267 | QCOMPARE(comp3->entities().size(), 0); |
268 | |
269 | // WHEN |
270 | entity1->addComponent(comp: comp1); |
271 | entity1->addComponent(comp: comp2); |
272 | entity1->addComponent(comp: comp3); |
273 | |
274 | entity2->addComponent(comp: comp1); |
275 | entity2->addComponent(comp: comp2); |
276 | entity2->addComponent(comp: comp3); |
277 | |
278 | // THEN |
279 | QVERIFY(comp1->parent() == entity1.data()); |
280 | QVERIFY(comp2->parent() == entity1.data()); |
281 | QVERIFY(comp3->parent() == entity2.data()); |
282 | |
283 | QCOMPARE(entity1->components().size(), 3); |
284 | QCOMPARE(entity2->components().size(), 3); |
285 | |
286 | QCOMPARE(entity1->children().size(), 2); |
287 | QCOMPARE(entity2->children().size(), 1); |
288 | |
289 | QCOMPARE(comp1->entities().size(), 2); |
290 | QCOMPARE(comp2->entities().size(), 2); |
291 | QCOMPARE(comp3->entities().size(), 2); |
292 | } |
293 | |
294 | void tst_Entity::removeComponentSingleParentSingleAggregation() |
295 | { |
296 | // GIVEN |
297 | QScopedPointer<Qt3DCore::QEntity> entity(new QEntity()); |
298 | MyQComponent *comp = new MyQComponent(entity.data()); |
299 | QCoreApplication::processEvents(); |
300 | entity->addComponent(comp); |
301 | |
302 | // THEN |
303 | QVERIFY(comp->parent() == entity.data()); |
304 | QCOMPARE(entity->components().size(), 1); |
305 | QCOMPARE(entity->children().size(), 1); |
306 | QCOMPARE(comp->entities().size(), 1); |
307 | |
308 | // WHEN |
309 | entity->removeComponent(comp); |
310 | |
311 | // THEN |
312 | QVERIFY(comp->parent() == entity.data()); |
313 | QCOMPARE(entity->components().size(), 0); |
314 | QCOMPARE(entity->children().size(), 1); |
315 | QCOMPARE(comp->entities().size(), 0); |
316 | } |
317 | |
318 | void tst_Entity::removeComponentSingleParentSeveralAggregations() |
319 | { |
320 | // GIVEN |
321 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
322 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
323 | |
324 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
325 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
326 | MyQComponent *comp3 = new MyQComponent(entity1.data()); |
327 | QCoreApplication::processEvents(); |
328 | |
329 | entity1->addComponent(comp: comp1); |
330 | entity1->addComponent(comp: comp2); |
331 | entity1->addComponent(comp: comp3); |
332 | |
333 | entity2->addComponent(comp: comp1); |
334 | entity2->addComponent(comp: comp2); |
335 | entity2->addComponent(comp: comp3); |
336 | |
337 | // THEN |
338 | QVERIFY(comp1->parent() == entity1.data()); |
339 | QVERIFY(comp2->parent() == entity1.data()); |
340 | QVERIFY(comp3->parent() == entity1.data()); |
341 | |
342 | QCOMPARE(entity1->components().size(), 3); |
343 | QCOMPARE(entity2->components().size(), 3); |
344 | |
345 | QCOMPARE(entity1->children().size(), 3); |
346 | QCOMPARE(entity2->children().size(), 0); |
347 | |
348 | QCOMPARE(comp1->entities().size(), 2); |
349 | QCOMPARE(comp2->entities().size(), 2); |
350 | QCOMPARE(comp3->entities().size(), 2); |
351 | |
352 | // WHEN |
353 | entity1->removeComponent(comp: comp1); |
354 | entity1->removeComponent(comp: comp2); |
355 | entity1->removeComponent(comp: comp3); |
356 | |
357 | // THEN |
358 | QVERIFY(comp1->parent() == entity1.data()); |
359 | QVERIFY(comp2->parent() == entity1.data()); |
360 | QVERIFY(comp3->parent() == entity1.data()); |
361 | |
362 | QCOMPARE(entity1->components().size(), 0); |
363 | QCOMPARE(entity2->components().size(), 3); |
364 | |
365 | QCOMPARE(entity1->children().size(), 3); |
366 | QCOMPARE(entity2->children().size(), 0); |
367 | |
368 | QCOMPARE(comp1->entities().size(), 1); |
369 | QCOMPARE(comp2->entities().size(), 1); |
370 | QCOMPARE(comp3->entities().size(), 1); |
371 | |
372 | // WHEN |
373 | entity2->removeComponent(comp: comp1); |
374 | entity2->removeComponent(comp: comp2); |
375 | entity2->removeComponent(comp: comp3); |
376 | |
377 | // THEN |
378 | QVERIFY(comp1->parent() == entity1.data()); |
379 | QVERIFY(comp2->parent() == entity1.data()); |
380 | QVERIFY(comp3->parent() == entity1.data()); |
381 | |
382 | QCOMPARE(entity1->components().size(), 0); |
383 | QCOMPARE(entity2->components().size(), 0); |
384 | |
385 | QCOMPARE(entity1->children().size(), 3); |
386 | QCOMPARE(entity2->children().size(), 0); |
387 | |
388 | QCOMPARE(comp1->entities().size(), 0); |
389 | QCOMPARE(comp2->entities().size(), 0); |
390 | QCOMPARE(comp3->entities().size(), 0); |
391 | } |
392 | |
393 | void tst_Entity::removeComponentsSeveralParentsSingleAggreation() |
394 | { |
395 | // GIVEN |
396 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
397 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
398 | |
399 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
400 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
401 | MyQComponent *comp3 = new MyQComponent(entity2.data()); |
402 | QCoreApplication::processEvents(); |
403 | |
404 | // WHEN |
405 | entity1->addComponent(comp: comp1); |
406 | entity1->addComponent(comp: comp2); |
407 | entity2->addComponent(comp: comp3); |
408 | |
409 | // THEN |
410 | QVERIFY(comp1->parent() == entity1.data()); |
411 | QVERIFY(comp2->parent() == entity1.data()); |
412 | QVERIFY(comp3->parent() == entity2.data()); |
413 | |
414 | QCOMPARE(entity1->components().size(), 2); |
415 | QCOMPARE(entity2->components().size(), 1); |
416 | |
417 | QCOMPARE(entity1->children().size(), 2); |
418 | QCOMPARE(entity2->children().size(), 1); |
419 | |
420 | QCOMPARE(comp1->entities().size(), 1); |
421 | QCOMPARE(comp2->entities().size(), 1); |
422 | QCOMPARE(comp3->entities().size(), 1); |
423 | |
424 | // WHEN |
425 | entity1->removeComponent(comp: comp1); |
426 | entity1->removeComponent(comp: comp2); |
427 | entity2->removeComponent(comp: comp3); |
428 | |
429 | // THEN |
430 | QVERIFY(comp1->parent() == entity1.data()); |
431 | QVERIFY(comp2->parent() == entity1.data()); |
432 | QVERIFY(comp3->parent() == entity2.data()); |
433 | |
434 | QCOMPARE(entity1->components().size(), 0); |
435 | QCOMPARE(entity2->components().size(), 0); |
436 | |
437 | QCOMPARE(entity1->children().size(), 2); |
438 | QCOMPARE(entity2->children().size(), 1); |
439 | |
440 | QCOMPARE(comp1->entities().size(), 0); |
441 | QCOMPARE(comp2->entities().size(), 0); |
442 | QCOMPARE(comp3->entities().size(), 0); |
443 | } |
444 | |
445 | void tst_Entity::removeComponentsSeveralParentsSeveralAggregations() |
446 | { |
447 | // GIVEN |
448 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
449 | QScopedPointer<Qt3DCore::QEntity> entity2(new QEntity()); |
450 | |
451 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
452 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
453 | MyQComponent *comp3 = new MyQComponent(entity2.data()); |
454 | QCoreApplication::processEvents(); |
455 | |
456 | // WHEN |
457 | entity1->addComponent(comp: comp1); |
458 | entity1->addComponent(comp: comp2); |
459 | entity1->addComponent(comp: comp3); |
460 | |
461 | entity2->addComponent(comp: comp1); |
462 | entity2->addComponent(comp: comp2); |
463 | entity2->addComponent(comp: comp3); |
464 | |
465 | // THEN |
466 | QVERIFY(comp1->parent() == entity1.data()); |
467 | QVERIFY(comp2->parent() == entity1.data()); |
468 | QVERIFY(comp3->parent() == entity2.data()); |
469 | |
470 | QCOMPARE(entity1->components().size(), 3); |
471 | QCOMPARE(entity2->components().size(), 3); |
472 | |
473 | QCOMPARE(entity1->children().size(), 2); |
474 | QCOMPARE(entity2->children().size(), 1); |
475 | |
476 | QCOMPARE(comp1->entities().size(), 2); |
477 | QCOMPARE(comp2->entities().size(), 2); |
478 | QCOMPARE(comp3->entities().size(), 2); |
479 | |
480 | // WHEN |
481 | entity1->removeComponent(comp: comp1); |
482 | entity1->removeComponent(comp: comp2); |
483 | entity1->removeComponent(comp: comp3); |
484 | |
485 | // THEN |
486 | QVERIFY(comp1->parent() == entity1.data()); |
487 | QVERIFY(comp2->parent() == entity1.data()); |
488 | QVERIFY(comp3->parent() == entity2.data()); |
489 | |
490 | QCOMPARE(entity1->components().size(), 0); |
491 | QCOMPARE(entity2->components().size(), 3); |
492 | |
493 | QCOMPARE(entity1->children().size(), 2); |
494 | QCOMPARE(entity2->children().size(), 1); |
495 | |
496 | QCOMPARE(comp1->entities().size(), 1); |
497 | QCOMPARE(comp2->entities().size(), 1); |
498 | QCOMPARE(comp3->entities().size(), 1); |
499 | |
500 | // WHEN |
501 | entity2->removeComponent(comp: comp1); |
502 | entity2->removeComponent(comp: comp2); |
503 | entity2->removeComponent(comp: comp3); |
504 | |
505 | // THEN |
506 | QVERIFY(comp1->parent() == entity1.data()); |
507 | QVERIFY(comp2->parent() == entity1.data()); |
508 | QVERIFY(comp3->parent() == entity2.data()); |
509 | |
510 | QCOMPARE(entity1->components().size(), 0); |
511 | QCOMPARE(entity2->components().size(), 0); |
512 | |
513 | QCOMPARE(entity1->children().size(), 2); |
514 | QCOMPARE(entity2->children().size(), 1); |
515 | |
516 | QCOMPARE(comp1->entities().size(), 0); |
517 | QCOMPARE(comp2->entities().size(), 0); |
518 | QCOMPARE(comp3->entities().size(), 0); |
519 | } |
520 | |
521 | void tst_Entity::retrieveSingleComponent() |
522 | { |
523 | // GIVEN |
524 | QScopedPointer<Qt3DCore::QEntity> entity1(new QEntity()); |
525 | |
526 | MyQComponent *comp1 = new MyQComponent(entity1.data()); |
527 | MyQComponent *comp2 = new MyQComponent(entity1.data()); |
528 | QCoreApplication::processEvents(); |
529 | entity1->addComponent(comp: comp1); |
530 | entity1->addComponent(comp: comp2); |
531 | |
532 | // WHEN |
533 | QVector<MyQComponent*> myQComponentsInEntity = entity1->componentsOfType<MyQComponent>(); |
534 | QVector<MyQ2Component*> myQ2ComponentsInEntity = entity1->componentsOfType<MyQ2Component>(); |
535 | |
536 | // THEN |
537 | QVERIFY(myQComponentsInEntity.size() == 2); |
538 | QVERIFY(myQComponentsInEntity[0] == comp1); |
539 | QVERIFY(myQComponentsInEntity[1] == comp2); |
540 | |
541 | QVERIFY(myQ2ComponentsInEntity.size() == 0); |
542 | } |
543 | |
544 | void tst_Entity::addSeveralTimesSameComponent() |
545 | { |
546 | // GIVEN |
547 | QScopedPointer<Qt3DCore::QEntity> entity(new QEntity()); |
548 | MyQComponent *comp = new MyQComponent(entity.data()); |
549 | QCoreApplication::processEvents(); |
550 | entity->addComponent(comp); |
551 | |
552 | // THEN |
553 | QVERIFY(comp->parent() == entity.data()); |
554 | QCOMPARE(entity->components().size(), 1); |
555 | QCOMPARE(entity->children().size(), 1); |
556 | QCOMPARE(comp->entities().size(), 1); |
557 | |
558 | // WHEN |
559 | entity->addComponent(comp); |
560 | |
561 | // THEN |
562 | QVERIFY(comp->parent() == entity.data()); |
563 | QCOMPARE(entity->components().size(), 1); |
564 | QCOMPARE(entity->children().size(), 1); |
565 | QCOMPARE(comp->entities().size(), 1); |
566 | } |
567 | |
568 | void tst_Entity::removeSeveralTimesSameComponent() |
569 | { |
570 | // GIVEN |
571 | QScopedPointer<Qt3DCore::QEntity> entity(new QEntity()); |
572 | MyQComponent *comp = new MyQComponent(entity.data()); |
573 | QCoreApplication::processEvents(); |
574 | entity->addComponent(comp); |
575 | entity->removeComponent(comp); |
576 | |
577 | // THEN |
578 | QVERIFY(comp->parent() == entity.data()); |
579 | QCOMPARE(entity->components().size(), 0); |
580 | QCOMPARE(entity->children().size(), 1); |
581 | QCOMPARE(comp->entities().size(), 0); |
582 | |
583 | // WHEN |
584 | entity->removeComponent(comp); |
585 | |
586 | // THEN |
587 | QVERIFY(comp->parent() == entity.data()); |
588 | QCOMPARE(entity->components().size(), 0); |
589 | QCOMPARE(entity->children().size(), 1); |
590 | QCOMPARE(comp->entities().size(), 0); |
591 | } |
592 | |
593 | void tst_Entity::checkCloning_data() |
594 | { |
595 | QTest::addColumn<Qt3DCore::QEntity *>(name: "entity" ); |
596 | QTest::addColumn<QVector<QNodeId>>(name: "childEntityIds" ); |
597 | QTest::addColumn<int>(name: "creationChangeCount" ); |
598 | |
599 | { |
600 | QTest::newRow(dataTag: "defaultConstructed" ) << new MyEntity() << QVector<QNodeId>() << 1; |
601 | } |
602 | |
603 | { |
604 | Qt3DCore::QEntity *entityWithComponents = new MyEntity(); |
605 | Qt3DCore::QComponent *component1 = new MyQComponent(); |
606 | Qt3DCore::QComponent *component2 = new MyQComponent(); |
607 | Qt3DCore::QComponent *component3 = new MyQComponent(); |
608 | entityWithComponents->addComponent(comp: component1); |
609 | entityWithComponents->addComponent(comp: component2); |
610 | entityWithComponents->addComponent(comp: component3); |
611 | QTest::newRow(dataTag: "entityWithComponents" ) << entityWithComponents << QVector<QNodeId>() << 4; |
612 | } |
613 | |
614 | { |
615 | Qt3DCore::QEntity *entityWithChildren = new MyEntity(); |
616 | Qt3DCore::QEntity *child1 = new MyEntity(entityWithChildren); |
617 | Qt3DCore::QEntity *child2 = new MyEntity(entityWithChildren); |
618 | QVector<QNodeId> childIds = {child1->id(), child2->id()}; |
619 | QTest::newRow(dataTag: "entityWithChildren" ) << entityWithChildren << childIds << 3; |
620 | } |
621 | |
622 | { |
623 | Qt3DCore::QEntity *entityWithNestedChildren = new MyEntity(); |
624 | Qt3DCore::QEntity *child = new MyEntity(entityWithNestedChildren); |
625 | Qt3DCore::QNode *dummy = new Qt3DCore::QNode(entityWithNestedChildren); |
626 | Qt3DCore::QEntity *grandChild = new MyEntity(entityWithNestedChildren); |
627 | QVector<QNodeId> childIds = {child->id(), grandChild->id()}; |
628 | QTest::newRow(dataTag: "entityWithNestedChildren" ) << entityWithNestedChildren << childIds << 4; |
629 | |
630 | Q_UNUSED(dummy); |
631 | } |
632 | } |
633 | |
634 | void tst_Entity::checkCloning() |
635 | { |
636 | // GIVEN |
637 | QFETCH(Qt3DCore::QEntity *, entity); |
638 | QFETCH(QVector<QNodeId>, childEntityIds); |
639 | QFETCH(int, creationChangeCount); |
640 | |
641 | // WHEN |
642 | Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(entity); |
643 | QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges(); |
644 | |
645 | // THEN |
646 | QCOMPARE(creationChanges.size(), creationChangeCount); |
647 | |
648 | const Qt3DCore::QNodeCreatedChangePtr<Qt3DCore::QEntityData> creationChangeData = |
649 | qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DCore::QEntityData>>(src: creationChanges.first()); |
650 | const Qt3DCore::QEntityData &cloneData = creationChangeData->data; |
651 | |
652 | // THEN |
653 | QCOMPARE(creationChangeData->subjectId(), entity->id()); |
654 | QCOMPARE(creationChangeData->isNodeEnabled(), entity->isEnabled()); |
655 | QCOMPARE(creationChangeData->metaObject(), entity->metaObject()); |
656 | QCOMPARE(creationChangeData->parentId(), entity->parentNode() ? entity->parentNode()->id() : Qt3DCore::QNodeId()); |
657 | QCOMPARE(cloneData.parentEntityId, entity->parentEntity() ? entity->parentEntity()->id() : Qt3DCore::QNodeId()); |
658 | QCOMPARE(cloneData.childEntityIds, childEntityIds); |
659 | QCOMPARE(cloneData.componentIdsAndTypes.size(), entity->components().size()); |
660 | |
661 | const QVector<Qt3DCore::QComponent *> &components = entity->components(); |
662 | for (int i = 0, m = components.size(); i < m; ++i) { |
663 | QCOMPARE(cloneData.componentIdsAndTypes.at(i).id, components.at(i)->id()); |
664 | QCOMPARE(cloneData.componentIdsAndTypes.at(i).type, components.at(i)->metaObject()); |
665 | } |
666 | } |
667 | |
668 | void tst_Entity::checkComponentBookkeeping() |
669 | { |
670 | // GIVEN |
671 | QScopedPointer<Qt3DCore::QEntity> rootEntity(new Qt3DCore::QEntity); |
672 | { |
673 | // WHEN |
674 | QScopedPointer<Qt3DCore::QComponent> comp(new MyQComponent(rootEntity.data())); |
675 | rootEntity->addComponent(comp: comp.data()); |
676 | |
677 | // THEN |
678 | QCOMPARE(comp->parent(), rootEntity.data()); |
679 | QCOMPARE(rootEntity->components().size(), 1); |
680 | } |
681 | // THEN (Should not crash and comp should be automatically removed) |
682 | QVERIFY(rootEntity->components().empty()); |
683 | |
684 | { |
685 | // WHEN |
686 | QScopedPointer<Qt3DCore::QEntity> someOtherEntity(new Qt3DCore::QEntity); |
687 | QScopedPointer<Qt3DCore::QComponent> comp(new MyQComponent(someOtherEntity.data())); |
688 | rootEntity->addComponent(comp: comp.data()); |
689 | |
690 | // THEN |
691 | QCOMPARE(comp->parent(), someOtherEntity.data()); |
692 | QCOMPARE(rootEntity->components().size(), 1); |
693 | |
694 | // WHEN |
695 | int sigCount = 0; |
696 | QObject *sigSender = comp.data(); |
697 | connect(sender: comp.data(), signal: &QComponent::removedFromEntity, slot: [&sigCount, sigSender](QEntity *) { |
698 | QComponent *c = qobject_cast<QComponent *>(object: sigSender); |
699 | if (sigSender && c) |
700 | sigCount++; // test the sender is still a QComponent when signal is emitted |
701 | }); |
702 | |
703 | comp.reset(); |
704 | rootEntity.reset(); |
705 | |
706 | // THEN (Should not crash when the comp is destroyed (tests for failed removal of destruction helper) |
707 | QCOMPARE(sigCount, 1); |
708 | } |
709 | } |
710 | |
711 | Qt3DCore::QNodeId parentEntityId(Qt3DCore::QEntity *entity) |
712 | { |
713 | Qt3DCore::QEntityPrivate *d = static_cast<Qt3DCore::QEntityPrivate*>(Qt3DCore::QNodePrivate::get(q: entity)); |
714 | return d->parentEntityId(); |
715 | } |
716 | |
717 | QTEST_MAIN(tst_Entity) |
718 | |
719 | #include "tst_qentity.moc" |
720 | |