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 |
42 | static 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 | |
55 | class TestablePauseAnimation : public QPauseAnimation |
56 | { |
57 | Q_OBJECT |
58 | public: |
59 | TestablePauseAnimation(QObject *parent = 0) |
60 | : QPauseAnimation(parent), |
61 | m_updateCurrentTimeCount(0) |
62 | { |
63 | } |
64 | |
65 | int m_updateCurrentTimeCount; |
66 | protected: |
67 | void updateCurrentTime(int currentTime) |
68 | { |
69 | QPauseAnimation::updateCurrentTime(currentTime); |
70 | ++m_updateCurrentTimeCount; |
71 | } |
72 | }; |
73 | |
74 | class EnableConsistentTiming |
75 | { |
76 | public: |
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 | |
89 | class tst_QPauseAnimation : public QObject |
90 | { |
91 | Q_OBJECT |
92 | public Q_SLOTS: |
93 | void initTestCase(); |
94 | |
95 | private 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 | |
108 | void tst_QPauseAnimation::initTestCase() |
109 | { |
110 | qRegisterMetaType<QAbstractAnimation::State>(typeName: "QAbstractAnimation::State" ); |
111 | qRegisterMetaType<QAbstractAnimation::DeletionPolicy>(typeName: "QAbstractAnimation::DeletionPolicy" ); |
112 | } |
113 | |
114 | void 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 | |
127 | void 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 | |
138 | void 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 | |
161 | void 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 | |
204 | void 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 | |
233 | void 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 | |
253 | void 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 | |
308 | void 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 | |
342 | void 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 | |
432 | void 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 | |
443 | QTEST_MAIN(tst_QPauseAnimation) |
444 | #include "tst_qpauseanimation.moc" |
445 | |