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#include "../shared/particlestestsshared.h"
31#include <private/qquickparticlesystem_p.h>
32#include <private/qquickparticleemitter_p.h>
33#include <private/qquickimage_p.h>
34#include <private/qabstractanimation_p.h>
35
36#include "../../shared/util.h"
37
38class tst_qquickitemparticle : public QQmlDataTest
39{
40 Q_OBJECT
41public:
42 tst_qquickitemparticle() {}
43
44private slots:
45 void initTestCase();
46 void test_basic();
47 void test_deletion();
48 void test_noDeletion();
49 void test_takeGive();
50 void test_noCrashOnReset();
51 void test_noLeakWhenDeleted();
52};
53
54void tst_qquickitemparticle::initTestCase()
55{
56 QQmlDataTest::initTestCase();
57 QUnifiedTimer::instance()->setConsistentTiming(true);
58}
59
60void tst_qquickitemparticle::test_basic()
61{
62 QQuickView* view = createView(filename: testFileUrl(fileName: "basic.qml"), additionalWait: 600);
63 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
64 ensureAnimTime(requiredTime: 600, anim: system->m_animation);
65
66 QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
67 for (QQuickParticleData *d : qAsConst(t&: system->groupData[0]->data)) {
68 if (d->t == -1)
69 continue; //Particle data unused
70
71 QCOMPARE(d->x, 0.f);
72 QCOMPARE(d->y, 0.f);
73 QCOMPARE(d->vx, 0.f);
74 QCOMPARE(d->vy, 0.f);
75 QCOMPARE(d->ax, 0.f);
76 QCOMPARE(d->ay, 0.f);
77 QCOMPARE(d->lifeSpan, 0.5f);
78 QCOMPARE(d->size, 32.f);
79 QCOMPARE(d->endSize, 32.f);
80 QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0)));
81 if (d->t > ((qreal)system->timeInt/1000.0) - 0.05)//Delegates appear between frames, may miss the first couple
82 continue;
83 if (d->t < ((qreal)system->timeInt/1000.0) - 0.45)//Delegates cleared on death
84 continue;
85 QVERIFY(d->delegate);
86 QVERIFY(qobject_cast<QQuickImage*>(d->delegate));
87 }
88 delete view;
89}
90
91void tst_qquickitemparticle::test_deletion()
92{
93 QQuickView* view = createView(filename: testFileUrl(fileName: "managed.qml"), additionalWait: 500);
94 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
95 ensureAnimTime(requiredTime: 500, anim: system->m_animation);
96
97 QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 100, 10));
98 //qDebug() << system->property("acc").toInt(); Seems to be around +15 due to the one frame delay in cleanup compared to creation
99 QVERIFY(extremelyFuzzyCompare(system->property("acc").toInt(), 100, 20));
100 delete view;
101}
102
103void tst_qquickitemparticle::test_noDeletion()
104{
105 QQuickView* view = createView(filename: testFileUrl(fileName: "unmanaged.qml"), additionalWait: 500);
106 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
107 ensureAnimTime(requiredTime: 500, anim: system->m_animation);
108
109 QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 100, 10));
110 QVERIFY(extremelyFuzzyCompare(system->property("acc").toInt(), 100, 10));
111 delete view;
112}
113
114void tst_qquickitemparticle::test_takeGive()
115{
116 QQuickView* view = createView(filename: testFileUrl(fileName: "takeGive.qml"), additionalWait: 500);
117 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
118 QQuickParticleEmitter* emitter = view->rootObject()->findChild<QQuickParticleEmitter*>(aName: "emitter");
119 QMetaObject::invokeMethod(obj: view->rootObject(), member: "takeItems");
120 emitter->burst(num: 100);
121 ensureAnimTime(requiredTime: 1000, anim: system->m_animation);
122 QVERIFY(system->property("acc").toInt() == 100);
123 QMetaObject::invokeMethod(obj: view->rootObject(), member: "giveItems");
124 QTRY_VERIFY(system->property("acc").toInt() == 0);
125 QTRY_VERIFY(system->isEmpty() == true);
126 delete view;
127}
128
129void tst_qquickitemparticle::test_noCrashOnReset()
130{
131 QQuickView* view = createView(filename: testFileUrl(fileName: "basic.qml"), additionalWait: 600);
132 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
133
134 for (int i = 0; i < 10; ++i) {
135 ensureAnimTime(requiredTime: 16, anim: system->m_animation);
136 system->reset();
137 }
138
139 delete view;
140}
141
142void tst_qquickitemparticle::test_noLeakWhenDeleted()
143{
144 QQuickView* view = createView(filename: testFileUrl(fileName: "loader.qml"), additionalWait: 500);
145 QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>(aName: "system");
146 ensureAnimTime(requiredTime: 100, anim: system->m_animation);
147
148 auto particles = qAsConst(t&: system->groupData[0]->data);
149 QVERIFY(!particles.isEmpty());
150
151 QQuickParticleData* firstParticleData = particles.first();
152 QPointer<QQuickItem> firstParticleDelegate = firstParticleData->delegate;
153 QVERIFY(!firstParticleDelegate.isNull());
154
155 QQuickItem* loader = view->rootObject()->findChild<QQuickItem*>(aName: "loader");
156 loader->setProperty(name: "active", value: false); //This should destroy the ParticleSystem, ItemParticle and Emitter
157
158 QTest::qWait(ms: 1); //Process events to make sure the loader is properly unloaded
159 QVERIFY(firstParticleDelegate.isNull()); //Delegates should be deleted
160
161 delete view;
162}
163
164QTEST_MAIN(tst_qquickitemparticle);
165
166#include "tst_qquickitemparticle.moc"
167

source code of qtdeclarative/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp