/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #if defined(Q_OS_WIN) || defined(Q_OS_ANDROID) # define BAD_TIMER_RESOLUTION #endif #ifdef BAD_TIMER_RESOLUTION static const char timerError[] = "On this platform, consistent timing is not working properly due to bad timer resolution"; # define WAIT_FOR_STOPPED(animation, duration) \ QTest::qWait(duration); \ if (animation.state() != QAbstractAnimation::Stopped) \ QEXPECT_FAIL("", timerError, Abort); \ QCOMPARE(animation.state(), QAbstractAnimation::Stopped) #else // Use QTRY_COMPARE with one additional timer tick # define WAIT_FOR_STOPPED(animation, duration) \ QTRY_COMPARE_WITH_TIMEOUT(animation.state(), QAbstractAnimation::Stopped, (duration)) #endif class TestablePauseAnimation : public QPauseAnimation { Q_OBJECT public: TestablePauseAnimation(QObject *parent = 0) : QPauseAnimation(parent), m_updateCurrentTimeCount(0) { } int m_updateCurrentTimeCount; protected: void updateCurrentTime(int currentTime) { QPauseAnimation::updateCurrentTime(currentTime); ++m_updateCurrentTimeCount; } }; class EnableConsistentTiming { public: EnableConsistentTiming() { QUnifiedTimer *timer = QUnifiedTimer::instance(); timer->setConsistentTiming(true); } ~EnableConsistentTiming() { QUnifiedTimer *timer = QUnifiedTimer::instance(); timer->setConsistentTiming(false); } }; class tst_QPauseAnimation : public QObject { Q_OBJECT public Q_SLOTS: void initTestCase(); private slots: void changeDirectionWhileRunning(); void noTimerUpdates_data(); void noTimerUpdates(); void multiplePauseAnimations(); void pauseAndPropertyAnimations(); void pauseResume(); void sequentialPauseGroup(); void sequentialGroupWithPause(); void multipleSequentialGroups(); void zeroDuration(); }; void tst_QPauseAnimation::initTestCase() { qRegisterMetaType("QAbstractAnimation::State"); qRegisterMetaType("QAbstractAnimation::DeletionPolicy"); } void tst_QPauseAnimation::changeDirectionWhileRunning() { EnableConsistentTiming enabled; TestablePauseAnimation animation; animation.setDuration(400); animation.start(); QTRY_COMPARE(animation.state(), QAbstractAnimation::Running); animation.setDirection(QAbstractAnimation::Backward); const int expectedDuration = animation.totalDuration() + 100; WAIT_FOR_STOPPED(animation, expectedDuration); } void tst_QPauseAnimation::noTimerUpdates_data() { QTest::addColumn("duration"); QTest::addColumn("loopCount"); QTest::newRow("0") << 200 << 1; QTest::newRow("1") << 160 << 1; QTest::newRow("2") << 160 << 2; QTest::newRow("3") << 200 << 3; } void tst_QPauseAnimation::noTimerUpdates() { EnableConsistentTiming enabled; QFETCH(int, duration); QFETCH(int, loopCount); TestablePauseAnimation animation; animation.setDuration(duration); animation.setLoopCount(loopCount); animation.start(); const int expectedDuration = animation.totalDuration() + 150; WAIT_FOR_STOPPED(animation, expectedDuration); const int expectedLoopCount = 1 + loopCount; #ifdef BAD_TIMER_RESOLUTION if (animation.m_updateCurrentTimeCount != expectedLoopCount) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(animation.m_updateCurrentTimeCount, expectedLoopCount); } void tst_QPauseAnimation::multiplePauseAnimations() { EnableConsistentTiming enabled; TestablePauseAnimation animation; animation.setDuration(200); TestablePauseAnimation animation2; animation2.setDuration(800); animation.start(); animation2.start(); const int expectedDuration = animation.totalDuration() + 150; WAIT_FOR_STOPPED(animation, expectedDuration); #ifdef BAD_TIMER_RESOLUTION if (animation2.state() != QAbstractAnimation::Running) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(animation2.state(), QAbstractAnimation::Running); #ifdef BAD_TIMER_RESOLUTION if (animation.m_updateCurrentTimeCount != 2) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(animation.m_updateCurrentTimeCount, 2); #ifdef BAD_TIMER_RESOLUTION if (animation2.m_updateCurrentTimeCount != 2) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(animation2.m_updateCurrentTimeCount, 2); WAIT_FOR_STOPPED(animation2, 600); #ifdef BAD_TIMER_RESOLUTION if (animation2.m_updateCurrentTimeCount != 3) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(animation2.m_updateCurrentTimeCount, 3); } void tst_QPauseAnimation::pauseAndPropertyAnimations() { EnableConsistentTiming enabled; TestablePauseAnimation pause; pause.setDuration(200); QObject o; o.setProperty("ole", 42); QPropertyAnimation animation(&o, "ole"); animation.setEndValue(43); pause.start(); QTest::qWait(100); animation.start(); QCOMPARE(animation.state(), QAbstractAnimation::Running); QCOMPARE(pause.state(), QAbstractAnimation::Running); QCOMPARE(pause.m_updateCurrentTimeCount, 2); const int expectedDuration = animation.totalDuration() + 150; WAIT_FOR_STOPPED(animation, expectedDuration); QCOMPARE(pause.state(), QAbstractAnimation::Stopped); QVERIFY(pause.m_updateCurrentTimeCount > 3); } void tst_QPauseAnimation::pauseResume() { TestablePauseAnimation animation; animation.setDuration(400); animation.start(); QCOMPARE(animation.state(), QAbstractAnimation::Running); QTest::qWait(200); animation.pause(); QCOMPARE(animation.state(), QAbstractAnimation::Paused); animation.start(); QTRY_COMPARE(animation.state(), QAbstractAnimation::Stopped); #ifdef BAD_TIMER_RESOLUTION if (animation.m_updateCurrentTimeCount < 3) QEXPECT_FAIL("", timerError, Abort); #endif QVERIFY2(animation.m_updateCurrentTimeCount >= 3, qPrintable( QString::fromLatin1("animation.m_updateCurrentTimeCount = %1").arg(animation.m_updateCurrentTimeCount))); } void tst_QPauseAnimation::sequentialPauseGroup() { QSequentialAnimationGroup group; TestablePauseAnimation animation1(&group); animation1.setDuration(200); TestablePauseAnimation animation2(&group); animation2.setDuration(200); TestablePauseAnimation animation3(&group); animation3.setDuration(200); group.start(); QCOMPARE(animation1.m_updateCurrentTimeCount, 1); QCOMPARE(animation2.m_updateCurrentTimeCount, 0); QCOMPARE(animation3.m_updateCurrentTimeCount, 0); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(animation1.state(), QAbstractAnimation::Running); QCOMPARE(animation2.state(), QAbstractAnimation::Stopped); QCOMPARE(animation3.state(), QAbstractAnimation::Stopped); group.setCurrentTime(250); QCOMPARE(animation1.m_updateCurrentTimeCount, 2); QCOMPARE(animation2.m_updateCurrentTimeCount, 1); QCOMPARE(animation3.m_updateCurrentTimeCount, 0); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(animation1.state(), QAbstractAnimation::Stopped); QCOMPARE((QAbstractAnimation*)&animation2, group.currentAnimation()); QCOMPARE(animation2.state(), QAbstractAnimation::Running); QCOMPARE(animation3.state(), QAbstractAnimation::Stopped); group.setCurrentTime(500); QCOMPARE(animation1.m_updateCurrentTimeCount, 2); QCOMPARE(animation2.m_updateCurrentTimeCount, 2); QCOMPARE(animation3.m_updateCurrentTimeCount, 1); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(animation1.state(), QAbstractAnimation::Stopped); QCOMPARE(animation2.state(), QAbstractAnimation::Stopped); QCOMPARE((QAbstractAnimation*)&animation3, group.currentAnimation()); QCOMPARE(animation3.state(), QAbstractAnimation::Running); group.setCurrentTime(750); QCOMPARE(group.state(), QAbstractAnimation::Stopped); QCOMPARE(animation1.state(), QAbstractAnimation::Stopped); QCOMPARE(animation2.state(), QAbstractAnimation::Stopped); QCOMPARE(animation3.state(), QAbstractAnimation::Stopped); QCOMPARE(animation1.m_updateCurrentTimeCount, 2); QCOMPARE(animation2.m_updateCurrentTimeCount, 2); QCOMPARE(animation3.m_updateCurrentTimeCount, 2); } void tst_QPauseAnimation::sequentialGroupWithPause() { QSequentialAnimationGroup group; QObject o; o.setProperty("ole", 42); QPropertyAnimation animation(&o, "ole", &group); animation.setEndValue(43); TestablePauseAnimation pause(&group); pause.setDuration(250); group.start(); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(animation.state(), QAbstractAnimation::Running); QCOMPARE(pause.state(), QAbstractAnimation::Stopped); group.setCurrentTime(300); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(animation.state(), QAbstractAnimation::Stopped); QCOMPARE((QAbstractAnimation*)&pause, group.currentAnimation()); QCOMPARE(pause.state(), QAbstractAnimation::Running); group.setCurrentTime(600); QCOMPARE(group.state(), QAbstractAnimation::Stopped); QCOMPARE(animation.state(), QAbstractAnimation::Stopped); QCOMPARE(pause.state(), QAbstractAnimation::Stopped); QCOMPARE(pause.m_updateCurrentTimeCount, 2); } void tst_QPauseAnimation::multipleSequentialGroups() { EnableConsistentTiming enabled; QParallelAnimationGroup group; group.setLoopCount(2); QSequentialAnimationGroup subgroup1(&group); QObject o; o.setProperty("ole", 42); QPropertyAnimation animation(&o, "ole", &subgroup1); animation.setEndValue(43); animation.setDuration(300); TestablePauseAnimation pause(&subgroup1); pause.setDuration(200); QSequentialAnimationGroup subgroup2(&group); o.setProperty("ole2", 42); QPropertyAnimation animation2(&o, "ole2", &subgroup2); animation2.setEndValue(43); animation2.setDuration(200); TestablePauseAnimation pause2(&subgroup2); pause2.setDuration(250); QSequentialAnimationGroup subgroup3(&group); TestablePauseAnimation pause3(&subgroup3); pause3.setDuration(400); o.setProperty("ole3", 42); QPropertyAnimation animation3(&o, "ole3", &subgroup3); animation3.setEndValue(43); animation3.setDuration(200); QSequentialAnimationGroup subgroup4(&group); TestablePauseAnimation pause4(&subgroup4); pause4.setDuration(310); TestablePauseAnimation pause5(&subgroup4); pause5.setDuration(60); group.start(); QCOMPARE(group.state(), QAbstractAnimation::Running); QCOMPARE(subgroup1.state(), QAbstractAnimation::Running); QCOMPARE(subgroup2.state(), QAbstractAnimation::Running); QCOMPARE(subgroup3.state(), QAbstractAnimation::Running); QCOMPARE(subgroup4.state(), QAbstractAnimation::Running); // This is a pretty long animation so it tends to get rather out of sync // when using the consistent timer, so run for an extra half second for good // measure... const int expectedDuration = group.totalDuration() + 550; WAIT_FOR_STOPPED(group, expectedDuration); #ifdef BAD_TIMER_RESOLUTION if (subgroup1.state() != QAbstractAnimation::Stopped) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(subgroup1.state(), QAbstractAnimation::Stopped); #ifdef BAD_TIMER_RESOLUTION if (subgroup2.state() != QAbstractAnimation::Stopped) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(subgroup2.state(), QAbstractAnimation::Stopped); #ifdef BAD_TIMER_RESOLUTION if (subgroup3.state() != QAbstractAnimation::Stopped) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(subgroup3.state(), QAbstractAnimation::Stopped); #ifdef BAD_TIMER_RESOLUTION if (subgroup4.state() != QAbstractAnimation::Stopped) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(subgroup4.state(), QAbstractAnimation::Stopped); #ifdef BAD_TIMER_RESOLUTION if (pause5.m_updateCurrentTimeCount != 4) QEXPECT_FAIL("", timerError, Abort); #endif QCOMPARE(pause5.m_updateCurrentTimeCount, 4); } void tst_QPauseAnimation::zeroDuration() { TestablePauseAnimation animation; animation.setDuration(0); animation.start(); const int expectedDuration = animation.totalDuration() + 150; WAIT_FOR_STOPPED(animation, expectedDuration); QCOMPARE(animation.m_updateCurrentTimeCount, 1); } QTEST_MAIN(tst_QPauseAnimation) #include "tst_qpauseanimation.moc"