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>
31QT_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
40using namespace Qt3DCore;
41
42class tst_Entity : public QObject
43{
44 Q_OBJECT
45public:
46 tst_Entity() : QObject()
47 {
48 qRegisterMetaType<Qt3DCore::QNode*>();
49 }
50 ~tst_Entity() {}
51
52private 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
76class MyQComponent : public Qt3DCore::QComponent
77{
78 Q_OBJECT
79public:
80 explicit MyQComponent(Qt3DCore::QNode *parent = nullptr)
81 : QComponent(parent)
82 {}
83};
84
85class MyQ2Component : public Qt3DCore::QComponent
86{
87 Q_OBJECT
88public:
89 explicit MyQ2Component(Qt3DCore::QNode *parent = 0)
90 : QComponent(parent)
91 {}
92};
93
94class MyEntity : public Qt3DCore::QEntity
95{
96public:
97 explicit MyEntity(Qt3DCore::QNode *parent = nullptr)
98 : QEntity(parent)
99 {}
100};
101
102void 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
121void 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
144void 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
195void 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
243void 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
294void 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
318void 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
393void 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
445void 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
521void 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
544void 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
568void 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
593void 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
634void 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
668void 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
711Qt3DCore::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
717QTEST_MAIN(tst_Entity)
718
719#include "tst_qentity.moc"
720

source code of qt3d/tests/auto/core/qentity/tst_qentity.cpp