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
31#include <QtQml/private/qpauseanimationjob_p.h>
32#include <QtQml/private/qsequentialanimationgroupjob_p.h>
33#include <QtQml/private/qparallelanimationgroupjob_p.h>
34
35#ifdef Q_OS_WIN
36static const char winTimerError[] = "On windows, consistent timing is not working properly due to bad timer resolution";
37#endif
38
39class TestablePauseAnimation : public QPauseAnimationJob
40{
41public:
42 TestablePauseAnimation() { }
43
44 TestablePauseAnimation(int duration)
45 : QPauseAnimationJob(duration), m_updateCurrentTimeCount(0)
46 {
47 }
48
49 int m_updateCurrentTimeCount = 0;
50protected:
51 void updateCurrentTime(int currentTime)
52 {
53 QPauseAnimationJob::updateCurrentTime(currentTime);
54 ++m_updateCurrentTimeCount;
55 }
56};
57
58class TestableGenericAnimation : public QAbstractAnimationJob
59{
60public:
61 TestableGenericAnimation(int duration = 250) : m_duration(duration) {}
62 int duration() const { return m_duration; }
63
64private:
65 int m_duration;
66};
67
68class EnableConsistentTiming
69{
70public:
71 EnableConsistentTiming()
72 {
73 QUnifiedTimer *timer = QUnifiedTimer::instance();
74 timer->setConsistentTiming(true);
75 }
76 ~EnableConsistentTiming()
77 {
78 QUnifiedTimer *timer = QUnifiedTimer::instance();
79 timer->setConsistentTiming(false);
80 }
81};
82
83class tst_QPauseAnimationJob : public QObject
84{
85 Q_OBJECT
86public Q_SLOTS:
87 void initTestCase();
88
89private slots:
90 void changeDirectionWhileRunning();
91 void noTimerUpdates_data();
92 void noTimerUpdates();
93 void multiplePauseAnimations();
94 void pauseAndPropertyAnimations();
95 void pauseResume();
96 void sequentialPauseGroup();
97 void sequentialGroupWithPause();
98 void multipleSequentialGroups();
99 void zeroDuration();
100};
101
102void tst_QPauseAnimationJob::initTestCase()
103{
104// qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State");
105}
106
107void tst_QPauseAnimationJob::changeDirectionWhileRunning()
108{
109 EnableConsistentTiming enabled;
110
111 TestablePauseAnimation animation;
112 animation.setDuration(400);
113 animation.start();
114 QTest::qWait(ms: 100);
115 QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
116 animation.setDirection(QAbstractAnimationJob::Backward);
117 QTest::qWait(ms: animation.totalDuration() + 50);
118 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
119}
120
121void tst_QPauseAnimationJob::noTimerUpdates_data()
122{
123 QTest::addColumn<int>(name: "duration");
124 QTest::addColumn<int>(name: "loopCount");
125
126 QTest::newRow(dataTag: "0") << 200 << 1;
127 QTest::newRow(dataTag: "1") << 160 << 1;
128 QTest::newRow(dataTag: "2") << 160 << 2;
129 QTest::newRow(dataTag: "3") << 200 << 3;
130}
131
132void tst_QPauseAnimationJob::noTimerUpdates()
133{
134 EnableConsistentTiming enabled;
135
136 QFETCH(int, duration);
137 QFETCH(int, loopCount);
138
139 TestablePauseAnimation animation;
140 animation.setDuration(duration);
141 animation.setLoopCount(loopCount);
142 animation.start();
143 QTest::qWait(ms: animation.totalDuration() + 100);
144
145#ifdef Q_OS_WIN
146 if (animation.state() != QAbstractAnimationJob::Stopped)
147 QEXPECT_FAIL("", winTimerError, Abort);
148#endif
149
150 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
151 const int expectedLoopCount = 1 + loopCount;
152
153#ifdef Q_OS_WIN
154 if (animation.m_updateCurrentTimeCount != expectedLoopCount)
155 QEXPECT_FAIL("", winTimerError, Abort);
156#endif
157 QCOMPARE(animation.m_updateCurrentTimeCount, expectedLoopCount);
158}
159
160void tst_QPauseAnimationJob::multiplePauseAnimations()
161{
162 EnableConsistentTiming enabled;
163
164 TestablePauseAnimation animation;
165 animation.setDuration(200);
166
167 TestablePauseAnimation animation2;
168 animation2.setDuration(800);
169
170 animation.start();
171 animation2.start();
172 QTest::qWait(ms: animation.totalDuration() + 100);
173
174#ifdef Q_OS_WIN
175 if (animation.state() != QAbstractAnimationJob::Stopped)
176 QEXPECT_FAIL("", winTimerError, Abort);
177#endif
178 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
179
180#ifdef Q_OS_WIN
181 if (animation2.state() != QAbstractAnimationJob::Running)
182 QEXPECT_FAIL("", winTimerError, Abort);
183#endif
184 QCOMPARE(animation2.state(), QAbstractAnimationJob::Running);
185
186#ifdef Q_OS_WIN
187 if (animation.m_updateCurrentTimeCount != 2)
188 QEXPECT_FAIL("", winTimerError, Abort);
189#endif
190 QCOMPARE(animation.m_updateCurrentTimeCount, 2);
191
192#ifdef Q_OS_WIN
193 if (animation2.m_updateCurrentTimeCount != 2)
194 QEXPECT_FAIL("", winTimerError, Abort);
195#endif
196 QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
197
198 QTRY_COMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
199 QVERIFY(animation2.m_updateCurrentTimeCount >= 3);
200}
201
202void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
203{
204 EnableConsistentTiming enabled;
205
206 TestablePauseAnimation pause;
207 pause.setDuration(200);
208
209 TestableGenericAnimation animation;
210
211 pause.start();
212
213 QTest::qWait(ms: 100);
214 animation.start();
215
216 QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
217
218 QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Running);
219 QCOMPARE(pause.state(), QAbstractAnimationJob::Running);
220 QVERIFY2(pause.m_updateCurrentTimeCount >= 2,
221 QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
222
223 QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Stopped);
224 QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
225 QVERIFY2(pause.m_updateCurrentTimeCount > 3,
226 QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
227}
228
229void tst_QPauseAnimationJob::pauseResume()
230{
231 TestablePauseAnimation animation;
232 animation.setDuration(400);
233 animation.start();
234 QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
235 QTest::qWait(ms: 200);
236 animation.pause();
237 QCOMPARE(animation.state(), QAbstractAnimationJob::Paused);
238 animation.start();
239 QTest::qWait(ms: 300);
240 QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Stopped);
241 QVERIFY2(animation.m_updateCurrentTimeCount >= 3,
242 QByteArrayLiteral("animation.m_updateCurrentTimeCount=") + QByteArray::number(animation.m_updateCurrentTimeCount));
243}
244
245void tst_QPauseAnimationJob::sequentialPauseGroup()
246{
247 QSequentialAnimationGroupJob group;
248
249 TestablePauseAnimation animation1(200);
250 group.appendAnimation(animation: &animation1);
251 TestablePauseAnimation animation2(200);
252 group.appendAnimation(animation: &animation2);
253 TestablePauseAnimation animation3(200);
254 group.appendAnimation(animation: &animation3);
255
256 group.start();
257 QCOMPARE(animation1.m_updateCurrentTimeCount, 1);
258 QCOMPARE(animation2.m_updateCurrentTimeCount, 0);
259 QCOMPARE(animation3.m_updateCurrentTimeCount, 0);
260
261 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
262 QCOMPARE(animation1.state(), QAbstractAnimationJob::Running);
263 QCOMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
264 QCOMPARE(animation3.state(), QAbstractAnimationJob::Stopped);
265
266 group.setCurrentTime(250);
267 QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
268 QCOMPARE(animation2.m_updateCurrentTimeCount, 1);
269 QCOMPARE(animation3.m_updateCurrentTimeCount, 0);
270
271 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
272 QCOMPARE(animation1.state(), QAbstractAnimationJob::Stopped);
273 QCOMPARE((QAbstractAnimationJob*)&animation2, group.currentAnimation());
274 QCOMPARE(animation2.state(), QAbstractAnimationJob::Running);
275 QCOMPARE(animation3.state(), QAbstractAnimationJob::Stopped);
276
277 group.setCurrentTime(500);
278 QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
279 QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
280 QCOMPARE(animation3.m_updateCurrentTimeCount, 1);
281
282 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
283 QCOMPARE(animation1.state(), QAbstractAnimationJob::Stopped);
284 QCOMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
285 QCOMPARE((QAbstractAnimationJob*)&animation3, group.currentAnimation());
286 QCOMPARE(animation3.state(), QAbstractAnimationJob::Running);
287
288 group.setCurrentTime(750);
289
290 QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
291 QCOMPARE(animation1.state(), QAbstractAnimationJob::Stopped);
292 QCOMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
293 QCOMPARE(animation3.state(), QAbstractAnimationJob::Stopped);
294
295 QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
296 QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
297 QCOMPARE(animation3.m_updateCurrentTimeCount, 2);
298}
299
300void tst_QPauseAnimationJob::sequentialGroupWithPause()
301{
302 QSequentialAnimationGroupJob group;
303
304 TestableGenericAnimation animation;
305 group.appendAnimation(animation: &animation);
306
307 TestablePauseAnimation pause;
308 pause.setDuration(250);
309 group.appendAnimation(animation: &pause);
310
311 group.start();
312
313 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
314 QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
315 QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
316
317 group.setCurrentTime(300);
318
319 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
320 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
321 QCOMPARE((QAbstractAnimationJob*)&pause, group.currentAnimation());
322 QCOMPARE(pause.state(), QAbstractAnimationJob::Running);
323
324 group.setCurrentTime(600);
325
326 QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
327 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
328 QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
329
330 QCOMPARE(pause.m_updateCurrentTimeCount, 2);
331}
332
333void tst_QPauseAnimationJob::multipleSequentialGroups()
334{
335 EnableConsistentTiming enabled;
336
337 QParallelAnimationGroupJob group;
338 group.setLoopCount(2);
339
340 QSequentialAnimationGroupJob subgroup1;
341 group.appendAnimation(animation: &subgroup1);
342
343 TestableGenericAnimation animation(300);
344 subgroup1.appendAnimation(animation: &animation);
345
346 TestablePauseAnimation pause(200);
347 subgroup1.appendAnimation(animation: &pause);
348
349 QSequentialAnimationGroupJob subgroup2;
350 group.appendAnimation(animation: &subgroup2);
351
352 TestableGenericAnimation animation2(200);
353 subgroup2.appendAnimation(animation: &animation2);
354
355 TestablePauseAnimation pause2(250);
356 subgroup2.appendAnimation(animation: &pause2);
357
358 QSequentialAnimationGroupJob subgroup3;
359 group.appendAnimation(animation: &subgroup3);
360
361 TestablePauseAnimation pause3(400);
362 subgroup3.appendAnimation(animation: &pause3);
363
364 TestableGenericAnimation animation3(200);
365 subgroup3.appendAnimation(animation: &animation3);
366
367 QSequentialAnimationGroupJob subgroup4;
368 group.appendAnimation(animation: &subgroup4);
369
370 TestablePauseAnimation pause4(310);
371 subgroup4.appendAnimation(animation: &pause4);
372
373 TestablePauseAnimation pause5(60);
374 subgroup4.appendAnimation(animation: &pause5);
375
376 group.start();
377
378 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
379 QCOMPARE(subgroup1.state(), QAbstractAnimationJob::Running);
380 QCOMPARE(subgroup2.state(), QAbstractAnimationJob::Running);
381 QCOMPARE(subgroup3.state(), QAbstractAnimationJob::Running);
382 QCOMPARE(subgroup4.state(), QAbstractAnimationJob::Running);
383
384 // This is a pretty long animation so it tends to get rather out of sync
385 // when using the consistent timer, so run for an extra half second for good
386 // measure...
387 QTest::qWait(ms: group.totalDuration() + 500);
388
389#ifdef Q_OS_WIN
390 if (group.state() != QAbstractAnimationJob::Stopped)
391 QEXPECT_FAIL("", winTimerError, Abort);
392 QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
393#else
394 QTRY_COMPARE(group.state(), QAbstractAnimationJob::Stopped);
395#endif
396
397#ifdef Q_OS_WIN
398 if (subgroup1.state() != QAbstractAnimationJob::Stopped)
399 QEXPECT_FAIL("", winTimerError, Abort);
400#endif
401 QCOMPARE(subgroup1.state(), QAbstractAnimationJob::Stopped);
402
403#ifdef Q_OS_WIN
404 if (subgroup2.state() != QAbstractAnimationJob::Stopped)
405 QEXPECT_FAIL("", winTimerError, Abort);
406#endif
407 QCOMPARE(subgroup2.state(), QAbstractAnimationJob::Stopped);
408
409#ifdef Q_OS_WIN
410 if (subgroup3.state() != QAbstractAnimationJob::Stopped)
411 QEXPECT_FAIL("", winTimerError, Abort);
412#endif
413 QCOMPARE(subgroup3.state(), QAbstractAnimationJob::Stopped);
414
415#ifdef Q_OS_WIN
416 if (subgroup4.state() != QAbstractAnimationJob::Stopped)
417 QEXPECT_FAIL("", winTimerError, Abort);
418#endif
419 QCOMPARE(subgroup4.state(), QAbstractAnimationJob::Stopped);
420
421#ifdef Q_OS_WIN
422 if (pause5.m_updateCurrentTimeCount != 4)
423 QEXPECT_FAIL("", winTimerError, Abort);
424#endif
425 QCOMPARE(pause5.m_updateCurrentTimeCount, 4);
426}
427
428void tst_QPauseAnimationJob::zeroDuration()
429{
430 TestablePauseAnimation animation;
431 animation.setDuration(0);
432 animation.start();
433 QTest::qWait(ms: animation.totalDuration() + 100);
434 QCOMPARE(animation.state(), QAbstractAnimationJob::Stopped);
435 QCOMPARE(animation.m_updateCurrentTimeCount, 1);
436}
437
438QTEST_MAIN(tst_QPauseAnimationJob)
439#include "tst_qpauseanimationjob.moc"
440

source code of qtdeclarative/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp