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

source code of qtbase/tests/auto/corelib/animation/qpauseanimation/tst_qpauseanimation.cpp