1/****************************************************************************
2**
3** Copyright (C) 2017 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/QTest>
30#include <Qt3DAnimation/qchannelmapping.h>
31#include <Qt3DAnimation/private/qabstractchannelmapping_p.h>
32#include <Qt3DAnimation/private/qchannelmapping_p.h>
33#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
34#include <Qt3DCore/qentity.h>
35#include <Qt3DCore/qnodecreatedchange.h>
36#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
37#include <QObject>
38#include <QSignalSpy>
39#include <QQuaternion>
40#include <testpostmanarbiter.h>
41
42class tst_QTargetEntity : public Qt3DCore::QEntity
43{
44 Q_OBJECT
45 Q_PROPERTY(QQuaternion rotation MEMBER m_rotation NOTIFY rotationChanged)
46 Q_PROPERTY(QVector3D translation MEMBER m_translation NOTIFY translationChanged)
47 Q_PROPERTY(QVector3D scale MEMBER m_scale NOTIFY scaleChanged)
48 Q_PROPERTY(float floatProperty MEMBER m_floatProperty NOTIFY floatPropertyChanged)
49 Q_PROPERTY(QVector2D vec2Property MEMBER m_vec2Property NOTIFY vec2PropertyChanged)
50 Q_PROPERTY(QVector3D vec3Property MEMBER m_vec3Property NOTIFY vec3PropertyChanged)
51 Q_PROPERTY(QVector4D vec4Property MEMBER m_vec4Property NOTIFY vec4PropertyChanged)
52 Q_PROPERTY(QQuaternion quaternionProperty MEMBER m_quaternionProperty NOTIFY quaternionPropertyChanged)
53 Q_PROPERTY(QVariantList listProperty MEMBER m_listProperty NOTIFY listPropertyChanged)
54 Q_PROPERTY(QVector<float> vecProperty MEMBER m_vecProperty NOTIFY vecPropertyChanged)
55
56signals:
57 void rotationChanged();
58 void translationChanged();
59 void scaleChanged();
60 void floatPropertyChanged();
61 void vec2PropertyChanged();
62 void vec3PropertyChanged();
63 void vec4PropertyChanged();
64 void quaternionPropertyChanged();
65 void listPropertyChanged();
66 void vecPropertyChanged();
67
68private:
69 QQuaternion m_rotation;
70 QVector3D m_translation;
71 QVector3D m_scale;
72 float m_floatProperty;
73 QVector2D m_vec2Property;
74 QVector3D m_vec3Property;
75 QVector4D m_vec4Property;
76 QQuaternion m_quaternionProperty;
77 QVariantList m_listProperty;
78 QVector<float> m_vecProperty;
79};
80
81
82class tst_QChannelMapping : public QObject
83{
84 Q_OBJECT
85
86private Q_SLOTS:
87 void checkDefaultConstruction()
88 {
89 // GIVEN
90 Qt3DAnimation::QChannelMapping mapping;
91
92 // THEN
93 QCOMPARE(mapping.channelName(), QString());
94 QCOMPARE(mapping.target(), static_cast<Qt3DCore::QNode *>(nullptr));
95 QCOMPARE(mapping.property(), QString());
96
97 const Qt3DAnimation::QChannelMappingPrivate *d =
98 static_cast<const Qt3DAnimation::QChannelMappingPrivate *>(
99 Qt3DAnimation::QChannelMappingPrivate::get(q: &mapping));
100
101 QCOMPARE(d->m_type, static_cast<int>(QVariant::Invalid));
102 QCOMPARE(d->m_componentCount, 0);
103 }
104
105 void checkPropertyChanges()
106 {
107 // GIVEN
108 Qt3DAnimation::QChannelMapping mapping;
109
110 {
111 // WHEN
112 QSignalSpy spy(&mapping, SIGNAL(channelNameChanged(QString)));
113 const QString newValue(QStringLiteral("Rotation"));
114 mapping.setChannelName(newValue);
115
116 // THEN
117 QVERIFY(spy.isValid());
118 QCOMPARE(mapping.channelName(), newValue);
119 QCOMPARE(spy.count(), 1);
120
121 // WHEN
122 spy.clear();
123 mapping.setChannelName(newValue);
124
125 // THEN
126 QCOMPARE(mapping.channelName(), newValue);
127 QCOMPARE(spy.count(), 0);
128 }
129
130 {
131 // WHEN
132 QSignalSpy spy(&mapping, SIGNAL(targetChanged(Qt3DCore::QNode*)));
133 auto newValue = new Qt3DCore::QEntity();
134 mapping.setTarget(newValue);
135
136 // THEN
137 QVERIFY(spy.isValid());
138 QCOMPARE(mapping.target(), newValue);
139 QCOMPARE(newValue->parent(), &mapping);
140 QCOMPARE(spy.count(), 1);
141
142 // WHEN
143 spy.clear();
144 mapping.setTarget(newValue);
145
146 // THEN
147 QCOMPARE(mapping.target(), newValue);
148 QCOMPARE(spy.count(), 0);
149 }
150
151 {
152 // WHEN
153 QSignalSpy spy(&mapping, SIGNAL(propertyChanged(QString)));
154 const QString newValue(QStringLiteral("rotation"));
155 mapping.setProperty(newValue);
156
157 // THEN
158 QVERIFY(spy.isValid());
159 QCOMPARE(mapping.property(), newValue);
160 QCOMPARE(spy.count(), 1);
161
162 // WHEN
163 spy.clear();
164 mapping.setProperty(newValue);
165
166 // THEN
167 QCOMPARE(mapping.property(), newValue);
168 QCOMPARE(spy.count(), 0);
169 }
170 }
171
172 void checkCreationData()
173 {
174 // GIVEN
175 Qt3DAnimation::QChannelMapping mapping;
176 auto target = new tst_QTargetEntity;
177
178 mapping.setChannelName(QStringLiteral("Location"));
179 mapping.setTarget(target);
180 mapping.setProperty(QStringLiteral("translation"));
181
182 // WHEN
183 QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
184
185 {
186 Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
187 creationChanges = creationChangeGenerator.creationChanges();
188 }
189
190 // THEN
191 {
192 QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for target
193
194 const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QChannelMappingData>>(src: creationChanges.first());
195 const Qt3DAnimation::QChannelMappingData data = creationChangeData->data;
196
197 QCOMPARE(mapping.id(), creationChangeData->subjectId());
198 QCOMPARE(mapping.isEnabled(), true);
199 QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
200 QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
201 QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::ChannelMapping);
202 QCOMPARE(mapping.channelName(), data.channelName);
203 QCOMPARE(mapping.target()->id(), data.targetId);
204 QVERIFY(qstrcmp(mapping.property().toLatin1().constData(), data.propertyName) == 0);
205 QCOMPARE(data.type, static_cast<int>(QVariant::Vector3D));
206 QCOMPARE(data.componentCount, 3);
207 }
208
209 // WHEN
210 mapping.setEnabled(false);
211
212 {
213 Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
214 creationChanges = creationChangeGenerator.creationChanges();
215 }
216
217 // THEN
218 {
219 QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for target
220
221 const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QChannelMappingData>>(src: creationChanges.first());
222 const Qt3DAnimation::QChannelMappingData data = creationChangeData->data;
223
224 QCOMPARE(mapping.id(), creationChangeData->subjectId());
225 QCOMPARE(mapping.isEnabled(), false);
226 QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
227 QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
228 QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::ChannelMapping);
229 QCOMPARE(mapping.channelName(), data.channelName);
230 QCOMPARE(mapping.target()->id(), data.targetId);
231 QVERIFY(qstrcmp(mapping.property().toLatin1().constData(), data.propertyName) == 0);
232 QCOMPARE(data.type, static_cast<int>(QVariant::Vector3D));
233 QCOMPARE(data.componentCount, 3);
234 }
235 }
236
237 void checkPropertyUpdateChanges()
238 {
239 // GIVEN
240 TestArbiter arbiter;
241 Qt3DAnimation::QChannelMapping mapping;
242 QScopedPointer<Qt3DCore::QEntity> target(new tst_QTargetEntity());
243 arbiter.setArbiterOnNode(&mapping);
244
245 {
246 // WHEN
247 mapping.setChannelName(QStringLiteral("Scale"));
248
249 // THEN
250 QCOMPARE(arbiter.dirtyNodes.size(), 1);
251 QCOMPARE(arbiter.dirtyNodes.front(), &mapping);
252
253 arbiter.dirtyNodes.clear();
254
255 // WHEN
256 mapping.setChannelName(QStringLiteral("Scale"));
257
258 // THEN
259 QCOMPARE(arbiter.dirtyNodes.size(), 0);
260 }
261
262 {
263 // WHEN
264 mapping.setTarget(target.data());
265
266 // THEN
267 QCOMPARE(arbiter.dirtyNodes.size(), 1);
268 QCOMPARE(arbiter.dirtyNodes.front(), &mapping);
269
270 arbiter.dirtyNodes.clear();
271
272 // WHEN
273 mapping.setTarget(target.data());
274
275 // THEN
276 QCOMPARE(arbiter.dirtyNodes.size(), 0);
277 }
278
279 {
280 // WHEN
281 target->setProperty(name: "scale", value: QVector3D(1.0f, 0.0f, 0.0f));
282 mapping.setProperty(QStringLiteral("scale"));
283 QCoreApplication::processEvents();
284
285 // THEN
286 QCOMPARE(arbiter.events.size(), 0);
287 QCOMPARE(arbiter.dirtyNodes.size(), 1);
288 QCOMPARE(arbiter.dirtyNodes.front(), &mapping);
289
290 arbiter.dirtyNodes.clear();
291
292 // WHEN
293 mapping.setProperty(QStringLiteral("scale"));
294 QCoreApplication::processEvents();
295
296 // THEN
297 QCOMPARE(arbiter.events.size(), 0);
298 QCOMPARE(arbiter.dirtyNodes.size(), 0);
299 }
300 }
301
302 void checkPropertyUpdateNameTypeAndComponentCount_data()
303 {
304 QTest::addColumn<QByteArray>(name: "propertyName");
305 QTest::addColumn<QVariant>(name: "value");
306 QTest::addColumn<int>(name: "expectedType");
307 QTest::addColumn<int>(name: "expectedComponentCount");
308
309 QTest::newRow(dataTag: "float") << QByteArrayLiteral("floatProperty") << QVariant(1.0f) << static_cast<int>(QMetaType::Float) << 1;
310 QTest::newRow(dataTag: "vec2") << QByteArrayLiteral("vec2Property") << QVariant(QVector2D(1.0f, 1.0f)) << static_cast<int>(QVariant::Vector2D) << 2;
311 QTest::newRow(dataTag: "vec3") << QByteArrayLiteral("vec3Property") << QVariant(QVector3D(1.0f, 1.0f, 1.0f)) << static_cast<int>(QVariant::Vector3D) << 3;
312 QTest::newRow(dataTag: "vec4") << QByteArrayLiteral("vec4Property") << QVariant(QVector4D(1.0f, 1.0f, 1.0f, 1.0f)) << static_cast<int>(QVariant::Vector4D) << 4;
313 QTest::newRow(dataTag: "quaternion") << QByteArrayLiteral("quaternionProperty") << QVariant(QQuaternion(1.0f, 1.0f, 1.0f, 1.0f)) << static_cast<int>(QVariant::Quaternion) << 4;
314
315 QVariantList list = QVariantList() << QVariant(1.0f) << QVariant(1.0) << QVariant(1.0f) << QVariant(1.0f) << QVariant(1.0f);
316 QTest::newRow(dataTag: "variantlist") << QByteArrayLiteral("listProperty") << QVariant::fromValue(value: list) << static_cast<int>(QVariant::List) << 5;
317
318 QVector<float> vec(8);
319 QTest::newRow(dataTag: "vector") << QByteArrayLiteral("vecProperty") << QVariant::fromValue(value: vec) << qMetaTypeId<decltype(vec)>() << 8;
320 }
321
322 void checkPropertyUpdateNameTypeAndComponentCount()
323 {
324 // GIVEN
325 QFETCH(QByteArray, propertyName);
326 QFETCH(QVariant, value);
327 QFETCH(int, expectedType);
328 QFETCH(int, expectedComponentCount);
329
330 Q_UNUSED(expectedType)
331 Q_UNUSED(expectedComponentCount)
332
333 TestArbiter arbiter;
334 Qt3DAnimation::QChannelMapping mapping;
335 QScopedPointer<Qt3DCore::QEntity> target(new tst_QTargetEntity());
336 mapping.setTarget(target.data());
337 arbiter.setArbiterOnNode(&mapping);
338
339 {
340 // WHEN
341 target->setProperty(name: propertyName.constData(), value);
342
343 // THEN
344 QCOMPARE(arbiter.dirtyNodes.size(), 1);
345 QCOMPARE(arbiter.dirtyNodes.front(), target.data());
346
347 arbiter.dirtyNodes.clear();
348
349 // THEN
350 mapping.setProperty(QString::fromLatin1(str: propertyName));
351
352 // THEN
353 QCOMPARE(arbiter.dirtyNodes.size(), 1);
354 }
355 }
356
357};
358
359QTEST_MAIN(tst_QChannelMapping)
360
361#include "tst_qchannelmapping.moc"
362

source code of qt3d/tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp