/**************************************************************************** ** ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include using namespace Qt3DCore; class tst_Entity : public QObject { Q_OBJECT public: tst_Entity() : QObject() { qRegisterMetaType(); } ~tst_Entity() {} private slots: void constructionDestruction(); void addComponentSingleParentSingleAggregation(); void addComponentSingleParentSeveralAggregations(); void addComponentsSeveralParentsSingleAggregations(); void addComponentsSeveralParentsSeveralAggregations(); void retrieveSingleComponent(); void removeComponentSingleParentSingleAggregation(); void removeComponentSingleParentSeveralAggregations(); void removeComponentsSeveralParentsSingleAggreation(); void removeComponentsSeveralParentsSeveralAggregations(); void addSeveralTimesSameComponent(); void removeSeveralTimesSameComponent(); void checkComponentBookkeeping(); }; class MyQComponent : public Qt3DCore::QComponent { Q_OBJECT public: explicit MyQComponent(Qt3DCore::QNode *parent = nullptr) : QComponent(parent) {} }; class MyQ2Component : public Qt3DCore::QComponent { Q_OBJECT public: explicit MyQ2Component(Qt3DCore::QNode *parent = 0) : QComponent(parent) {} }; class MyEntity : public Qt3DCore::QEntity { public: explicit MyEntity(Qt3DCore::QNode *parent = nullptr) : QEntity(parent) {} }; void tst_Entity::constructionDestruction() { // GIVEN QEntity *entity = nullptr; // WHEN entity = new QEntity; // THEN QVERIFY(entity != nullptr); delete entity; // GIVEN QScopedPointer entity2(new QEntity); // WHEN entity2.reset(nullptr); // THEN // this should not crash } void tst_Entity::addComponentSingleParentSingleAggregation() { // GIVEN QScopedPointer entity(new QEntity()); MyQComponent *comp = new MyQComponent(entity.data()); QCoreApplication::processEvents(); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 0); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 0); // WHEN entity->addComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 1); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 1); } void tst_Entity::addComponentSingleParentSeveralAggregations() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity1.data()); QCoreApplication::processEvents(); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity1.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 3); QCOMPARE(entity2->children().size(), 0); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); // WHEN entity1->addComponent(comp1); entity1->addComponent(comp2); entity1->addComponent(comp3); entity2->addComponent(comp1); entity2->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity1.data()); QCOMPARE(entity1->components().size(), 3); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 3); QCOMPARE(entity2->children().size(), 0); QCOMPARE(comp1->entities().size(), 2); QCOMPARE(comp2->entities().size(), 2); QCOMPARE(comp3->entities().size(), 2); } void tst_Entity::addComponentsSeveralParentsSingleAggregations() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity2.data()); QCoreApplication::processEvents(); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); // WHEN entity1->addComponent(comp1); entity1->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 2); QCOMPARE(entity2->components().size(), 1); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 1); QCOMPARE(comp2->entities().size(), 1); QCOMPARE(comp3->entities().size(), 1); } void tst_Entity::addComponentsSeveralParentsSeveralAggregations() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity2.data()); QCoreApplication::processEvents(); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); // WHEN entity1->addComponent(comp1); entity1->addComponent(comp2); entity1->addComponent(comp3); entity2->addComponent(comp1); entity2->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 3); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 2); QCOMPARE(comp2->entities().size(), 2); QCOMPARE(comp3->entities().size(), 2); } void tst_Entity::removeComponentSingleParentSingleAggregation() { // GIVEN QScopedPointer entity(new QEntity()); MyQComponent *comp = new MyQComponent(entity.data()); QCoreApplication::processEvents(); entity->addComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 1); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 1); // WHEN entity->removeComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 0); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 0); } void tst_Entity::removeComponentSingleParentSeveralAggregations() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity1.data()); QCoreApplication::processEvents(); entity1->addComponent(comp1); entity1->addComponent(comp2); entity1->addComponent(comp3); entity2->addComponent(comp1); entity2->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity1.data()); QCOMPARE(entity1->components().size(), 3); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 3); QCOMPARE(entity2->children().size(), 0); QCOMPARE(comp1->entities().size(), 2); QCOMPARE(comp2->entities().size(), 2); QCOMPARE(comp3->entities().size(), 2); // WHEN entity1->removeComponent(comp1); entity1->removeComponent(comp2); entity1->removeComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity1.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 3); QCOMPARE(entity2->children().size(), 0); QCOMPARE(comp1->entities().size(), 1); QCOMPARE(comp2->entities().size(), 1); QCOMPARE(comp3->entities().size(), 1); // WHEN entity2->removeComponent(comp1); entity2->removeComponent(comp2); entity2->removeComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity1.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 3); QCOMPARE(entity2->children().size(), 0); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); } void tst_Entity::removeComponentsSeveralParentsSingleAggreation() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity2.data()); QCoreApplication::processEvents(); // WHEN entity1->addComponent(comp1); entity1->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 2); QCOMPARE(entity2->components().size(), 1); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 1); QCOMPARE(comp2->entities().size(), 1); QCOMPARE(comp3->entities().size(), 1); // WHEN entity1->removeComponent(comp1); entity1->removeComponent(comp2); entity2->removeComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); } void tst_Entity::removeComponentsSeveralParentsSeveralAggregations() { // GIVEN QScopedPointer entity1(new QEntity()); QScopedPointer entity2(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); MyQComponent *comp3 = new MyQComponent(entity2.data()); QCoreApplication::processEvents(); // WHEN entity1->addComponent(comp1); entity1->addComponent(comp2); entity1->addComponent(comp3); entity2->addComponent(comp1); entity2->addComponent(comp2); entity2->addComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 3); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 2); QCOMPARE(comp2->entities().size(), 2); QCOMPARE(comp3->entities().size(), 2); // WHEN entity1->removeComponent(comp1); entity1->removeComponent(comp2); entity1->removeComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 3); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 1); QCOMPARE(comp2->entities().size(), 1); QCOMPARE(comp3->entities().size(), 1); // WHEN entity2->removeComponent(comp1); entity2->removeComponent(comp2); entity2->removeComponent(comp3); // THEN QVERIFY(comp1->parent() == entity1.data()); QVERIFY(comp2->parent() == entity1.data()); QVERIFY(comp3->parent() == entity2.data()); QCOMPARE(entity1->components().size(), 0); QCOMPARE(entity2->components().size(), 0); QCOMPARE(entity1->children().size(), 2); QCOMPARE(entity2->children().size(), 1); QCOMPARE(comp1->entities().size(), 0); QCOMPARE(comp2->entities().size(), 0); QCOMPARE(comp3->entities().size(), 0); } void tst_Entity::retrieveSingleComponent() { // GIVEN QScopedPointer entity1(new QEntity()); MyQComponent *comp1 = new MyQComponent(entity1.data()); MyQComponent *comp2 = new MyQComponent(entity1.data()); QCoreApplication::processEvents(); entity1->addComponent(comp1); entity1->addComponent(comp2); // WHEN const QList myQComponentsInEntity = entity1->componentsOfType(); const QList myQ2ComponentsInEntity = entity1->componentsOfType(); // THEN QVERIFY(myQComponentsInEntity.size() == 2); QVERIFY(myQComponentsInEntity[0] == comp1); QVERIFY(myQComponentsInEntity[1] == comp2); QVERIFY(myQ2ComponentsInEntity.size() == 0); } void tst_Entity::addSeveralTimesSameComponent() { // GIVEN QScopedPointer entity(new QEntity()); MyQComponent *comp = new MyQComponent(entity.data()); QCoreApplication::processEvents(); entity->addComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 1); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 1); // WHEN entity->addComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 1); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 1); } void tst_Entity::removeSeveralTimesSameComponent() { // GIVEN QScopedPointer entity(new QEntity()); MyQComponent *comp = new MyQComponent(entity.data()); QCoreApplication::processEvents(); entity->addComponent(comp); entity->removeComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 0); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 0); // WHEN entity->removeComponent(comp); // THEN QVERIFY(comp->parent() == entity.data()); QCOMPARE(entity->components().size(), 0); QCOMPARE(entity->children().size(), 1); QCOMPARE(comp->entities().size(), 0); } void tst_Entity::checkComponentBookkeeping() { // GIVEN QScopedPointer rootEntity(new Qt3DCore::QEntity); { // WHEN QScopedPointer comp(new MyQComponent(rootEntity.data())); rootEntity->addComponent(comp.data()); // THEN QCOMPARE(comp->parent(), rootEntity.data()); QCOMPARE(rootEntity->components().size(), 1); } // THEN (Should not crash and comp should be automatically removed) QVERIFY(rootEntity->components().empty()); { // WHEN QScopedPointer someOtherEntity(new Qt3DCore::QEntity); QScopedPointer comp(new MyQComponent(someOtherEntity.data())); rootEntity->addComponent(comp.data()); // THEN QCOMPARE(comp->parent(), someOtherEntity.data()); QCOMPARE(rootEntity->components().size(), 1); // WHEN int sigCount = 0; QObject *sigSender = comp.data(); connect(comp.data(), &QComponent::removedFromEntity, [&sigCount, sigSender](QEntity *) { QComponent *c = qobject_cast(sigSender); if (sigSender && c) sigCount++; // test the sender is still a QComponent when signal is emitted }); comp.reset(); rootEntity.reset(); // THEN (Should not crash when the comp is destroyed (tests for failed removal of destruction helper) QCOMPARE(sigCount, 1); } } Qt3DCore::QNodeId parentEntityId(Qt3DCore::QEntity *entity) { Qt3DCore::QEntityPrivate *d = static_cast(Qt3DCore::QNodePrivate::get(entity)); return d->parentEntityId(); } QTEST_MAIN(tst_Entity) #include "tst_qentity.moc"