diff options
Diffstat (limited to 'tests')
31 files changed, 4428 insertions, 75 deletions
diff --git a/tests/auto/declarative/animation/animation.pro b/tests/auto/declarative/animation/animation.pro new file mode 100644 index 0000000000..a9c0cee309 --- /dev/null +++ b/tests/auto/declarative/animation/animation.pro @@ -0,0 +1,7 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qabstractanimationjob \ + qanimationgroupjob \ + qparallelanimationgroupjob \ + qpauseanimationjob \ + qsequentialanimationgroupjob diff --git a/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro b/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro new file mode 100644 index 0000000000..db8649bbb9 --- /dev/null +++ b/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro @@ -0,0 +1,5 @@ +CONFIG += testcase parallel_test +macx:CONFIG -= app_bundle +TARGET = tst_qabstractanimationjob +QT = core-private declarative-private testlib +SOURCES = tst_qabstractanimationjob.cpp diff --git a/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp b/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp new file mode 100644 index 0000000000..6a8db097c2 --- /dev/null +++ b/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtDeclarative/private/qabstractanimationjob_p.h> +#include <QtDeclarative/private/qanimationgroupjob_p.h> +#include <QtTest> + +class tst_QAbstractAnimationJob : public QObject +{ + Q_OBJECT +private slots: + void construction(); + void destruction(); + void currentLoop(); + void currentLoopTime(); + void currentTime(); + void direction(); + void group(); + void loopCount(); + void state(); + void totalDuration(); + void avoidJumpAtStart(); + void avoidJumpAtStartWithStop(); + void avoidJumpAtStartWithRunning(); +}; + +class TestableQAbstractAnimation : public QAbstractAnimationJob +{ +public: + TestableQAbstractAnimation() : m_duration(10) {} + virtual ~TestableQAbstractAnimation() {}; + + int duration() const { return m_duration; } + virtual void updateCurrentTime(int) {} + + void setDuration(int duration) { m_duration = duration; } +private: + int m_duration; +}; + +class DummyQAnimationGroup : public QAnimationGroupJob +{ +public: + int duration() const { return 10; } + virtual void updateCurrentTime(int) {} +}; + +void tst_QAbstractAnimationJob::construction() +{ + TestableQAbstractAnimation anim; +} + +void tst_QAbstractAnimationJob::destruction() +{ + TestableQAbstractAnimation *anim = new TestableQAbstractAnimation; + delete anim; +} + +void tst_QAbstractAnimationJob::currentLoop() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.currentLoop(), 0); +} + +void tst_QAbstractAnimationJob::currentLoopTime() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.currentLoopTime(), 0); +} + +void tst_QAbstractAnimationJob::currentTime() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.currentTime(), 0); + anim.setCurrentTime(10); + QCOMPARE(anim.currentTime(), 10); +} + +void tst_QAbstractAnimationJob::direction() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.direction(), QAbstractAnimationJob::Forward); + anim.setDirection(QAbstractAnimationJob::Backward); + QCOMPARE(anim.direction(), QAbstractAnimationJob::Backward); + anim.setDirection(QAbstractAnimationJob::Forward); + QCOMPARE(anim.direction(), QAbstractAnimationJob::Forward); +} + +void tst_QAbstractAnimationJob::group() +{ + TestableQAbstractAnimation *anim = new TestableQAbstractAnimation; + DummyQAnimationGroup group; + group.appendAnimation(anim); + QCOMPARE(anim->group(), &group); +} + +void tst_QAbstractAnimationJob::loopCount() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.loopCount(), 1); + anim.setLoopCount(10); + QCOMPARE(anim.loopCount(), 10); +} + +void tst_QAbstractAnimationJob::state() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.state(), QAbstractAnimationJob::Stopped); +} + +void tst_QAbstractAnimationJob::totalDuration() +{ + TestableQAbstractAnimation anim; + QCOMPARE(anim.duration(), 10); + anim.setLoopCount(5); + QCOMPARE(anim.totalDuration(), 50); +} + +void tst_QAbstractAnimationJob::avoidJumpAtStart() +{ + TestableQAbstractAnimation anim; + anim.setDuration(1000); + + /* + the timer shouldn't actually start until we hit the event loop, + so the sleep should have no effect + */ + anim.start(); + QTest::qSleep(300); + QCoreApplication::processEvents(); + QVERIFY(anim.currentTime() < 50); +} + +void tst_QAbstractAnimationJob::avoidJumpAtStartWithStop() +{ + TestableQAbstractAnimation anim; + anim.setDuration(1000); + + TestableQAbstractAnimation anim2; + anim2.setDuration(1000); + + TestableQAbstractAnimation anim3; + anim3.setDuration(1000); + + anim.start(); + QTest::qWait(300); + anim.stop(); + + /* + same test as avoidJumpAtStart, but after there is a + running animation that is stopped + */ + anim2.start(); + QTest::qSleep(300); + anim3.start(); + QCoreApplication::processEvents(); + QVERIFY(anim2.currentTime() < 50); + QVERIFY(anim3.currentTime() < 50); +} + +void tst_QAbstractAnimationJob::avoidJumpAtStartWithRunning() +{ + TestableQAbstractAnimation anim; + anim.setDuration(2000); + + TestableQAbstractAnimation anim2; + anim2.setDuration(1000); + + TestableQAbstractAnimation anim3; + anim3.setDuration(1000); + + anim.start(); + QTest::qWait(300); //make sure timer has started + + /* + same test as avoidJumpAtStart, but with an + existing running animation + */ + anim2.start(); + QTest::qSleep(300); //force large delta for next tick + anim3.start(); + QCoreApplication::processEvents(); + QVERIFY(anim2.currentTime() < 50); + QVERIFY(anim3.currentTime() < 50); +} + + +QTEST_MAIN(tst_QAbstractAnimationJob) + +#include "tst_qabstractanimationjob.moc" diff --git a/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro b/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro new file mode 100644 index 0000000000..b9c9d2921d --- /dev/null +++ b/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro @@ -0,0 +1,5 @@ +CONFIG += testcase parallel_test +macx:CONFIG -= app_bundle +TARGET = tst_qanimationgroupjob +QT = core-private declarative-private testlib +SOURCES = tst_qanimationgroupjob.cpp diff --git a/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp b/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp new file mode 100644 index 0000000000..ec7d2b37c7 --- /dev/null +++ b/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtDeclarative/private/qanimationgroupjob_p.h> +#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h> +#include <QtDeclarative/private/qparallelanimationgroupjob_p.h> + +Q_DECLARE_METATYPE(QAbstractAnimationJob::State) + +class tst_QAnimationGroupJob : public QObject +{ + Q_OBJECT +public Q_SLOTS: + void initTestCase(); + +private slots: + void construction(); + void emptyGroup(); + void setCurrentTime(); + void addChildTwice(); +}; + +void tst_QAnimationGroupJob::initTestCase() +{ + qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); +} + +void tst_QAnimationGroupJob::construction() +{ + QSequentialAnimationGroupJob animationgroup; +} + +class TestableGenericAnimation : public QAbstractAnimationJob +{ +public: + TestableGenericAnimation(int duration = 250) : m_duration(duration) {} + int duration() const { return m_duration; } + +private: + int m_duration; +}; + +class UncontrolledAnimation : public QObject, public QAbstractAnimationJob +{ + Q_OBJECT +public: + UncontrolledAnimation() + : id(0) + { + } + + int duration() const { return -1; /* not time driven */ } + +protected: + void timerEvent(QTimerEvent *event) + { + if (event->timerId() == id) + stop(); + } + + void updateRunning(bool running) + { + if (running) { + id = startTimer(500); + } else { + killTimer(id); + id = 0; + } + } + +private: + int id; +}; + +class StateChangeListener: public QAnimation2ChangeListener +{ +public: + virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) + { + states << newState; + } + + int count() + { + return states.count(); + } + + QList<QAbstractAnimationJob::State> states; +}; + +void tst_QAnimationGroupJob::emptyGroup() +{ + QSequentialAnimationGroupJob group; + StateChangeListener groupStateChangedSpy; + group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + group.start(); + + QCOMPARE(groupStateChangedSpy.count(), 2); + + QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(groupStateChangedSpy.states.at(1), QAnimationGroupJob::Stopped); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + + QTest::ignoreMessage(QtWarningMsg, "QAbstractAnimationJob::pause: Cannot pause a stopped animation"); + group.pause(); + + QCOMPARE(groupStateChangedSpy.count(), 2); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + + group.start(); + + QCOMPARE(groupStateChangedSpy.states.at(2), + QAnimationGroupJob::Running); + QCOMPARE(groupStateChangedSpy.states.at(3), + QAnimationGroupJob::Stopped); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + + group.stop(); + + QCOMPARE(groupStateChangedSpy.count(), 4); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); +} + +void tst_QAnimationGroupJob::setCurrentTime() +{ + // was originally sequence operating on same object/property + QSequentialAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + QAbstractAnimationJob *a1_s_o1 = new TestableGenericAnimation; + QAbstractAnimationJob *a2_s_o1 = new TestableGenericAnimation; + QAbstractAnimationJob *a3_s_o1 = new TestableGenericAnimation; + a2_s_o1->setLoopCount(3); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + + // was originally sequence operating on different object/properties + QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob(); + QAbstractAnimationJob *a1_s_o2 = new TestableGenericAnimation; + QAbstractAnimationJob *a1_s_o3 = new TestableGenericAnimation; + sequence2->appendAnimation(a1_s_o2); + sequence2->appendAnimation(a1_s_o3); + + // was originally parallel operating on different object/properties + QAnimationGroupJob *parallel = new QParallelAnimationGroupJob(); + QAbstractAnimationJob *a1_p_o1 = new TestableGenericAnimation; + QAbstractAnimationJob *a1_p_o2 = new TestableGenericAnimation; + QAbstractAnimationJob *a1_p_o3 = new TestableGenericAnimation; + a1_p_o2->setLoopCount(3); + parallel->appendAnimation(a1_p_o1); + parallel->appendAnimation(a1_p_o2); + parallel->appendAnimation(a1_p_o3); + + QAbstractAnimationJob *notTimeDriven = new UncontrolledAnimation; + QCOMPARE(notTimeDriven->totalDuration(), -1); + + QAbstractAnimationJob *loopsForever = new TestableGenericAnimation; + loopsForever->setLoopCount(-1); + QCOMPARE(loopsForever->totalDuration(), -1); + + QParallelAnimationGroupJob group; + group.appendAnimation(sequence); + group.appendAnimation(sequence2); + group.appendAnimation(parallel); + group.appendAnimation(notTimeDriven); + group.appendAnimation(loopsForever); + + // Current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(parallel->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o3->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 1); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + QCOMPARE(a1_p_o1->currentLoopTime(), 1); + QCOMPARE(a1_p_o2->currentLoopTime(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 1); + QCOMPARE(notTimeDriven->currentLoopTime(), 1); + QCOMPARE(loopsForever->currentLoopTime(), 1); + + // Current time = 250 + group.setCurrentTime(250); + QCOMPARE(group.currentLoopTime(), 250); + QCOMPARE(sequence->currentLoopTime(), 250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + QCOMPARE(a1_p_o1->currentLoopTime(), 250); + QCOMPARE(a1_p_o2->currentLoopTime(), 0); + QCOMPARE(a1_p_o2->currentLoop(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 250); + QCOMPARE(loopsForever->currentLoopTime(), 0); + QCOMPARE(loopsForever->currentLoop(), 1); + QCOMPARE(sequence->currentAnimation(), a2_s_o1); + + // Current time = 251 + group.setCurrentTime(251); + QCOMPARE(group.currentLoopTime(), 251); + QCOMPARE(sequence->currentLoopTime(), 251); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoop(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 251); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 1); + QCOMPARE(a1_p_o1->currentLoopTime(), 250); + QCOMPARE(a1_p_o2->currentLoopTime(), 1); + QCOMPARE(a1_p_o2->currentLoop(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 251); + QCOMPARE(loopsForever->currentLoopTime(), 1); + QCOMPARE(sequence->currentAnimation(), a2_s_o1); +} + +void tst_QAnimationGroupJob::addChildTwice() +{ + QAbstractAnimationJob *subGroup; + QAbstractAnimationJob *subGroup2; + QAnimationGroupJob *parent = new QSequentialAnimationGroupJob(); + + subGroup = new QAbstractAnimationJob; + parent->appendAnimation(subGroup); + parent->appendAnimation(subGroup); + QVERIFY(parent->firstChild() && !parent->firstChild()->nextSibling()); + + parent->clear(); + + QVERIFY(!parent->firstChild()); + + // adding the same item twice to a group will remove the item from its current position + // and append it to the end + subGroup = new QAbstractAnimationJob; + parent->appendAnimation(subGroup); + subGroup2 = new QAbstractAnimationJob; + parent->appendAnimation(subGroup2); + + QCOMPARE(parent->firstChild(), subGroup); + QCOMPARE(parent->lastChild(), subGroup2); + + parent->appendAnimation(subGroup); + + QCOMPARE(parent->firstChild(), subGroup2); + QCOMPARE(parent->lastChild(), subGroup); + + delete parent; +} + +QTEST_MAIN(tst_QAnimationGroupJob) +#include "tst_qanimationgroupjob.moc" diff --git a/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro b/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro new file mode 100644 index 0000000000..332fa4554b --- /dev/null +++ b/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +macx:CONFIG -= app_bundle +TARGET = tst_qparallelanimationgroupjob +QT = core-private gui declarative-private testlib +SOURCES = tst_qparallelanimationgroupjob.cpp diff --git a/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp new file mode 100644 index 0000000000..13da19ec90 --- /dev/null +++ b/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp @@ -0,0 +1,931 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtDeclarative/private/qparallelanimationgroupjob_p.h> + +Q_DECLARE_METATYPE(QAbstractAnimationJob::State) + +class tst_QParallelAnimationGroupJob : public QObject +{ + Q_OBJECT +public Q_SLOTS: + void initTestCase(); + +private slots: + void construction(); + void setCurrentTime(); + void stateChanged(); + void clearGroup(); + void propagateGroupUpdateToChildren(); + void updateChildrenWithRunningGroup(); + void deleteChildrenWithRunningGroup(); + void startChildrenWithStoppedGroup(); + void stopGroupWithRunningChild(); + void startGroupWithRunningChild(); + void zeroDurationAnimation(); + void stopUncontrolledAnimations(); + void loopCount_data(); + void loopCount(); + void addAndRemoveDuration(); + void pauseResume(); + + void crashWhenRemovingUncontrolledAnimation(); +}; + +void tst_QParallelAnimationGroupJob::initTestCase() +{ + qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); +#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) + // give the mac/wince app start event queue time to clear + QTest::qWait(1000); +#endif +} + +void tst_QParallelAnimationGroupJob::construction() +{ + QParallelAnimationGroupJob animationgroup; +} + +class TestAnimation : public QAbstractAnimationJob +{ +public: + TestAnimation(int duration = 250) : m_duration(duration) {} + int duration() const { return m_duration; } + +private: + int m_duration; +}; + +class UncontrolledAnimation : public QObject, public QAbstractAnimationJob +{ + Q_OBJECT +public: + UncontrolledAnimation() + : id(0) + { + } + + int duration() const { return -1; /* not time driven */ } + +protected: + void timerEvent(QTimerEvent *event) + { + if (event->timerId() == id) + stop(); + } + + void updateRunning(bool running) + { + if (running) { + id = startTimer(500); + } else { + killTimer(id); + id = 0; + } + } + +private: + int id; +}; + +class StateChangeListener: public QAnimation2ChangeListener +{ +public: + virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) + { + states << newState; + } + + void clear() { states.clear(); } + int count() { return states.count(); } + + QList<QAbstractAnimationJob::State> states; +}; + +class FinishedListener: public QAnimation2ChangeListener +{ +public: + FinishedListener() : m_count(0) {} + + virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; } + void clear() { m_count = 0; } + int count() { return m_count; } + +private: + int m_count; +}; + +void tst_QParallelAnimationGroupJob::setCurrentTime() +{ + // originally was parallel operating on different object/properties + QAnimationGroupJob *parallel = new QParallelAnimationGroupJob(); + TestAnimation *a1_p_o1 = new TestAnimation; + TestAnimation *a1_p_o2 = new TestAnimation; + TestAnimation *a1_p_o3 = new TestAnimation; + a1_p_o2->setLoopCount(3); + parallel->appendAnimation(a1_p_o1); + parallel->appendAnimation(a1_p_o2); + parallel->appendAnimation(a1_p_o3); + + UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation; + QCOMPARE(notTimeDriven->totalDuration(), -1); + + TestAnimation *loopsForever = new TestAnimation; + loopsForever->setLoopCount(-1); + QCOMPARE(loopsForever->totalDuration(), -1); + + QParallelAnimationGroupJob group; + group.appendAnimation(parallel); + group.appendAnimation(notTimeDriven); + group.appendAnimation(loopsForever); + + // Current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(parallel->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_p_o3->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(a1_p_o1->currentLoopTime(), 1); + QCOMPARE(a1_p_o2->currentLoopTime(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 1); + QCOMPARE(notTimeDriven->currentLoopTime(), 1); + QCOMPARE(loopsForever->currentLoopTime(), 1); + + // Current time = 250 + group.setCurrentTime(250); + QCOMPARE(group.currentLoopTime(), 250); + QCOMPARE(a1_p_o1->currentLoopTime(), 250); + QCOMPARE(a1_p_o2->currentLoopTime(), 0); + QCOMPARE(a1_p_o2->currentLoop(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 250); + QCOMPARE(loopsForever->currentLoopTime(), 0); + QCOMPARE(loopsForever->currentLoop(), 1); + + // Current time = 251 + group.setCurrentTime(251); + QCOMPARE(group.currentLoopTime(), 251); + QCOMPARE(a1_p_o1->currentLoopTime(), 250); + QCOMPARE(a1_p_o2->currentLoopTime(), 1); + QCOMPARE(a1_p_o2->currentLoop(), 1); + QCOMPARE(a1_p_o3->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 251); + QCOMPARE(loopsForever->currentLoopTime(), 1); +} + +void tst_QParallelAnimationGroupJob::stateChanged() +{ + //this ensures that the correct animations are started when starting the group + TestAnimation *anim1 = new TestAnimation(1000); + TestAnimation *anim2 = new TestAnimation(2000); + TestAnimation *anim3 = new TestAnimation(3000); + TestAnimation *anim4 = new TestAnimation(3000); + + QParallelAnimationGroupJob group; + group.appendAnimation(anim1); + group.appendAnimation(anim2); + group.appendAnimation(anim3); + group.appendAnimation(anim4); + + StateChangeListener spy1; + anim1->addAnimationChangeListener(&spy1, QAbstractAnimationJob::StateChange); + StateChangeListener spy2; + anim2->addAnimationChangeListener(&spy2, QAbstractAnimationJob::StateChange); + StateChangeListener spy3; + anim3->addAnimationChangeListener(&spy3, QAbstractAnimationJob::StateChange); + StateChangeListener spy4; + anim4->addAnimationChangeListener(&spy4, QAbstractAnimationJob::StateChange); + + //first; let's start forward + group.start(); + //all the animations should be started + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy1.states.last(), TestAnimation::Running); + QCOMPARE(spy2.count(), 1); + QCOMPARE(spy2.states.last(), TestAnimation::Running); + QCOMPARE(spy3.count(), 1); + QCOMPARE(spy3.states.last(), TestAnimation::Running); + QCOMPARE(spy4.count(), 1); + QCOMPARE(spy4.states.last(), TestAnimation::Running); + + group.setCurrentTime(1500); //anim1 should be finished + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(spy1.count(), 2); + QCOMPARE(spy1.states.last(), TestAnimation::Stopped); + QCOMPARE(spy2.count(), 1); //no change + QCOMPARE(spy3.count(), 1); //no change + QCOMPARE(spy4.count(), 1); //no change + + group.setCurrentTime(2500); //anim2 should be finished + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(spy1.count(), 2); //no change + QCOMPARE(spy2.count(), 2); + QCOMPARE(spy2.states.last(), TestAnimation::Stopped); + QCOMPARE(spy3.count(), 1); //no change + QCOMPARE(spy4.count(), 1); //no change + + group.setCurrentTime(3500); //everything should be finished + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(spy1.count(), 2); //no change + QCOMPARE(spy2.count(), 2); //no change + QCOMPARE(spy3.count(), 2); + QCOMPARE(spy3.states.last(), TestAnimation::Stopped); + QCOMPARE(spy4.count(), 2); + QCOMPARE(spy4.states.last(), TestAnimation::Stopped); + + //cleanup + spy1.clear(); + spy2.clear(); + spy3.clear(); + spy4.clear(); + + //now let's try to reverse that + group.setDirection(QAbstractAnimationJob::Backward); + group.start(); + + //only anim3 and anim4 should be started + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(spy1.count(), 0); + QCOMPARE(spy2.count(), 0); + QCOMPARE(spy3.count(), 1); + QCOMPARE(spy3.states.last(), TestAnimation::Running); + QCOMPARE(spy4.count(), 1); + QCOMPARE(spy4.states.last(), TestAnimation::Running); + + group.setCurrentTime(1500); //anim2 should be started + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(spy1.count(), 0); //no change + QCOMPARE(spy2.count(), 1); + QCOMPARE(spy2.states.last(), TestAnimation::Running); + QCOMPARE(spy3.count(), 1); //no change + QCOMPARE(spy4.count(), 1); //no change + + group.setCurrentTime(500); //anim1 is finally also started + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy1.states.last(), TestAnimation::Running); + QCOMPARE(spy2.count(), 1); //no change + QCOMPARE(spy3.count(), 1); //no change + QCOMPARE(spy4.count(), 1); //no change + + group.setCurrentTime(0); //everything should be stopped + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(spy1.count(), 2); + QCOMPARE(spy1.states.last(), TestAnimation::Stopped); + QCOMPARE(spy2.count(), 2); + QCOMPARE(spy2.states.last(), TestAnimation::Stopped); + QCOMPARE(spy3.count(), 2); + QCOMPARE(spy3.states.last(), TestAnimation::Stopped); + QCOMPARE(spy4.count(), 2); + QCOMPARE(spy4.states.last(), TestAnimation::Stopped); +} + +void tst_QParallelAnimationGroupJob::clearGroup() +{ + QParallelAnimationGroupJob group; + static const int animationCount = 10; + + for (int i = 0; i < animationCount; ++i) { + group.appendAnimation(new QParallelAnimationGroupJob); + } + + int count = 0; + for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling()) + ++count; + QCOMPARE(count, animationCount); + + group.clear(); + + QVERIFY(!group.firstChild() && !group.lastChild()); + QCOMPARE(group.currentLoopTime(), 0); +} + +void tst_QParallelAnimationGroupJob::propagateGroupUpdateToChildren() +{ + // this test verifies if group state changes are updating its children correctly + QParallelAnimationGroupJob group; + + TestAnimation anim1(100); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + group.start(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Running); + + group.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(anim1.state(), QAnimationGroupJob::Paused); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); +} + +void tst_QParallelAnimationGroupJob::updateChildrenWithRunningGroup() +{ + // assert that its possible to modify a child's state directly while their group is running + QParallelAnimationGroupJob group; + + TestAnimation anim(200); + + StateChangeListener groupStateChangedSpy; + group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange); + StateChangeListener childStateChangedSpy; + anim.addAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange); + + QCOMPARE(groupStateChangedSpy.count(), 0); + QCOMPARE(childStateChangedSpy.count(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim); + + group.start(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Running); + + QCOMPARE(groupStateChangedSpy.count(), 1); + QCOMPARE(childStateChangedSpy.count(), 1); + + QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(childStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + + // starting directly a running child will not have any effect + anim.start(); + + QCOMPARE(groupStateChangedSpy.count(), 1); + QCOMPARE(childStateChangedSpy.count(), 1); + + anim.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Paused); + + // in the animation stops directly, the group will still be running + anim.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Stopped); + + //cleanup + group.removeAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange); + anim.removeAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange); +} + +void tst_QParallelAnimationGroupJob::deleteChildrenWithRunningGroup() +{ + // test if children can be activated when their group is stopped + QParallelAnimationGroupJob group; + + TestAnimation *anim1 = new TestAnimation(200); + group.appendAnimation(anim1); + + QCOMPARE(group.duration(), anim1->duration()); + + group.start(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1->state(), QAnimationGroupJob::Running); + + QTest::qWait(80); + QVERIFY(group.currentLoopTime() > 0); + + delete anim1; + QVERIFY(!group.firstChild()); + QCOMPARE(group.duration(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.currentLoopTime(), 0); //that's the invariant +} + +void tst_QParallelAnimationGroupJob::startChildrenWithStoppedGroup() +{ + // test if children can be activated when their group is stopped + QParallelAnimationGroupJob group; + + TestAnimation anim1(200); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + anim1.start(); + anim2.start(); + anim2.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); +} + +void tst_QParallelAnimationGroupJob::stopGroupWithRunningChild() +{ + // children that started independently will not be affected by a group stop + QParallelAnimationGroupJob group; + + TestAnimation anim1(200); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + anim1.start(); + anim2.start(); + anim2.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + anim1.stop(); + anim2.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); +} + +void tst_QParallelAnimationGroupJob::startGroupWithRunningChild() +{ + // as the group has precedence over its children, starting a group will restart all the children + QParallelAnimationGroupJob group; + + TestAnimation anim1(200); + TestAnimation anim2(200); + + StateChangeListener stateChangedSpy1; + anim1.addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + StateChangeListener stateChangedSpy2; + anim2.addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); + + QCOMPARE(stateChangedSpy1.count(), 0); + QCOMPARE(stateChangedSpy2.count(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + anim1.start(); + anim2.start(); + anim2.pause(); + + QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(stateChangedSpy2.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(stateChangedSpy2.states.at(1), QAnimationGroupJob::Paused); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + group.start(); + + QCOMPARE(stateChangedSpy1.count(), 3); + QCOMPARE(stateChangedSpy1.states.at(1), QAnimationGroupJob::Stopped); + QCOMPARE(stateChangedSpy1.states.at(2), QAnimationGroupJob::Running); + + QCOMPARE(stateChangedSpy2.count(), 4); + QCOMPARE(stateChangedSpy2.states.at(2), QAnimationGroupJob::Stopped); + QCOMPARE(stateChangedSpy2.states.at(3), QAnimationGroupJob::Running); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Running); + + //cleanup + anim1.removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + anim2.removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); +} + +void tst_QParallelAnimationGroupJob::zeroDurationAnimation() +{ + QParallelAnimationGroupJob group; + + TestAnimation anim1(0); + TestAnimation anim2(100); + TestAnimation anim3(10); + + StateChangeListener stateChangedSpy1; + anim1.addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + FinishedListener finishedSpy1; + anim1.addAnimationChangeListener(&finishedSpy1, QAbstractAnimationJob::Completion); + + StateChangeListener stateChangedSpy2; + anim2.addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); + FinishedListener finishedSpy2; + anim2.addAnimationChangeListener(&finishedSpy2, QAbstractAnimationJob::Completion); + + StateChangeListener stateChangedSpy3; + anim3.addAnimationChangeListener(&stateChangedSpy3, QAbstractAnimationJob::StateChange); + FinishedListener finishedSpy3; + anim3.addAnimationChangeListener(&finishedSpy3, QAbstractAnimationJob::Completion); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + group.appendAnimation(&anim3); + QCOMPARE(stateChangedSpy1.count(), 0); + group.start(); + QCOMPARE(stateChangedSpy1.count(), 2); + QCOMPARE(finishedSpy1.count(), 1); + QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(stateChangedSpy1.states.at(1), QAnimationGroupJob::Stopped); + + QCOMPARE(stateChangedSpy2.count(), 1); + QCOMPARE(finishedSpy2.count(), 0); + QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running); + + QCOMPARE(stateChangedSpy3.count(), 1); + QCOMPARE(finishedSpy3.count(), 0); + QCOMPARE(stateChangedSpy3.states.at(0), QAnimationGroupJob::Running); + + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Running); + QCOMPARE(anim3.state(), QAnimationGroupJob::Running); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + + group.stop(); + group.setLoopCount(4); + stateChangedSpy1.clear(); + stateChangedSpy2.clear(); + stateChangedSpy3.clear(); + + group.start(); + QCOMPARE(stateChangedSpy1.count(), 2); + QCOMPARE(stateChangedSpy2.count(), 1); + QCOMPARE(stateChangedSpy3.count(), 1); + group.setCurrentTime(50); + QCOMPARE(stateChangedSpy1.count(), 2); + QCOMPARE(stateChangedSpy2.count(), 1); + QCOMPARE(stateChangedSpy3.count(), 2); + group.setCurrentTime(150); + QCOMPARE(stateChangedSpy1.count(), 4); + QCOMPARE(stateChangedSpy2.count(), 3); + QCOMPARE(stateChangedSpy3.count(), 4); + group.setCurrentTime(50); + QCOMPARE(stateChangedSpy1.count(), 6); + QCOMPARE(stateChangedSpy2.count(), 5); + QCOMPARE(stateChangedSpy3.count(), 6); + + //cleanup + anim1.removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + anim1.removeAnimationChangeListener(&finishedSpy1, QAbstractAnimationJob::Completion); + anim2.removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); + anim2.removeAnimationChangeListener(&finishedSpy2, QAbstractAnimationJob::Completion); + anim3.removeAnimationChangeListener(&stateChangedSpy3, QAbstractAnimationJob::StateChange); + anim3.removeAnimationChangeListener(&finishedSpy3, QAbstractAnimationJob::Completion); +} + +void tst_QParallelAnimationGroupJob::stopUncontrolledAnimations() +{ + QParallelAnimationGroupJob group; + + TestAnimation anim1(0); + + UncontrolledAnimation notTimeDriven; + QCOMPARE(notTimeDriven.totalDuration(), -1); + + TestAnimation loopsForever(100); + loopsForever.setLoopCount(-1); + + StateChangeListener stateChangedSpy; + anim1.addAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange); + + group.appendAnimation(&anim1); + group.appendAnimation(¬TimeDriven); + group.appendAnimation(&loopsForever); + + group.start(); + + QCOMPARE(stateChangedSpy.count(), 2); + QCOMPARE(stateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(stateChangedSpy.states.at(1), QAnimationGroupJob::Stopped); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + + notTimeDriven.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running); + + loopsForever.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped); +} + +struct AnimState { + AnimState(int time = -1) : time(time), state(-1) {} + AnimState(int time, int state) : time(time), state(state) {} + int time; + int state; +}; + +#define Running QAbstractAnimationJob::Running +#define Stopped QAbstractAnimationJob::Stopped + +Q_DECLARE_METATYPE(AnimState) +void tst_QParallelAnimationGroupJob::loopCount_data() +{ + QTest::addColumn<bool>("directionBackward"); + QTest::addColumn<int>("setLoopCount"); + QTest::addColumn<int>("initialGroupTime"); + QTest::addColumn<int>("currentGroupTime"); + QTest::addColumn<AnimState>("expected1"); + QTest::addColumn<AnimState>("expected2"); + QTest::addColumn<AnimState>("expected3"); + + // D U R A T I O N + // 100 60*2 0 + // direction = Forward + QTest::newRow("50") << false << 3 << 0 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("100") << false << 3 << 0 << 100 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped); + QTest::newRow("110") << false << 3 << 0 << 110 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("120") << false << 3 << 0 << 120 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped); + + QTest::newRow("170") << false << 3 << 0 << 170 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("220") << false << 3 << 0 << 220 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped); + QTest::newRow("230") << false << 3 << 0 << 230 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("240") << false << 3 << 0 << 240 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped); + + QTest::newRow("290") << false << 3 << 0 << 290 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("340") << false << 3 << 0 << 340 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped); + QTest::newRow("350") << false << 3 << 0 << 350 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("360") << false << 3 << 0 << 360 << AnimState(100, Stopped) << AnimState( 60 ) << AnimState( 0, Stopped); + + QTest::newRow("410") << false << 3 << 0 << 410 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped); + QTest::newRow("460") << false << 3 << 0 << 460 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped); + QTest::newRow("470") << false << 3 << 0 << 470 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped); + QTest::newRow("480") << false << 3 << 0 << 480 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped); + + // direction = Forward, rewind + QTest::newRow("120-110") << false << 3 << 120 << 110 << AnimState( 0, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("120-50") << false << 3 << 120 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("120-0") << false << 3 << 120 << 0 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped); + QTest::newRow("300-110") << false << 3 << 300 << 110 << AnimState( 0, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("300-50") << false << 3 << 300 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("300-0") << false << 3 << 300 << 0 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped); + QTest::newRow("115-105") << false << 3 << 115 << 105 << AnimState( 42, Stopped) << AnimState( 45, Running) << AnimState( 0, Stopped); + + // direction = Backward + QTest::newRow("b120-120") << true << 3 << 120 << 120 << AnimState( 42, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped); + QTest::newRow("b120-110") << true << 3 << 120 << 110 << AnimState( 42, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("b120-100") << true << 3 << 120 << 100 << AnimState(100, Running) << AnimState( 40, Running) << AnimState( 0, Stopped); + QTest::newRow("b120-50") << true << 3 << 120 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("b120-0") << true << 3 << 120 << 0 << AnimState( 0, Stopped) << AnimState( 0, Stopped) << AnimState( 0, Stopped); + QTest::newRow("b360-170") << true << 3 << 360 << 170 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("b360-220") << true << 3 << 360 << 220 << AnimState(100, Running) << AnimState( 40, Running) << AnimState( 0, Stopped); + QTest::newRow("b360-210") << true << 3 << 360 << 210 << AnimState( 90, Running) << AnimState( 30, Running) << AnimState( 0, Stopped); + QTest::newRow("b360-120") << true << 3 << 360 << 120 << AnimState( 0, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped); + + // rewind, direction = Backward + QTest::newRow("b50-110") << true << 3 << 50 << 110 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + QTest::newRow("b50-120") << true << 3 << 50 << 120 << AnimState(100, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped); + QTest::newRow("b50-140") << true << 3 << 50 << 140 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped); + QTest::newRow("b50-240") << true << 3 << 50 << 240 << AnimState(100, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped); + QTest::newRow("b50-260") << true << 3 << 50 << 260 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped); + QTest::newRow("b50-350") << true << 3 << 50 << 350 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + + // infinite looping + QTest::newRow("inf1220") << false << -1 << 0 << 1220 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped); + QTest::newRow("inf1310") << false << -1 << 0 << 1310 << AnimState( 100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + // infinite looping, direction = Backward (will only loop once) + QTest::newRow("b.inf120-120") << true << -1 << 120 << 120 << AnimState( 42, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped); + QTest::newRow("b.inf120-20") << true << -1 << 120 << 20 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped); + QTest::newRow("b.inf120-110") << true << -1 << 120 << 110 << AnimState( 42, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped); + + +} + +void tst_QParallelAnimationGroupJob::loopCount() +{ + QFETCH(bool, directionBackward); + QFETCH(int, setLoopCount); + QFETCH(int, initialGroupTime); + QFETCH(int, currentGroupTime); + QFETCH(AnimState, expected1); + QFETCH(AnimState, expected2); + QFETCH(AnimState, expected3); + + QParallelAnimationGroupJob group; + + TestAnimation anim1(100); + TestAnimation anim2(60); //total 120 + anim2.setLoopCount(2); + TestAnimation anim3(0); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + group.appendAnimation(&anim3); + + group.setLoopCount(setLoopCount); + if (initialGroupTime >= 0) + group.setCurrentTime(initialGroupTime); + if (directionBackward) + group.setDirection(QAbstractAnimationJob::Backward); + + group.start(); + if (initialGroupTime >= 0) + group.setCurrentTime(initialGroupTime); + + anim1.setCurrentTime(42); // 42 is "untouched" + anim2.setCurrentTime(42); + + group.setCurrentTime(currentGroupTime); + + QCOMPARE(anim1.currentLoopTime(), expected1.time); + QCOMPARE(anim2.currentLoopTime(), expected2.time); + QCOMPARE(anim3.currentLoopTime(), expected3.time); + + if (expected1.state >=0) + QCOMPARE(int(anim1.state()), expected1.state); + if (expected2.state >=0) + QCOMPARE(int(anim2.state()), expected2.state); + if (expected3.state >=0) + QCOMPARE(int(anim3.state()), expected3.state); + +} + +void tst_QParallelAnimationGroupJob::addAndRemoveDuration() +{ + QParallelAnimationGroupJob group; + QCOMPARE(group.duration(), 0); + TestAnimation *test = new TestAnimation(250); // 0, duration = 250; + group.appendAnimation(test); + QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(&group)); + QCOMPARE(test->duration(), 250); + QCOMPARE(group.duration(), 250); + + TestAnimation *test2 = new TestAnimation(750); // 1 + group.appendAnimation(test2); + QCOMPARE(test2->group(), static_cast<QAnimationGroupJob*>(&group)); + QCOMPARE(group.duration(), 750); + + TestAnimation *test3 = new TestAnimation(500); // 2 + group.appendAnimation(test3); + QCOMPARE(test3->group(), static_cast<QAnimationGroupJob*>(&group)); + QCOMPARE(group.duration(), 750); + + group.removeAnimation(test2); // remove the one with duration = 750 + delete test2; + QCOMPARE(group.duration(), 500); + + group.removeAnimation(test3); // remove the one with duration = 500 + delete test3; + QCOMPARE(group.duration(), 250); + + group.removeAnimation(test); // remove the last one (with duration = 250) + QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(0)); + QCOMPARE(group.duration(), 0); + delete test; +} + +void tst_QParallelAnimationGroupJob::pauseResume() +{ + QParallelAnimationGroupJob group; + TestAnimation *anim = new TestAnimation(250); // 0, duration = 250; + group.appendAnimation(anim); + StateChangeListener spy; + anim->addAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange); + QCOMPARE(group.duration(), 250); + group.start(); + QTest::qWait(100); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim->state(), QAnimationGroupJob::Running); + QCOMPARE(spy.count(), 1); + spy.clear(); + const int currentTime = group.currentLoopTime(); + QCOMPARE(anim->currentLoopTime(), currentTime); + + group.pause(); + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(group.currentLoopTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroupJob::Paused); + QCOMPARE(anim->currentLoopTime(), currentTime); + QCOMPARE(spy.count(), 1); + spy.clear(); + + group.resume(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(group.currentLoopTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroupJob::Running); + QCOMPARE(anim->currentLoopTime(), currentTime); + QCOMPARE(spy.count(), 1); + + group.stop(); + spy.clear(); + group.appendAnimation(new TestAnimation(500)); + group.start(); + QCOMPARE(spy.count(), 1); //the animation should have been started + QCOMPARE(spy.states.at(0), TestAnimation::Running); + group.setCurrentTime(250); //end of first animation + QCOMPARE(spy.count(), 2); //the animation should have been stopped + QCOMPARE(spy.states.at(1), TestAnimation::Stopped); + group.pause(); + QCOMPARE(spy.count(), 2); //this shouldn't have changed + group.resume(); + QCOMPARE(spy.count(), 2); //this shouldn't have changed +} + +// This is a regression test for QTBUG-8910, where a crash occurred when the +// last animation was removed from a group. +void tst_QParallelAnimationGroupJob::crashWhenRemovingUncontrolledAnimation() +{ + QParallelAnimationGroupJob group; + TestAnimation *anim = new TestAnimation; + anim->setLoopCount(-1); + TestAnimation *anim2 = new TestAnimation; + anim2->setLoopCount(-1); + group.appendAnimation(anim); + group.appendAnimation(anim2); + group.start(); + delete anim; + // it would crash here because the internals of the group would still have a reference to anim + delete anim2; +} + + +QTEST_MAIN(tst_QParallelAnimationGroupJob) +#include "tst_qparallelanimationgroupjob.moc" diff --git a/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro b/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro new file mode 100644 index 0000000000..d2b48a6c74 --- /dev/null +++ b/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +macx:CONFIG -= app_bundle +TARGET = tst_qpauseanimationjob +QT = core-private gui-private declarative-private testlib +SOURCES = tst_qpauseanimationjob.cpp diff --git a/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp new file mode 100644 index 0000000000..9592b4c0f0 --- /dev/null +++ b/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp @@ -0,0 +1,470 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtDeclarative/private/qpauseanimationjob_p.h> +#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h> +#include <QtDeclarative/private/qparallelanimationgroupjob_p.h> + +#ifdef Q_OS_WIN +static const char winTimerError[] = "On windows, consistent timing is not working properly due to bad timer resolution"; +#endif + +class TestablePauseAnimation : public QPauseAnimationJob +{ +public: + TestablePauseAnimation() + : m_updateCurrentTimeCount(0) + { + } + + TestablePauseAnimation(int duration) + : QPauseAnimationJob(duration), m_updateCurrentTimeCount(0) + { + } + + int m_updateCurrentTimeCount; +protected: + void updateCurrentTime(int currentTime) + { + QPauseAnimationJob::updateCurrentTime(currentTime); + ++m_updateCurrentTimeCount; + } +}; + +class TestableGenericAnimation : public QAbstractAnimationJob +{ +public: + TestableGenericAnimation(int duration = 250) : m_duration(duration) {} + int duration() const { return m_duration; } + +private: + int m_duration; +}; + +class EnableConsistentTiming +{ +public: + EnableConsistentTiming() + { + QUnifiedTimer *timer = QUnifiedTimer::instance(); + timer->setConsistentTiming(true); + } + ~EnableConsistentTiming() + { + QUnifiedTimer *timer = QUnifiedTimer::instance(); + timer->setConsistentTiming(false); + } +}; + +class tst_QPauseAnimationJob : 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_QPauseAnimationJob::initTestCase() +{ +// qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); +} + +void tst_QPauseAnimationJob::changeDirectionWhileRunning() +{ + EnableConsistentTiming enabled; + + TestablePauseAnimation animation; + animation.setDuration(400); + animation.start(); + QTest::qWait(100); + QVERIFY(animation.state() == QAbstractAnimationJob::Running); + animation.setDirection(QAbstractAnimationJob::Backward); + QTest::qWait(animation.totalDuration() + 50); + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); +} + +void tst_QPauseAnimationJob::noTimerUpdates_data() +{ + QTest::addColumn<int>("duration"); + QTest::addColumn<int>("loopCount"); + + QTest::newRow("0") << 200 << 1; + QTest::newRow("1") << 160 << 1; + QTest::newRow("2") << 160 << 2; + QTest::newRow("3") << 200 << 3; +} + +void tst_QPauseAnimationJob::noTimerUpdates() +{ + EnableConsistentTiming enabled; + + QFETCH(int, duration); + QFETCH(int, loopCount); + + TestablePauseAnimation animation; + animation.setDuration(duration); + animation.setLoopCount(loopCount); + animation.start(); + QTest::qWait(animation.totalDuration() + 100); + +#ifdef Q_OS_WIN + if (animation.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + const int expectedLoopCount = 1 + loopCount; + +#ifdef Q_OS_WIN + if (animation.m_updateCurrentTimeCount != expectedLoopCount) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(animation.m_updateCurrentTimeCount, expectedLoopCount); +} + +void tst_QPauseAnimationJob::multiplePauseAnimations() +{ + EnableConsistentTiming enabled; + + TestablePauseAnimation animation; + animation.setDuration(200); + + TestablePauseAnimation animation2; + animation2.setDuration(800); + + animation.start(); + animation2.start(); + QTest::qWait(animation.totalDuration() + 100); + +#ifdef Q_OS_WIN + if (animation.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (animation2.state() != QAbstractAnimationJob::Running) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(animation2.state() == QAbstractAnimationJob::Running); + +#ifdef Q_OS_WIN + if (animation.m_updateCurrentTimeCount != 2) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(animation.m_updateCurrentTimeCount, 2); + +#ifdef Q_OS_WIN + if (animation2.m_updateCurrentTimeCount != 2) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(animation2.m_updateCurrentTimeCount, 2); + + QTest::qWait(550); + +#ifdef Q_OS_WIN + if (animation2.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (animation2.m_updateCurrentTimeCount != 3) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(animation2.m_updateCurrentTimeCount, 3); +} + +void tst_QPauseAnimationJob::pauseAndPropertyAnimations() +{ + EnableConsistentTiming enabled; + + TestablePauseAnimation pause; + pause.setDuration(200); + + TestableGenericAnimation animation; + + pause.start(); + + QTest::qWait(100); + animation.start(); + + QVERIFY(animation.state() == QAbstractAnimationJob::Running); + QVERIFY(pause.state() == QAbstractAnimationJob::Running); + QCOMPARE(pause.m_updateCurrentTimeCount, 2); + + QTest::qWait(animation.totalDuration() + 100); + +#ifdef Q_OS_WIN + if (animation.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + QVERIFY(pause.state() == QAbstractAnimationJob::Stopped); + QVERIFY(pause.m_updateCurrentTimeCount > 3); +} + +void tst_QPauseAnimationJob::pauseResume() +{ + TestablePauseAnimation animation; + animation.setDuration(400); + animation.start(); + QVERIFY(animation.state() == QAbstractAnimationJob::Running); + QTest::qWait(200); + animation.pause(); + QVERIFY(animation.state() == QAbstractAnimationJob::Paused); + animation.start(); + QTest::qWait(300); + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (animation.m_updateCurrentTimeCount != 3) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(animation.m_updateCurrentTimeCount, 3); +} + +void tst_QPauseAnimationJob::sequentialPauseGroup() +{ + QSequentialAnimationGroupJob group; + + TestablePauseAnimation animation1(200); + group.appendAnimation(&animation1); + TestablePauseAnimation animation2(200); + group.appendAnimation(&animation2); + TestablePauseAnimation animation3(200); + group.appendAnimation(&animation3); + + group.start(); + QCOMPARE(animation1.m_updateCurrentTimeCount, 1); + QCOMPARE(animation2.m_updateCurrentTimeCount, 0); + QCOMPARE(animation3.m_updateCurrentTimeCount, 0); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(animation1.state() == QAbstractAnimationJob::Running); + QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped); + + group.setCurrentTime(250); + QCOMPARE(animation1.m_updateCurrentTimeCount, 2); + QCOMPARE(animation2.m_updateCurrentTimeCount, 1); + QCOMPARE(animation3.m_updateCurrentTimeCount, 0); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped); + QCOMPARE((QAbstractAnimationJob*)&animation2, group.currentAnimation()); + QVERIFY(animation2.state() == QAbstractAnimationJob::Running); + QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped); + + group.setCurrentTime(500); + QCOMPARE(animation1.m_updateCurrentTimeCount, 2); + QCOMPARE(animation2.m_updateCurrentTimeCount, 2); + QCOMPARE(animation3.m_updateCurrentTimeCount, 1); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped); + QCOMPARE((QAbstractAnimationJob*)&animation3, group.currentAnimation()); + QVERIFY(animation3.state() == QAbstractAnimationJob::Running); + + group.setCurrentTime(750); + + QVERIFY(group.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped); + + QCOMPARE(animation1.m_updateCurrentTimeCount, 2); + QCOMPARE(animation2.m_updateCurrentTimeCount, 2); + QCOMPARE(animation3.m_updateCurrentTimeCount, 2); +} + +void tst_QPauseAnimationJob::sequentialGroupWithPause() +{ + QSequentialAnimationGroupJob group; + + TestableGenericAnimation animation; + group.appendAnimation(&animation); + + TestablePauseAnimation pause; + pause.setDuration(250); + group.appendAnimation(&pause); + + group.start(); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(animation.state() == QAbstractAnimationJob::Running); + QVERIFY(pause.state() == QAbstractAnimationJob::Stopped); + + group.setCurrentTime(300); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + QCOMPARE((QAbstractAnimationJob*)&pause, group.currentAnimation()); + QVERIFY(pause.state() == QAbstractAnimationJob::Running); + + group.setCurrentTime(600); + + QVERIFY(group.state() == QAbstractAnimationJob::Stopped); + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + QVERIFY(pause.state() == QAbstractAnimationJob::Stopped); + + QCOMPARE(pause.m_updateCurrentTimeCount, 2); +} + +void tst_QPauseAnimationJob::multipleSequentialGroups() +{ + EnableConsistentTiming enabled; + + QParallelAnimationGroupJob group; + group.setLoopCount(2); + + QSequentialAnimationGroupJob subgroup1; + group.appendAnimation(&subgroup1); + + TestableGenericAnimation animation(300); + subgroup1.appendAnimation(&animation); + + TestablePauseAnimation pause(200); + subgroup1.appendAnimation(&pause); + + QSequentialAnimationGroupJob subgroup2; + group.appendAnimation(&subgroup2); + + TestableGenericAnimation animation2(200); + subgroup2.appendAnimation(&animation2); + + TestablePauseAnimation pause2(250); + subgroup2.appendAnimation(&pause2); + + QSequentialAnimationGroupJob subgroup3; + group.appendAnimation(&subgroup3); + + TestablePauseAnimation pause3(400); + subgroup3.appendAnimation(&pause3); + + TestableGenericAnimation animation3(200); + subgroup3.appendAnimation(&animation3); + + QSequentialAnimationGroupJob subgroup4; + group.appendAnimation(&subgroup4); + + TestablePauseAnimation pause4(310); + subgroup4.appendAnimation(&pause4); + + TestablePauseAnimation pause5(60); + subgroup4.appendAnimation(&pause5); + + group.start(); + + QVERIFY(group.state() == QAbstractAnimationJob::Running); + QVERIFY(subgroup1.state() == QAbstractAnimationJob::Running); + QVERIFY(subgroup2.state() == QAbstractAnimationJob::Running); + QVERIFY(subgroup3.state() == QAbstractAnimationJob::Running); + QVERIFY(subgroup4.state() == QAbstractAnimationJob::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... + QTest::qWait(group.totalDuration() + 500); + +#ifdef Q_OS_WIN + if (group.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(group.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (subgroup1.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(subgroup1.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (subgroup2.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(subgroup2.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (subgroup3.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(subgroup3.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (subgroup4.state() != QAbstractAnimationJob::Stopped) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QVERIFY(subgroup4.state() == QAbstractAnimationJob::Stopped); + +#ifdef Q_OS_WIN + if (pause5.m_updateCurrentTimeCount != 4) + QEXPECT_FAIL("", winTimerError, Abort); +#endif + QCOMPARE(pause5.m_updateCurrentTimeCount, 4); +} + +void tst_QPauseAnimationJob::zeroDuration() +{ + TestablePauseAnimation animation; + animation.setDuration(0); + animation.start(); + QTest::qWait(animation.totalDuration() + 100); + QVERIFY(animation.state() == QAbstractAnimationJob::Stopped); + QCOMPARE(animation.m_updateCurrentTimeCount, 1); +} + +QTEST_MAIN(tst_QPauseAnimationJob) +#include "tst_qpauseanimationjob.moc" diff --git a/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro b/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro new file mode 100644 index 0000000000..914fc3ca62 --- /dev/null +++ b/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro @@ -0,0 +1,5 @@ +CONFIG += testcase parallel_test +macx:CONFIG -= app_bundle +TARGET = tst_qsequentialanimationgroupjob +QT = core-private declarative-private testlib +SOURCES = tst_qsequentialanimationgroupjob.cpp diff --git a/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp new file mode 100644 index 0000000000..31a1e441c0 --- /dev/null +++ b/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp @@ -0,0 +1,1617 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h> +#include <QtDeclarative/private/qparallelanimationgroupjob_p.h> +#include <QtDeclarative/private/qpauseanimationjob_p.h> + +Q_DECLARE_METATYPE(QAbstractAnimationJob::State) +Q_DECLARE_METATYPE(QAbstractAnimationJob*) + +class tst_QSequentialAnimationGroupJob : public QObject +{ + Q_OBJECT +public Q_SLOTS: + void initTestCase(); + +private slots: + void construction(); + void setCurrentTime(); + void setCurrentTimeWithUncontrolledAnimation(); + void seekingForwards(); + void seekingBackwards(); + void pauseAndResume(); + void restart(); + void looping(); + void startDelay(); + void clearGroup(); + void groupWithZeroDurationAnimations(); + void propagateGroupUpdateToChildren(); + void updateChildrenWithRunningGroup(); + void deleteChildrenWithRunningGroup(); + void startChildrenWithStoppedGroup(); + void stopGroupWithRunningChild(); + void startGroupWithRunningChild(); + void zeroDurationAnimation(); + void stopUncontrolledAnimations(); + void finishWithUncontrolledAnimation(); + void addRemoveAnimation(); + void currentAnimation(); + void currentAnimationWithZeroDuration(); + void insertAnimation(); + void clear(); + void pauseResume(); +}; + +void tst_QSequentialAnimationGroupJob::initTestCase() +{ + qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); + qRegisterMetaType<QAbstractAnimationJob*>("QAbstractAnimationJob*"); +} + +void tst_QSequentialAnimationGroupJob::construction() +{ + QSequentialAnimationGroupJob animationgroup; +} + +class TestAnimation : public QAbstractAnimationJob +{ +public: + TestAnimation(int duration = 250) : m_duration(duration) {} + int duration() const { return m_duration; } + +private: + int m_duration; +}; + +class TestValueAnimation : public TestAnimation +{ +public: + TestValueAnimation(int duration = 250) + : TestAnimation(duration), start(0), end(0), value(0) {} + + void updateCurrentTime(int msecs) + { + if (msecs >= duration()) + value = end; + else + value = start + (end - start) * (qreal(msecs) / duration()); + } + + qreal start, end; + qreal value; +}; + +class UncontrolledAnimation : public QObject, public QAbstractAnimationJob +{ + Q_OBJECT +public: + int duration() const { return -1; /* not time driven */ } + +protected: + void updateCurrentTime(int currentTime) + { + if (currentTime >= 250) + stop(); + } +}; + +class StateChangeListener: public QAnimation2ChangeListener +{ +public: + virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) + { + states << newState; + } + + void clear() { states.clear(); } + int count() const { return states.count(); } + + QList<QAbstractAnimationJob::State> states; +}; + +class FinishedListener: public QAnimation2ChangeListener +{ +public: + FinishedListener() : m_count(0) {} + + virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; } + void clear() { m_count = 0; } + int count() { return m_count; } + +private: + int m_count; +}; + +void tst_QSequentialAnimationGroupJob::setCurrentTime() +{ + // sequence operating on same object/property + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o1 = new TestAnimation; + TestAnimation *a2_s_o1 = new TestAnimation; + TestAnimation *a3_s_o1 = new TestAnimation; + a2_s_o1->setLoopCount(3); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + + // sequence operating on different object/properties + QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o2 = new TestAnimation; + TestAnimation *a1_s_o3 = new TestAnimation; + sequence2->appendAnimation(a1_s_o2); + sequence2->appendAnimation(a1_s_o3); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + group.appendAnimation(sequence2); + + // Current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 250 + group.setCurrentTime(250); + QCOMPARE(group.currentLoopTime(), 250); + QCOMPARE(sequence->currentLoopTime(), 250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 251 + group.setCurrentTime(251); + QCOMPARE(group.currentLoopTime(), 251); + QCOMPARE(sequence->currentLoopTime(), 251); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoop(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 750 + group.setCurrentTime(750); + QCOMPARE(group.currentLoopTime(), 750); + QCOMPARE(sequence->currentLoopTime(), 750); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1000 + group.setCurrentTime(1000); + QCOMPARE(group.currentLoopTime(), 1000); + QCOMPARE(sequence->currentLoopTime(), 1000); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1010 + group.setCurrentTime(1010); + QCOMPARE(group.currentLoopTime(), 1010); + QCOMPARE(sequence->currentLoopTime(), 1010); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 10); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1250 + group.setCurrentTime(1250); + QCOMPARE(group.currentLoopTime(), 1250); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1500 + group.setCurrentTime(1500); + QCOMPARE(group.currentLoopTime(), 1500); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1750 + group.setCurrentTime(1750); + QCOMPARE(group.currentLoopTime(), 1750); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 500); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 250); + + // Current time = 2000 + group.setCurrentTime(2000); + QCOMPARE(group.currentLoopTime(), 1750); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 500); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 250); +} + +void tst_QSequentialAnimationGroupJob::setCurrentTimeWithUncontrolledAnimation() +{ + // sequence operating on different object/properties + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o1 = new TestAnimation; + TestAnimation *a1_s_o2 = new TestAnimation; + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a1_s_o2); + + UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation; + QCOMPARE(notTimeDriven->totalDuration(), -1); + + TestAnimation *loopsForever = new TestAnimation; + loopsForever->setLoopCount(-1); + QCOMPARE(loopsForever->totalDuration(), -1); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + group.appendAnimation(notTimeDriven); + group.appendAnimation(loopsForever); + group.start(); + group.pause(); // this allows the group to listen for the finish signal of its children + + // Current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(notTimeDriven->currentLoopTime(), 0); + QCOMPARE(loopsForever->currentLoopTime(), 0); + + // Current time = 250 + group.setCurrentTime(250); + QCOMPARE(group.currentLoopTime(), 250); + QCOMPARE(sequence->currentLoopTime(), 250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(notTimeDriven->currentLoopTime(), 0); + QCOMPARE(loopsForever->currentLoopTime(), 0); + + // Current time = 500 + group.setCurrentTime(500); + QCOMPARE(group.currentLoopTime(), 500); + QCOMPARE(sequence->currentLoopTime(), 500); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 0); + QCOMPARE(loopsForever->currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven)); + + // Current time = 505 + group.setCurrentTime(505); + QCOMPARE(group.currentLoopTime(), 505); + QCOMPARE(sequence->currentLoopTime(), 500); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 5); + QCOMPARE(loopsForever->currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven)); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Paused); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped); + + // Current time = 750 (end of notTimeDriven animation) + group.setCurrentTime(750); + QCOMPARE(group.currentLoopTime(), 750); + QCOMPARE(sequence->currentLoopTime(), 500); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 250); + QCOMPARE(loopsForever->currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), loopsForever); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Paused); + + // Current time = 800 (as notTimeDriven was finished at 750, loopsforever should still run) + group.setCurrentTime(800); + QCOMPARE(group.currentLoopTime(), 800); + QCOMPARE(group.currentAnimation(), loopsForever); + QCOMPARE(sequence->currentLoopTime(), 500); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(notTimeDriven->currentLoopTime(), 250); + QCOMPARE(loopsForever->currentLoopTime(), 50); + + loopsForever->stop(); // this should stop the group + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::seekingForwards() +{ + + // sequence operating on same object/property + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob; + TestAnimation *a1_s_o1 = new TestAnimation; + TestAnimation *a2_s_o1 = new TestAnimation; + TestAnimation *a3_s_o1 = new TestAnimation; + a2_s_o1->setLoopCount(3); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + + // sequence operating on different object/properties + QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob; + TestAnimation *a1_s_o2 = new TestAnimation; + TestAnimation *a1_s_o3 = new TestAnimation; + sequence2->appendAnimation(a1_s_o2); + sequence2->appendAnimation(a1_s_o3); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + group.appendAnimation(sequence2); + + // Current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // Current time = 1500 + group.setCurrentTime(1500); + QCOMPARE(group.currentLoopTime(), 1500); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 250); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + // this will restart the group + group.start(); + group.pause(); + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped); + + // Current time = 1750 + group.setCurrentTime(1750); + QCOMPARE(group.currentLoopTime(), 1750); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 500); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 250); +} + +void tst_QSequentialAnimationGroupJob::seekingBackwards() +{ + // sequence operating on same object/property + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o1 = new TestAnimation; + TestAnimation *a2_s_o1 = new TestAnimation; + TestAnimation *a3_s_o1 = new TestAnimation; + a2_s_o1->setLoopCount(3); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + + // sequence operating on different object/properties + QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o2 = new TestAnimation; + TestAnimation *a1_s_o3 = new TestAnimation; + sequence2->appendAnimation(a1_s_o2); + sequence2->appendAnimation(a1_s_o3); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + group.appendAnimation(sequence2); + + group.start(); + + // Current time = 1600 + group.setCurrentTime(1600); + QCOMPARE(group.currentLoopTime(), 1600); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 350); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 100); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Running); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Running); + + // Seeking backwards, current time = 1 + group.setCurrentTime(1); + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + + QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," + "hence they don't reset from their current animation", Continue); + QCOMPARE(a2_s_o1->currentLoopTime(), 0); + QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," + "hence they don't reset from their current animation", Continue); + QCOMPARE(a2_s_o1->currentLoop(), 0); + QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," + "hence they don't reset from their current animation", Continue); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence2->currentLoopTime(), 0); + QCOMPARE(a1_s_o2->currentLoopTime(), 0); + QCOMPARE(a1_s_o3->currentLoopTime(), 0); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(sequence->state(), QAnimationGroupJob::Running); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Running); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped); + + // Current time = 2000 + group.setCurrentTime(2000); + QCOMPARE(group.currentLoopTime(), 1750); + QCOMPARE(sequence->currentLoopTime(), 1250); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 2); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + QCOMPARE(sequence2->currentLoopTime(), 500); + QCOMPARE(a1_s_o2->currentLoopTime(), 250); + QCOMPARE(a1_s_o3->currentLoopTime(), 250); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped); +} + +typedef QList<QAbstractAnimationJob::State> StateList; + +static bool compareStates(const StateChangeListener& spy, const StateList &expectedStates) +{ + bool equals = true; + for (int i = 0; i < qMax(expectedStates.count(), spy.count()); ++i) { + if (i >= spy.count() || i >= expectedStates.count()) { + equals = false; + break; + } + QAbstractAnimationJob::State st = expectedStates.at(i); + QAbstractAnimationJob::State actual = spy.states.at(i); + if (equals && actual != st) { + equals = false; + break; + } + } + if (!equals) { + const char *stateStrings[] = {"Stopped", "Paused", "Running"}; + QString e,a; + for (int i = 0; i < qMax(expectedStates.count(), spy.count()); ++i) { + if (i < expectedStates.count()) { + int exp = int(expectedStates.at(i)); + if (!e.isEmpty()) + e += QLatin1String(", "); + e += QLatin1String(stateStrings[exp]); + } + if (i < spy.count()) { + QAbstractAnimationJob::State actual = spy.states.at(i); + if (!a.isEmpty()) + a += QLatin1String(", "); + if (int(actual) >= 0 && int(actual) <= 2) { + a += QLatin1String(stateStrings[int(actual)]); + } else { + a += QLatin1String("NaN"); + } + } + + } + qDebug("\n" + "expected (count == %d): %s\n" + "actual (count == %d): %s\n", expectedStates.count(), qPrintable(e), spy.count(), qPrintable(a)); + } + return equals; +} + +void tst_QSequentialAnimationGroupJob::pauseAndResume() +{ + // sequence operating on same object/property + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + TestAnimation *a1_s_o1 = new TestAnimation; + TestAnimation *a2_s_o1 = new TestAnimation; + TestAnimation *a3_s_o1 = new TestAnimation; + a2_s_o1->setLoopCount(2); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + sequence->setLoopCount(2); + + StateChangeListener a1StateChangedSpy; + a1_s_o1->addAnimationChangeListener(&a1StateChangedSpy, QAbstractAnimationJob::StateChange); + StateChangeListener seqStateChangedSpy; + sequence->addAnimationChangeListener(&seqStateChangedSpy, QAbstractAnimationJob::StateChange); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + + group.start(); + group.pause(); + + // Current time = 1751 + group.setCurrentTime(1751); + QCOMPARE(group.currentLoopTime(), 1751); + QCOMPARE(sequence->currentLoopTime(), 751); + QCOMPARE(sequence->currentLoop(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 1); + QCOMPARE(a3_s_o1->currentLoop(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 1); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused); + + QCOMPARE(a1StateChangedSpy.count(), 5); // Running,Paused,Stopped,Running,Stopped + QCOMPARE(seqStateChangedSpy.count(), 2); // Running,Paused + + QVERIFY(compareStates(a1StateChangedSpy, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Stopped))); + + //### is this the same test as compareStates test above? + QCOMPARE(a1StateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(a1StateChangedSpy.states.at(1), QAnimationGroupJob::Paused); + QCOMPARE(a1StateChangedSpy.states.at(2), QAnimationGroupJob::Stopped); + QCOMPARE(a1StateChangedSpy.states.at(3), QAnimationGroupJob::Running); + QCOMPARE(a1StateChangedSpy.states.at(4), QAnimationGroupJob::Stopped); + + QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Paused); + + group.resume(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(sequence->state(), QAnimationGroupJob::Running); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Running); + + QVERIFY(group.currentLoopTime() >= 1751); + QVERIFY(sequence->currentLoopTime() >= 751); + QCOMPARE(sequence->currentLoop(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 1); + QCOMPARE(a3_s_o1->currentLoop(), 0); + QVERIFY(a3_s_o1->currentLoopTime() >= 1); + + QCOMPARE(seqStateChangedSpy.count(), 3); // Running,Paused,Running + QCOMPARE(seqStateChangedSpy.states.at(2), QAnimationGroupJob::Running); + + group.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused); + + QVERIFY(group.currentLoopTime() >= 1751); + QVERIFY(sequence->currentLoopTime() >= 751); + QCOMPARE(sequence->currentLoop(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 1); + QCOMPARE(a3_s_o1->currentLoop(), 0); + QVERIFY(a3_s_o1->currentLoopTime() >= 1); + + QCOMPARE(seqStateChangedSpy.count(), 4); // Running,Paused,Running,Paused + QCOMPARE(seqStateChangedSpy.states.at(3), QAnimationGroupJob::Paused); + + group.stop(); + + QCOMPARE(seqStateChangedSpy.count(), 5); // Running,Paused,Running,Paused,Stopped + QCOMPARE(seqStateChangedSpy.states.at(4), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::restart() +{ + // originally was sequence operating on same object/property + QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + //### no equivilant signal + //QSignalSpy seqCurrentAnimChangedSpy(sequence, SIGNAL(currentAnimationChanged(QAbstractAnimationJob*))); + + StateChangeListener seqStateChangedSpy; + sequence->addAnimationChangeListener(&seqStateChangedSpy, QAbstractAnimationJob::StateChange); + + TestAnimation *anims[3]; + StateChangeListener *animsStateChanged[3]; + + for (int i = 0; i < 3; i++) { + anims[i] = new TestAnimation(100); + animsStateChanged[i] = new StateChangeListener; + anims[i]->addAnimationChangeListener(animsStateChanged[i], QAbstractAnimationJob::StateChange); + } + + anims[1]->setLoopCount(2); + sequence->appendAnimation(anims[0]); + sequence->appendAnimation(anims[1]); + sequence->appendAnimation(anims[2]); + sequence->setLoopCount(2); + + QSequentialAnimationGroupJob group; + group.appendAnimation(sequence); + + group.start(); + + QTest::qWait(500); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + + QTest::qWait(300); + QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped); + + for (int i = 0; i < 3; i++) { + QCOMPARE(animsStateChanged[i]->count(), 4); + QCOMPARE(animsStateChanged[i]->states.at(0), QAnimationGroupJob::Running); + QCOMPARE(animsStateChanged[i]->states.at(1), QAnimationGroupJob::Stopped); + QCOMPARE(animsStateChanged[i]->states.at(2), QAnimationGroupJob::Running); + QCOMPARE(animsStateChanged[i]->states.at(3), QAnimationGroupJob::Stopped); + } + + QCOMPARE(seqStateChangedSpy.count(), 2); + QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Stopped); + + //QCOMPARE(seqCurrentAnimChangedSpy.count(), 6); + //for(int i=0; i<seqCurrentAnimChangedSpy.count(); i++) + // QCOMPARE(static_cast<QAbstractAnimationJob*>(anims[i%3]), qVariantValue<QAbstractAnimationJob*>(seqCurrentAnimChangedSpy.at(i).at(0))); + + group.start(); + + QCOMPARE(animsStateChanged[0]->count(), 5); + QCOMPARE(animsStateChanged[1]->count(), 4); + QCOMPARE(animsStateChanged[2]->count(), 4); + QCOMPARE(seqStateChangedSpy.count(), 3); +} + +void tst_QSequentialAnimationGroupJob::looping() +{ + // originally was sequence operating on same object/property + QSequentialAnimationGroupJob *sequence = new QSequentialAnimationGroupJob(); + QAbstractAnimationJob *a1_s_o1 = new TestAnimation; + QAbstractAnimationJob *a2_s_o1 = new TestAnimation; + QAbstractAnimationJob *a3_s_o1 = new TestAnimation; + + StateChangeListener a1Spy; + a1_s_o1->addAnimationChangeListener(&a1Spy, QAbstractAnimationJob::StateChange); + StateChangeListener a2Spy; + a2_s_o1->addAnimationChangeListener(&a2Spy, QAbstractAnimationJob::StateChange); + StateChangeListener a3Spy; + a3_s_o1->addAnimationChangeListener(&a3Spy, QAbstractAnimationJob::StateChange); + StateChangeListener seqSpy; + sequence->addAnimationChangeListener(&seqSpy, QAbstractAnimationJob::StateChange); + + a2_s_o1->setLoopCount(2); + sequence->appendAnimation(a1_s_o1); + sequence->appendAnimation(a2_s_o1); + sequence->appendAnimation(a3_s_o1); + sequence->setLoopCount(2); + + QSequentialAnimationGroupJob group; + StateChangeListener groupSpy; + group.addAnimationChangeListener(&groupSpy, QAbstractAnimationJob::StateChange); + + group.appendAnimation(sequence); + group.setLoopCount(2); + + group.start(); + group.pause(); + + // Current time = 1750 + group.setCurrentTime(1750); + QCOMPARE(group.currentLoopTime(), 1750); + QCOMPARE(sequence->currentLoopTime(), 750); + QCOMPARE(sequence->currentLoop(), 1); + QCOMPARE(a1_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 1); + // this animation is at the beginning because it is the current one inside sequence + QCOMPARE(a3_s_o1->currentLoop(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 0); + QCOMPARE(sequence->currentAnimation(), a3_s_o1); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused); + + QCOMPARE(a1Spy.count(), 5); // Running,Paused,Stopped,Running,Stopped + QVERIFY(compareStates(a1Spy, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Stopped))); + + QCOMPARE(a2Spy.count(), 4); // Running,Stopped,Running,Stopped + QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused))); + + QCOMPARE(seqSpy.count(), 2); // Running,Paused + QCOMPARE(groupSpy.count(), 2); // Running,Paused + + // Looping, current time = duration + 1 + group.setCurrentTime(group.duration() + 1); + QCOMPARE(group.currentLoopTime(), 1); + QCOMPARE(group.currentLoop(), 1); + QCOMPARE(sequence->currentLoopTime(), 1); + QCOMPARE(sequence->currentLoop(), 0); + QCOMPARE(a1_s_o1->currentLoopTime(), 1); + QCOMPARE(a2_s_o1->currentLoopTime(), 250); + QCOMPARE(a2_s_o1->currentLoop(), 1); + // this animation is at the end because it was run on the previous loop + QCOMPARE(a3_s_o1->currentLoop(), 0); + QCOMPARE(a3_s_o1->currentLoopTime(), 250); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(sequence->state(), QAnimationGroupJob::Paused); + QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused); + QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Stopped); + + QCOMPARE(a1Spy.count(), 7); // Running,Paused,Stopped,Running,Stopped,Running,Stopped + QCOMPARE(a2Spy.count(), 4); // Running, Stopped, Running, Stopped + QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused + << QAbstractAnimationJob::Stopped))); + QVERIFY(compareStates(seqSpy, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused))); + QCOMPARE(groupSpy.count(), 2); + + //cleanup + a1_s_o1->removeAnimationChangeListener(&a1Spy, QAbstractAnimationJob::StateChange); + a2_s_o1->removeAnimationChangeListener(&a2Spy, QAbstractAnimationJob::StateChange); + a3_s_o1->removeAnimationChangeListener(&a3Spy, QAbstractAnimationJob::StateChange); + sequence->removeAnimationChangeListener(&seqSpy, QAbstractAnimationJob::StateChange); + group.removeAnimationChangeListener(&groupSpy, QAbstractAnimationJob::StateChange); +} + +void tst_QSequentialAnimationGroupJob::startDelay() +{ + QSequentialAnimationGroupJob group; + group.appendAnimation(new QPauseAnimationJob(250)); + group.appendAnimation(new QPauseAnimationJob(125)); + QCOMPARE(group.totalDuration(), 375); + + group.start(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + + QTest::qWait(500); + + QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped); + QVERIFY(group.currentLoopTime() == 375); +} + +void tst_QSequentialAnimationGroupJob::clearGroup() +{ + QSequentialAnimationGroupJob group; + + static const int animationCount = 20; + + for (int i = 0; i < animationCount/2; ++i) { + QSequentialAnimationGroupJob *subGroup = new QSequentialAnimationGroupJob; + group.appendAnimation(subGroup); + group.appendAnimation(new QPauseAnimationJob(100)); + subGroup->appendAnimation(new QPauseAnimationJob(10)); + } + + int count = 0; + for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling()) + ++count; + QCOMPARE(count, animationCount); + + group.clear(); + + QVERIFY(!group.firstChild() && !group.lastChild()); + QCOMPARE(group.currentLoopTime(), 0); +} + +void tst_QSequentialAnimationGroupJob::groupWithZeroDurationAnimations() +{ + QSequentialAnimationGroupJob group; + + TestValueAnimation *a1 = new TestValueAnimation(0); + a1->start = 42; + a1->end = 43; + group.appendAnimation(a1); + + //this should just run fine and change nothing + group.setCurrentTime(0); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(a1)); + + TestValueAnimation *a2 = new TestValueAnimation(500); + a2->start = 13; + a2->end = 31; + group.appendAnimation(a2); + + TestValueAnimation *a3 = new TestValueAnimation(0); + a3->start = 43; + a3->end = 44; + group.appendAnimation(a3); + + TestValueAnimation *a4 = new TestValueAnimation(250); + a4->start = 13; + a4->end = 75; + group.appendAnimation(a4); + + TestValueAnimation *a5 = new TestValueAnimation(0); + a5->start = 42; + a5->end = 12; + group.appendAnimation(a5); + + QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want? + QCOMPARE((int)a2->value, 0); + QCOMPARE((int)a3->value, 0); + QCOMPARE((int)a4->value, 0); + QCOMPARE((int)a5->value, 0); + + group.start(); + + QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want? + QCOMPARE((int)a2->value, 13); + QCOMPARE((int)a3->value, 0); + QCOMPARE((int)a4->value, 0); + QCOMPARE((int)a5->value, 0); + + QTest::qWait(100); + + QCOMPARE((int)a1->value, 43); + QVERIFY(a2->value > 13 && a2->value < 31); + QCOMPARE((int)a3->value, 0); + QCOMPARE((int)a4->value, 0); + QCOMPARE((int)a5->value, 0); + + QTest::qWait(500); + + QTRY_COMPARE((int)a3->value, 44); + QCOMPARE((int)a1->value, 43); + QCOMPARE((int)a2->value, 31); + //QCOMPARE((int)a4->value, 36); + QCOMPARE((int)a5->value, 0); + QCOMPARE(a1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a4->state(), QAnimationGroupJob::Running); + QCOMPARE(a5->state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QTest::qWait(500); + + QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE((int)a1->value, 43); + QCOMPARE((int)a2->value, 31); + QCOMPARE((int)a3->value, 44); + QCOMPARE((int)a4->value, 75); + QCOMPARE((int)a5->value, 12); + QCOMPARE(a1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a2->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a3->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a4->state(), QAnimationGroupJob::Stopped); + QCOMPARE(a5->state(), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::propagateGroupUpdateToChildren() +{ + // this test verifies if group state changes are updating its children correctly + QSequentialAnimationGroupJob group; + + TestAnimation anim1(100); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + group.start(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(anim1.state(), QAnimationGroupJob::Paused); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::updateChildrenWithRunningGroup() +{ + // assert that its possible to modify a child's state directly while their group is running + QSequentialAnimationGroupJob group; + + TestAnimation anim(200); + + StateChangeListener groupStateChangedSpy; + group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange); + StateChangeListener childStateChangedSpy; + anim.addAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange); + + QCOMPARE(groupStateChangedSpy.count(), 0); + QCOMPARE(childStateChangedSpy.count(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim); + + group.start(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Running); + + QCOMPARE(groupStateChangedSpy.count(), 1); + QCOMPARE(childStateChangedSpy.count(), 1); + + QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(childStateChangedSpy.states.at(0), QAnimationGroupJob::Running); + + // starting directly a running child will not have any effect + anim.start(); + + QCOMPARE(groupStateChangedSpy.count(), 1); + QCOMPARE(childStateChangedSpy.count(), 1); + + anim.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Paused); + + // in the animation stops directly, the group will still be running + anim.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Stopped); + + //cleanup + group.removeAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange); + anim.removeAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange); +} + +void tst_QSequentialAnimationGroupJob::deleteChildrenWithRunningGroup() +{ + // test if children can be activated when their group is stopped + QSequentialAnimationGroupJob group; + + TestAnimation *anim1 = new TestAnimation(200); + group.appendAnimation(anim1); + + QCOMPARE(group.duration(), anim1->duration()); + + group.start(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1->state(), QAnimationGroupJob::Running); + + QTest::qWait(100); + QTRY_VERIFY(group.currentLoopTime() > 0); + + delete anim1; + QVERIFY(!group.firstChild()); + QCOMPARE(group.duration(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.currentLoopTime(), 0); //that's the invariant +} + +void tst_QSequentialAnimationGroupJob::startChildrenWithStoppedGroup() +{ + // test if children can be activated when their group is stopped + QSequentialAnimationGroupJob group; + + TestAnimation anim1(200); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + anim1.start(); + anim2.start(); + anim2.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); +} + +void tst_QSequentialAnimationGroupJob::stopGroupWithRunningChild() +{ + // children that started independently will not be affected by a group stop + QSequentialAnimationGroupJob group; + + TestAnimation anim1(200); + TestAnimation anim2(200); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(&anim1); + group.appendAnimation(&anim2); + + anim1.start(); + anim2.start(); + anim2.pause(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Running); + QCOMPARE(anim2.state(), QAnimationGroupJob::Paused); + + anim1.stop(); + anim2.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::startGroupWithRunningChild() +{ + // as the group has precedence over its children, starting a group will restart all the children + QSequentialAnimationGroupJob group; + + TestAnimation *anim1 = new TestAnimation(200); + TestAnimation *anim2 = new TestAnimation(200); + + StateChangeListener stateChangedSpy1; + anim1->addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + StateChangeListener stateChangedSpy2; + anim2->addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); + + QCOMPARE(stateChangedSpy1.count(), 0); + QCOMPARE(stateChangedSpy2.count(), 0); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped); + + group.appendAnimation(anim1); + group.appendAnimation(anim2); + + anim1->start(); + anim2->start(); + anim2->pause(); + + QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running))); + + QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused))); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1->state(), QAnimationGroupJob::Running); + QCOMPARE(anim2->state(), QAnimationGroupJob::Paused); + + group.start(); + + QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Stopped + << QAbstractAnimationJob::Running))); + QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running + << QAbstractAnimationJob::Paused))); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1->state(), QAnimationGroupJob::Running); + QCOMPARE(anim2->state(), QAnimationGroupJob::Paused); + + QTest::qWait(300); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2->state(), QAnimationGroupJob::Running); + + QCOMPARE(stateChangedSpy2.count(), 4); + QCOMPARE(stateChangedSpy2.states.at(2), QAnimationGroupJob::Stopped); + QCOMPARE(stateChangedSpy2.states.at(3), QAnimationGroupJob::Running); + + group.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped); + + anim1->removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange); + anim2->removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange); +} + +void tst_QSequentialAnimationGroupJob::zeroDurationAnimation() +{ + QSequentialAnimationGroupJob group; + + TestAnimation *anim1 = new TestAnimation(0); + TestAnimation *anim2 = new TestAnimation(100); + TestValueAnimation *anim3 = new TestValueAnimation(0); + anim3->end = 100; + + StateChangeListener stateChangedSpy; + anim1->addAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange); + + group.appendAnimation(anim1); + group.appendAnimation(anim2); + group.appendAnimation(anim3); + group.setLoopCount(2); + group.start(); + + QCOMPARE(stateChangedSpy.count(), 2); + QCOMPARE(stateChangedSpy.states.at(0), QAnimationGroupJob::Running); + QCOMPARE(stateChangedSpy.states.at(1), QAnimationGroupJob::Stopped); + + QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2->state(), QAnimationGroupJob::Running); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + + //now let's try to seek to the next loop + group.setCurrentTime(group.duration() + 1); + QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim2->state(), QAnimationGroupJob::Running); + QCOMPARE(anim3->state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + //TODO: test that anim3 was run + QCOMPARE(anim3->value, qreal(100)); //anim3 should have been run + + anim1->removeAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange); +} + +void tst_QSequentialAnimationGroupJob::stopUncontrolledAnimations() +{ + QSequentialAnimationGroupJob group; + + UncontrolledAnimation notTimeDriven; + QCOMPARE(notTimeDriven.totalDuration(), -1); + + TestAnimation loopsForever(100); + loopsForever.setLoopCount(-1); + + group.appendAnimation(¬TimeDriven); + group.appendAnimation(&loopsForever); + + group.start(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped); + + notTimeDriven.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running); + + loopsForever.stop(); + + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped); +} + +void tst_QSequentialAnimationGroupJob::finishWithUncontrolledAnimation() +{ + //1st case: + //first we test a group with one uncontrolled animation + QSequentialAnimationGroupJob group; + UncontrolledAnimation notTimeDriven; + group.appendAnimation(¬TimeDriven); + FinishedListener spy; + group.addAnimationChangeListener(&spy, QAbstractAnimationJob::Completion); + + group.start(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running); + QCOMPARE(group.currentLoopTime(), 0); + QCOMPARE(notTimeDriven.currentLoopTime(), 0); + + QTest::qWait(300); //wait for the end of notTimeDriven + QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + const int actualDuration = notTimeDriven.currentLoopTime(); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.currentLoopTime(), actualDuration); + QCOMPARE(spy.count(), 1); + + //2nd case: + // lets make sure the seeking will work again + spy.clear(); + TestAnimation anim; + group.appendAnimation(&anim); + StateChangeListener animStateChangedSpy; + anim.addAnimationChangeListener(&animStateChangedSpy, QAbstractAnimationJob::StateChange); + + group.setCurrentTime(300); + QCOMPARE(group.state(), QAnimationGroupJob::Stopped); + QCOMPARE(notTimeDriven.currentLoopTime(), actualDuration); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim)); + + //3rd case: + //now let's add a perfectly defined animation at the end + QCOMPARE(animStateChangedSpy.count(), 0); + group.start(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running); + QCOMPARE(group.currentLoopTime(), 0); + QCOMPARE(notTimeDriven.currentLoopTime(), 0); + + QCOMPARE(animStateChangedSpy.count(), 0); + + QTest::qWait(300); //wait for the end of notTimeDriven + QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim.state(), QAnimationGroupJob::Running); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim)); + QCOMPARE(animStateChangedSpy.count(), 1); + QTest::qWait(300); //wait for the end of anim + + QTRY_COMPARE(anim.state(), QAnimationGroupJob::Stopped); + QCOMPARE(anim.currentLoopTime(), anim.duration()); + + //we should simply be at the end + QCOMPARE(spy.count(), 1); + QCOMPARE(animStateChangedSpy.count(), 2); + QCOMPARE(group.currentLoopTime(), notTimeDriven.currentLoopTime() + anim.currentLoopTime()); + + //cleanup + group.removeAnimationChangeListener(&spy, QAbstractAnimationJob::Completion); + anim.removeAnimationChangeListener(&animStateChangedSpy, QAbstractAnimationJob::StateChange); +} + +void tst_QSequentialAnimationGroupJob::addRemoveAnimation() +{ + //this test is specific to the sequential animation group + QSequentialAnimationGroupJob group; + + QCOMPARE(group.duration(), 0); + QCOMPARE(group.currentLoopTime(), 0); + QAbstractAnimationJob *anim1 = new TestAnimation; + group.appendAnimation(anim1); + QCOMPARE(group.duration(), 250); + QCOMPARE(group.currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), anim1); + + //let's append an animation + QAbstractAnimationJob *anim2 = new TestAnimation; + group.appendAnimation(anim2); + QCOMPARE(group.duration(), 500); + QCOMPARE(group.currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), anim1); + + //let's prepend an animation + QAbstractAnimationJob *anim0 = new TestAnimation; + group.prependAnimation(anim0); + QCOMPARE(group.duration(), 750); + QCOMPARE(group.currentLoopTime(), 0); + QCOMPARE(group.currentAnimation(), anim0); //anim0 has become the new currentAnimation + + group.setCurrentTime(300); //anim0 | anim1 | anim2 + QCOMPARE(group.currentLoopTime(), 300); + QCOMPARE(group.currentAnimation(), anim1); + QCOMPARE(anim1->currentLoopTime(), 50); + + group.removeAnimation(anim0); //anim1 | anim2 + QCOMPARE(group.currentLoopTime(), 50); + QCOMPARE(group.currentAnimation(), anim1); + QCOMPARE(anim1->currentLoopTime(), 50); + + group.setCurrentTime(0); + group.prependAnimation(anim0); //anim0 | anim1 | anim2 + group.setCurrentTime(300); + QCOMPARE(group.currentLoopTime(), 300); + QCOMPARE(group.currentAnimation(), anim1); + QCOMPARE(anim1->currentLoopTime(), 50); + + group.removeAnimation(anim1); //anim0 | anim2 + QCOMPARE(group.currentLoopTime(), 250); + QCOMPARE(group.currentAnimation(), anim2); + QCOMPARE(anim0->currentLoopTime(), 250); +} + +void tst_QSequentialAnimationGroupJob::currentAnimation() +{ + QSequentialAnimationGroupJob group; + QVERIFY(group.currentAnimation() == 0); + + TestAnimation anim(0); + group.appendAnimation(&anim); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim)); +} + +void tst_QSequentialAnimationGroupJob::currentAnimationWithZeroDuration() +{ + QSequentialAnimationGroupJob group; + QVERIFY(group.currentAnimation() == 0); + + TestAnimation zero1(0); + TestAnimation zero2(0); + + TestAnimation anim; + + TestAnimation zero3(0); + TestAnimation zero4(0); + + group.appendAnimation(&zero1); + group.appendAnimation(&zero2); + group.appendAnimation(&anim); + group.appendAnimation(&zero3); + group.appendAnimation(&zero4); + + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1)); + + group.setCurrentTime(0); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim)); + + group.setCurrentTime(group.duration()); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero4)); + + group.setDirection(QAbstractAnimationJob::Backward); + + group.setCurrentTime(0); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1)); + + group.setCurrentTime(group.duration()); + QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim)); +} + +void tst_QSequentialAnimationGroupJob::insertAnimation() +{ + QSequentialAnimationGroupJob group; + group.setLoopCount(2); + TestAnimation *anim = new TestAnimation; + group.appendAnimation(anim); + QCOMPARE(group.duration(), anim->duration()); + group.setCurrentTime(300); + QCOMPARE(group.currentLoop(), 1); + + //this will crash if the sequential group calls duration on the created animation + group.appendAnimation(new TestAnimation); +} + +class ClearFinishedListener: public QAnimation2ChangeListener +{ +public: + ClearFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {} + + virtual void animationFinished(QAbstractAnimationJob *) + { + group->clear(); + } + + QSequentialAnimationGroupJob *group; +}; + +class RefillFinishedListener: public QAnimation2ChangeListener +{ +public: + RefillFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {} + + virtual void animationFinished(QAbstractAnimationJob *) + { + group->stop(); + group->clear(); + group->appendAnimation(new TestAnimation); + group->start(); + } + + QSequentialAnimationGroupJob *group; +}; + +void tst_QSequentialAnimationGroupJob::clear() +{ + QSKIP("deleting an animation when finished is not currently supported"); + QSequentialAnimationGroupJob group; + TestAnimation *anim1 = new TestAnimation; + group.appendAnimation(anim1); + ClearFinishedListener clearListener(&group); + anim1->addAnimationChangeListener(&clearListener, QAbstractAnimationJob::Completion); + + TestAnimation *anim2 = new TestAnimation; + group.appendAnimation(anim2); + QCOMPARE(group.firstChild(), anim1); + QCOMPARE(group.lastChild(), anim2); + + group.start(); + QTest::qWait(anim1->duration() + 100); + QTRY_VERIFY(!group.firstChild()); + QCOMPARE(group.state(), QAbstractAnimationJob::Stopped); + QCOMPARE(group.currentLoopTime(), 0); + + anim1 = new TestAnimation; + group.appendAnimation(anim1); + RefillFinishedListener refillListener(&group); + anim1->addAnimationChangeListener(&refillListener, QAbstractAnimationJob::Completion); + group.start(); + QTest::qWait(anim1->duration() + 100); + QTRY_COMPARE(group.state(), QAbstractAnimationJob::Running); +} + +void tst_QSequentialAnimationGroupJob::pauseResume() +{ + QParallelAnimationGroupJob group; + TestAnimation *anim = new TestAnimation; + group.appendAnimation(anim); + StateChangeListener spy; + anim->addAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange); + QCOMPARE(group.duration(), 250); + group.start(); + QTest::qWait(100); + QTRY_COMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(anim->state(), QAnimationGroupJob::Running); + QCOMPARE(spy.count(), 1); + spy.clear(); + const int currentTime = group.currentLoopTime(); + QCOMPARE(anim->currentLoopTime(), currentTime); + + group.pause(); + QCOMPARE(group.state(), QAnimationGroupJob::Paused); + QCOMPARE(group.currentLoopTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroupJob::Paused); + QCOMPARE(anim->currentLoopTime(), currentTime); + QCOMPARE(spy.count(), 1); + spy.clear(); + + group.resume(); + QCOMPARE(group.state(), QAnimationGroupJob::Running); + QCOMPARE(group.currentLoopTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroupJob::Running); + QCOMPARE(anim->currentLoopTime(), currentTime); + QCOMPARE(spy.count(), 1); + + anim->removeAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange); +} + +QTEST_MAIN(tst_QSequentialAnimationGroupJob) +#include "tst_qsequentialanimationgroupjob.moc" diff --git a/tests/auto/declarative/debugger/shared/debugutil.cpp b/tests/auto/declarative/debugger/shared/debugutil.cpp index a8c50748e2..de04c336bb 100644 --- a/tests/auto/declarative/debugger/shared/debugutil.cpp +++ b/tests/auto/declarative/debugger/shared/debugutil.cpp @@ -74,7 +74,6 @@ void QDeclarativeDebugTestService::statusChanged(Status) emit statusHasChanged(); } - QDeclarativeDebugTestClient::QDeclarativeDebugTestClient(const QString &s, QDeclarativeDebugConnection *c) : QDeclarativeDebugClient(s, c) { diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 6780a87f55..7288da27ba 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -27,6 +27,7 @@ PUBLICTESTS += \ qmlplugindump PRIVATETESTS += \ + animation \ qdeclarativebinding \ qdeclarativechangeset \ qdeclarativeconnection \ diff --git a/tests/auto/declarative/qdeclarativeanimations/data/reverse.qml b/tests/auto/declarative/qdeclarativeanimations/data/reverse.qml new file mode 100644 index 0000000000..c8624a6013 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeanimations/data/reverse.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 50 + + Rectangle { + id: myRectangle + width: 50 + height: 50 + color: "green" + x: 10 + } + + states: [ + State { + name: "moved" + PropertyChanges { + target: myRectangle + x: 100 + } + } + ] + + transitions: Transition { NumberAnimation { properties: "x" } } + + MouseArea { + anchors.fill: parent + onPressed: parent.state = "moved" + onReleased: parent.state = "" + } +} diff --git a/tests/auto/qtquick2/qdeclarativeanimationcontroller/data/tst_numberanimation.qml b/tests/auto/qtquick2/qdeclarativeanimationcontroller/data/tst_numberanimation.qml new file mode 100644 index 0000000000..7c4496b206 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimationcontroller/data/tst_numberanimation.qml @@ -0,0 +1,38 @@ +import QtQuick 2.0 +import QtTest 1.0 + +Rectangle { + id:container + width:50 + height:50 + + Rectangle {id:rect; x:0; y:0; color:"red"; width:10; height:10} + AnimationController { + id:numberAnimationcontroller + progress:1 + animation: NumberAnimation {target: rect; property: "x"; from:0; to:40; duration: 1000} + } + + TestCase { + name:"AnimationController" + when:windowShown + function test_numberAnimation() { + numberAnimationcontroller.progress = 0; + compare(rect.x, 0); + numberAnimationcontroller.progress = 0.5; + compare(rect.x, 20); + + // <=0 -> 0 + numberAnimationcontroller.progress = -1; + compare(rect.x, 0); + + //>=1 -> 1 + numberAnimationcontroller.progress = 1.1; + compare(rect.x, 40); + + //make sure the progress can be set backward + numberAnimationcontroller.progress = 0.5; + compare(rect.x, 20); + } + } +}
\ No newline at end of file diff --git a/tests/auto/qtquick2/qdeclarativeanimationcontroller/qdeclarativeanimationcontroller.pro b/tests/auto/qtquick2/qdeclarativeanimationcontroller/qdeclarativeanimationcontroller.pro new file mode 100644 index 0000000000..487641d6c1 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimationcontroller/qdeclarativeanimationcontroller.pro @@ -0,0 +1,10 @@ +QT += core-private gui-private declarative-private widgets +TEMPLATE=app +TARGET=tst_qdeclarativeanimationcontroller + +CONFIG += warn_on qmltestcase +SOURCES += tst_qdeclarativeanimationcontroller.cpp + +importFiles.files = data +importFiles.path = . +DEPLOYMENT += importFiles diff --git a/tests/auto/qtquick2/qdeclarativeanimationcontroller/tst_qdeclarativeanimationcontroller.cpp b/tests/auto/qtquick2/qdeclarativeanimationcontroller/tst_qdeclarativeanimationcontroller.cpp new file mode 100644 index 0000000000..5813090486 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimationcontroller/tst_qdeclarativeanimationcontroller.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtQuickTest/quicktest.h> +QUICK_TEST_MAIN(qdeclarativeanimationcontroller)
\ No newline at end of file diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/looping.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/looping.qml new file mode 100644 index 0000000000..a3d40ae837 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/looping.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +Item { + width: 200; height: 200 + + Rectangle { + x: 50; y: 50; width: 50; height: 50; color: "red" + + SequentialAnimation on rotation { + NumberAnimation { + from: 0; to: 90; duration: 100 + loops: 3 + } + } + } +} diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/pathAnimation2.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/pathAnimation2.qml index 951c5b2e57..2f64dac2cc 100644 --- a/tests/auto/qtquick2/qdeclarativeanimations/data/pathAnimation2.qml +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/pathAnimation2.qml @@ -15,8 +15,8 @@ Rectangle { target: redRect duration: 100; endRotation: 0 - orientationEntryInterval: .1 - orientationExitInterval: .1 + orientationEntryDuration: 10 + orientationExitDuration: 10 orientation: PathAnimation.RightFirst path: Path { startX: 50; startY: 50 diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml new file mode 100644 index 0000000000..eb3d4c3f86 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +PathInterpolator { + path: Path { + startX: 200; startY: 280 + PathCurve { x: 150; y: 280 } + PathCurve { x: 150; y: 80 } + PathCurve { x: 0; y: 80 } + } +} diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/reanchor.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/reanchor.qml new file mode 100644 index 0000000000..241cc81a96 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/reanchor.qml @@ -0,0 +1,46 @@ +import QtQuick 2.0 + +Rectangle { + id: container + width: 200; height: 200 + Rectangle { + id: myRect + color: "green"; + anchors.left: parent.left + anchors.right: rightGuideline.left + anchors.top: topGuideline.top + anchors.bottom: container.bottom + } + Item { id: leftGuideline; x: 10 } + Item { id: rightGuideline; x: 150 } + Item { id: topGuideline; y: 10 } + Item { id: bottomGuideline; y: 150 } + Item { id: topGuideline2; y: 50 } + Item { id: bottomGuideline2; y: 175 } + + states: [ State { + name: "reanchored" + AnchorChanges { + target: myRect; + anchors.left: leftGuideline.left + anchors.right: container.right + anchors.top: container.top + anchors.bottom: bottomGuideline.bottom + } + }, State { + name: "reanchored2" + AnchorChanges { + target: myRect; + anchors.left: undefined + anchors.right: undefined + anchors.top: topGuideline2.top + anchors.bottom: bottomGuideline2.bottom + } + }] + + transitions: Transition { + AnchorAnimation { } + } + + state: "reanchored" +} diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/reparent.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/reparent.qml new file mode 100644 index 0000000000..39f1e7a6d2 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/reparent.qml @@ -0,0 +1,56 @@ +import QtQuick 2.0 + +Rectangle { + width: 400; + height: 240; + color: "black"; + + Rectangle { + id: gr + objectName: "target" + color: "green" + width: 50; height: 50 + } + + Rectangle { + id: np + objectName: "newParent" + x: 150 + width: 150; height: 150 + color: "yellow" + clip: true + Rectangle { + color: "red" + x: 50; y: 50; height: 50; width: 50 + } + + } + + Rectangle { + id: vp + objectName: "viaParent" + x: 100; y: 100 + width: 50; height: 50 + color: "blue" + rotation: 45 + scale: 2 + } + + states: State { + name: "state1" + ParentChange { + target: gr + parent: np + x: 50; y: 50; width: 100; + } + } + + transitions: Transition { + reversible: true + to: "state1" + ParentAnimation { + target: gr; via: vp; + NumberAnimation { properties: "x,y,rotation,scale,width" } + } + } +} diff --git a/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp b/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp index f58010998f..b2c07526ff 100644 --- a/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp +++ b/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp @@ -42,13 +42,13 @@ #include <QtDeclarative/qdeclarativeengine.h> #include <QtDeclarative/qdeclarativecomponent.h> #include <QtQuick/qquickview.h> +#include <QtDeclarative/private/qanimationgroupjob_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qdeclarativeanimation_p.h> #include <QtQuick/private/qdeclarativetransition_p.h> #include <QtQuick/private/qquickanimation_p.h> #include <QtQuick/private/qdeclarativepathinterpolator_p.h> #include <QtQuick/private/qquickitem_p.h> -#include <QVariantAnimation> #include <QEasingCurve> #include <limits.h> @@ -74,6 +74,8 @@ private slots: void simpleColor(); void simpleRotation(); void simplePath(); + void simpleAnchor(); + void reparent(); void pathInterpolator(); void pathInterpolatorBackwardJump(); void pathWithNoStart(); @@ -102,6 +104,7 @@ private slots: void transitionAssignmentBug(); void pauseBindingBug(); void pauseBug(); + void loopingBug(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -130,8 +133,8 @@ void tst_qdeclarativeanimations::simpleProperty() rect.setPos(QPointF(0,0)); animation.start(); - animation.pause(); QVERIFY(animation.isRunning()); + animation.pause(); QVERIFY(animation.isPaused()); animation.setCurrentTime(125); QVERIFY(animation.currentTime() == 125); @@ -239,6 +242,9 @@ void tst_qdeclarativeanimations::simplePath() QQuickPathAnimation *pathAnim = rect->findChild<QQuickPathAnimation*>(); QVERIFY(pathAnim); + QCOMPARE(pathAnim->duration(), 100); + QCOMPARE(pathAnim->target(), redRect); + pathAnim->start(); pathAnim->pause(); @@ -262,6 +268,8 @@ void tst_qdeclarativeanimations::simplePath() pathAnim->start(); QTRY_VERIFY(redRect->rotation() != 0); pathAnim->stop(); + + delete rect; } { @@ -276,6 +284,9 @@ void tst_qdeclarativeanimations::simplePath() QVERIFY(pathAnim); QCOMPARE(pathAnim->orientation(), QQuickPathAnimation::RightFirst); + QCOMPARE(pathAnim->endRotation(), qreal(0)); + QCOMPARE(pathAnim->orientationEntryDuration(), 10); + QCOMPARE(pathAnim->orientationExitDuration(), 10); pathAnim->start(); pathAnim->pause(); @@ -292,9 +303,136 @@ void tst_qdeclarativeanimations::simplePath() QCOMPARE(redRect->x(), qreal(300)); QCOMPARE(redRect->y(), qreal(300)); QCOMPARE(redRect->rotation(), qreal(0)); + + delete rect; } } +void tst_qdeclarativeanimations::simpleAnchor() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, testFileUrl("reanchor.qml")); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect); + + QQuickRectangle *greenRect = rect->findChild<QQuickRectangle*>(); + QVERIFY(greenRect); + + QCOMPARE(rect->state(), QLatin1String("reanchored")); + QCOMPARE(greenRect->x(), qreal(10)); + QCOMPARE(greenRect->y(), qreal(0)); + QCOMPARE(greenRect->width(), qreal(190)); + QCOMPARE(greenRect->height(), qreal(150)); + + rect->setState(""); + + //verify animation in progress + QTRY_VERIFY(greenRect->x() < 10 && greenRect->x() > 0); + QVERIFY(greenRect->y() > 0 && greenRect->y() < 10); + QVERIFY(greenRect->width() < 190 && greenRect->width() > 150); + QVERIFY(greenRect->height() > 150 && greenRect->height() < 190); + + //verify end state ("") + QTRY_COMPARE(greenRect->x(), qreal(0)); + QCOMPARE(greenRect->y(), qreal(10)); + QCOMPARE(greenRect->width(), qreal(150)); + QCOMPARE(greenRect->height(), qreal(190)); + + rect->setState("reanchored2"); + + //verify animation in progress + QTRY_VERIFY(greenRect->y() > 10 && greenRect->y() < 50); + QVERIFY(greenRect->height() > 125 && greenRect->height() < 190); + //NOTE: setting left/right anchors to undefined removes the anchors, but does not resize. + QCOMPARE(greenRect->x(), qreal(0)); + QCOMPARE(greenRect->width(), qreal(150)); + + //verify end state ("reanchored2") + QTRY_COMPARE(greenRect->y(), qreal(50)); + QCOMPARE(greenRect->height(), qreal(125)); + QCOMPARE(greenRect->x(), qreal(0)); + QCOMPARE(greenRect->width(), qreal(150)); + + rect->setState("reanchored"); + + //verify animation in progress + QTRY_VERIFY(greenRect->x() < 10 && greenRect->x() > 0); + QVERIFY(greenRect->y() > 0 && greenRect->y() < 50); + QVERIFY(greenRect->width() < 190 && greenRect->width() > 150); + QVERIFY(greenRect->height() > 125 && greenRect->height() < 150); + + //verify end state ("reanchored") + QTRY_COMPARE(greenRect->x(), qreal(10)); + QCOMPARE(greenRect->y(), qreal(0)); + QCOMPARE(greenRect->width(), qreal(190)); + QCOMPARE(greenRect->height(), qreal(150)); + + rect->setState("reanchored2"); + + //verify animation in progress + QTRY_VERIFY(greenRect->x() < 10 && greenRect->x() > 0); + QVERIFY(greenRect->y() > 0 && greenRect->y() < 50); + QVERIFY(greenRect->width() < 190 && greenRect->width() > 150); + QVERIFY(greenRect->height() > 125 && greenRect->height() < 150); + + //verify end state ("reanchored2") + QTRY_COMPARE(greenRect->x(), qreal(0)); + QCOMPARE(greenRect->y(), qreal(50)); + QCOMPARE(greenRect->width(), qreal(150)); + QCOMPARE(greenRect->height(), qreal(125)); + + delete rect; +} + +void tst_qdeclarativeanimations::reparent() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, testFileUrl("reparent.qml")); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect); + + QQuickRectangle *target = rect->findChild<QQuickRectangle*>("target"); + QVERIFY(target); + + QCOMPARE(target->parentItem(), rect); + QCOMPARE(target->x(), qreal(0)); + QCOMPARE(target->y(), qreal(0)); + QCOMPARE(target->width(), qreal(50)); + QCOMPARE(target->height(), qreal(50)); + QCOMPARE(target->rotation(), qreal(0)); + QCOMPARE(target->scale(), qreal(1)); + + rect->setState("state1"); + + QQuickRectangle *viaParent = rect->findChild<QQuickRectangle*>("viaParent"); + QVERIFY(viaParent); + + QQuickRectangle *newParent = rect->findChild<QQuickRectangle*>("newParent"); + QVERIFY(newParent); + + QTest::qWait(100); + + //animation in progress + QTRY_COMPARE(target->parentItem(), viaParent); + QVERIFY(target->x() > -100 && target->x() < 50); + QVERIFY(target->y() > -100 && target->y() < 50); + QVERIFY(target->width() > 50 && target->width() < 100); + QCOMPARE(target->height(), qreal(50)); + QCOMPARE(target->rotation(), qreal(-45)); + QCOMPARE(target->scale(), qreal(.5)); + + //end state + QTRY_COMPARE(target->parentItem(), newParent); + QCOMPARE(target->x(), qreal(50)); + QCOMPARE(target->y(), qreal(50)); + QCOMPARE(target->width(), qreal(100)); + QCOMPARE(target->height(), qreal(50)); + QCOMPARE(target->rotation(), qreal(0)); + QCOMPARE(target->scale(), qreal(1)); + + delete rect; +} + void tst_qdeclarativeanimations::pathInterpolator() { QDeclarativeEngine engine; @@ -311,7 +449,7 @@ void tst_qdeclarativeanimations::pathInterpolator() QCOMPARE(interpolator->progress(), qreal(.5)); QCOMPARE(interpolator->x(), qreal(175)); QCOMPARE(interpolator->y(), qreal(175)); - QCOMPARE(interpolator->angle(), qreal(270)); + QCOMPARE(interpolator->angle(), qreal(90)); interpolator->setProgress(1); QCOMPARE(interpolator->progress(), qreal(1)); @@ -322,34 +460,61 @@ void tst_qdeclarativeanimations::pathInterpolator() void tst_qdeclarativeanimations::pathInterpolatorBackwardJump() { - QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack.qml")); - QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create()); - QVERIFY(interpolator); - - QCOMPARE(interpolator->progress(), qreal(0)); - QCOMPARE(interpolator->x(), qreal(50)); - QCOMPARE(interpolator->y(), qreal(50)); - QCOMPARE(interpolator->angle(), qreal(270)); - - interpolator->setProgress(.5); - QCOMPARE(interpolator->progress(), qreal(.5)); - QCOMPARE(interpolator->x(), qreal(100)); - QCOMPARE(interpolator->y(), qreal(75)); - QCOMPARE(interpolator->angle(), qreal(90)); - - interpolator->setProgress(1); - QCOMPARE(interpolator->progress(), qreal(1)); - QCOMPARE(interpolator->x(), qreal(200)); - QCOMPARE(interpolator->y(), qreal(50)); - QCOMPARE(interpolator->angle(), qreal(0)); + { + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack.qml")); + QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create()); + QVERIFY(interpolator); + + QCOMPARE(interpolator->progress(), qreal(0)); + QCOMPARE(interpolator->x(), qreal(50)); + QCOMPARE(interpolator->y(), qreal(50)); + QCOMPARE(interpolator->angle(), qreal(90)); + + interpolator->setProgress(.5); + QCOMPARE(interpolator->progress(), qreal(.5)); + QCOMPARE(interpolator->x(), qreal(100)); + QCOMPARE(interpolator->y(), qreal(75)); + QCOMPARE(interpolator->angle(), qreal(270)); + + interpolator->setProgress(1); + QCOMPARE(interpolator->progress(), qreal(1)); + QCOMPARE(interpolator->x(), qreal(200)); + QCOMPARE(interpolator->y(), qreal(50)); + QCOMPARE(interpolator->angle(), qreal(0)); + + //make sure we don't get caught in infinite loop here + interpolator->setProgress(0); + QCOMPARE(interpolator->progress(), qreal(0)); + QCOMPARE(interpolator->x(), qreal(50)); + QCOMPARE(interpolator->y(), qreal(50)); + QCOMPARE(interpolator->angle(), qreal(90)); + } - //make sure we don't get caught in infinite loop here - interpolator->setProgress(0); - QCOMPARE(interpolator->progress(), qreal(0)); - QCOMPARE(interpolator->x(), qreal(50)); - QCOMPARE(interpolator->y(), qreal(50)); - QCOMPARE(interpolator->angle(), qreal(270)); + { + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack2.qml")); + QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create()); + QVERIFY(interpolator); + + QCOMPARE(interpolator->progress(), qreal(0)); + QCOMPARE(interpolator->x(), qreal(200)); + QCOMPARE(interpolator->y(), qreal(280)); + QCOMPARE(interpolator->angle(), qreal(180)); + + interpolator->setProgress(1); + QCOMPARE(interpolator->progress(), qreal(1)); + QCOMPARE(interpolator->x(), qreal(0)); + QCOMPARE(interpolator->y(), qreal(80)); + QCOMPARE(interpolator->angle(), qreal(180)); + + //make sure we don't get caught in infinite loop here + interpolator->setProgress(0); + QCOMPARE(interpolator->progress(), qreal(0)); + QCOMPARE(interpolator->x(), qreal(200)); + QCOMPARE(interpolator->y(), qreal(280)); + QCOMPARE(interpolator->angle(), qreal(180)); + } } void tst_qdeclarativeanimations::pathWithNoStart() @@ -860,8 +1025,8 @@ void tst_qdeclarativeanimations::propertyValueSourceDefaultStart() QVERIFY(rect); QDeclarativeAbstractAnimation *myAnim = rect->findChild<QDeclarativeAbstractAnimation*>("MyAnim"); - QVERIFY(myAnim && myAnim->qtAnimation()); - QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimation::Stopped); + QVERIFY(myAnim && !myAnim->qtAnimation()); + //QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimationJob::Stopped); } } @@ -879,8 +1044,8 @@ void tst_qdeclarativeanimations::dontStart() QVERIFY(rect); QDeclarativeAbstractAnimation *myAnim = rect->findChild<QDeclarativeAbstractAnimation*>("MyAnim"); - QVERIFY(myAnim && myAnim->qtAnimation()); - QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimation::Stopped); + QVERIFY(myAnim && !myAnim->qtAnimation()); + //QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimationJob::Stopped); } { @@ -894,8 +1059,8 @@ void tst_qdeclarativeanimations::dontStart() QVERIFY(rect); QDeclarativeAbstractAnimation *myAnim = rect->findChild<QDeclarativeAbstractAnimation*>("MyAnim"); - QVERIFY(myAnim && myAnim->qtAnimation()); - QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimation::Stopped); + QVERIFY(myAnim && !myAnim->qtAnimation()); + //QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimationJob::Stopped); } } @@ -1059,7 +1224,7 @@ void tst_qdeclarativeanimations::doubleRegistrationBug() QDeclarativeAbstractAnimation *anim = rect->findChild<QDeclarativeAbstractAnimation*>("animation"); QVERIFY(anim != 0); - QTRY_COMPARE(anim->qtAnimation()->state(), QAbstractAnimation::Stopped); + QTRY_COMPARE(anim->qtAnimation()->state(), QAbstractAnimationJob::Stopped); } //QTBUG-16736 @@ -1083,7 +1248,7 @@ void tst_qdeclarativeanimations::alwaysRunToEndRestartBug() QVERIFY(rect.x() != qreal(200)); QTest::qWait(800); QTIMED_COMPARE(rect.x(), qreal(200)); - QCOMPARE(static_cast<QDeclarativeAbstractAnimation*>(&animation)->qtAnimation()->state(), QAbstractAnimation::Stopped); + QCOMPARE(static_cast<QDeclarativeAbstractAnimation*>(&animation)->qtAnimation()->state(), QAbstractAnimationJob::Stopped); } //QTBUG-20227 @@ -1107,7 +1272,7 @@ void tst_qdeclarativeanimations::pauseBindingBug() QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); QVERIFY(rect != 0); QDeclarativeAbstractAnimation *anim = rect->findChild<QDeclarativeAbstractAnimation*>("animation"); - QVERIFY(anim->qtAnimation()->state() == QAbstractAnimation::Paused); + QVERIFY(anim->qtAnimation()->state() == QAbstractAnimationJob::Paused); delete rect; } @@ -1120,13 +1285,35 @@ void tst_qdeclarativeanimations::pauseBug() QDeclarativeComponent c(&engine, testFileUrl("pauseBug.qml")); QDeclarativeAbstractAnimation *anim = qobject_cast<QDeclarativeAbstractAnimation*>(c.create()); QVERIFY(anim != 0); - QCOMPARE(anim->qtAnimation()->state(), QAbstractAnimation::Paused); + QCOMPARE(anim->qtAnimation()->state(), QAbstractAnimationJob::Paused); QCOMPARE(anim->isPaused(), true); QCOMPARE(anim->isRunning(), true); delete anim; } +//QTBUG-23092 +void tst_qdeclarativeanimations::loopingBug() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, testFileUrl("looping.qml")); + QObject *obj = c.create(); + + QDeclarativeAbstractAnimation *anim = obj->findChild<QDeclarativeAbstractAnimation*>(); + QVERIFY(anim != 0); + QCOMPARE(anim->qtAnimation()->totalDuration(), 300); + QCOMPARE(anim->isRunning(), true); + QTRY_COMPARE(static_cast<QAnimationGroupJob*>(anim->qtAnimation())->firstChild()->currentLoop(), 2); + QTRY_COMPARE(anim->isRunning(), false); + + QQuickRectangle *rect = obj->findChild<QQuickRectangle*>(); + QVERIFY(rect != 0); + QCOMPARE(rect->rotation(), qreal(90)); + + delete obj; +} + QTEST_MAIN(tst_qdeclarativeanimations) #include "tst_qdeclarativeanimations.moc" diff --git a/tests/auto/qtquick2/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp b/tests/auto/qtquick2/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp index ed9430e85c..26a73d3bca 100644 --- a/tests/auto/qtquick2/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp +++ b/tests/auto/qtquick2/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp @@ -335,8 +335,8 @@ void tst_qdeclarativebehaviors::dontStart() QVERIFY(rect); QDeclarativeAbstractAnimation *myAnim = rect->findChild<QDeclarativeAbstractAnimation*>("MyAnim"); - QVERIFY(myAnim && myAnim->qtAnimation()); - QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimation::Stopped); + QVERIFY(myAnim && !myAnim->qtAnimation()); + //QVERIFY(myAnim->qtAnimation()->state() == QAbstractAnimation::Stopped); delete rect; } diff --git a/tests/auto/qtquick2/qdeclarativesmoothedanimation/data/simpleanimation.qml b/tests/auto/qtquick2/qdeclarativesmoothedanimation/data/simpleanimation.qml new file mode 100644 index 0000000000..b2be63ec94 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativesmoothedanimation/data/simpleanimation.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Rectangle { + width: 300; height: 300; + Rectangle { + objectName: "rect" + color: "red" + width: 60; height: 60; + x: 100; y: 100; + } + SmoothedAnimation { objectName: "anim"} +}
\ No newline at end of file diff --git a/tests/auto/qtquick2/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp b/tests/auto/qtquick2/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp index 44bd8ed74d..16a0c1ac27 100644 --- a/tests/auto/qtquick2/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp +++ b/tests/auto/qtquick2/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp @@ -41,7 +41,7 @@ #include <qtest.h> #include <QtDeclarative/qdeclarativeengine.h> #include <QtDeclarative/qdeclarativecomponent.h> -#include <private/qdeclarativesmoothedanimation_p.h> +#include <QtQuick/private/qdeclarativesmoothedanimation_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <private/qdeclarativevaluetype_p.h> #include "../../shared/util.h" @@ -120,28 +120,40 @@ void tst_qdeclarativesmoothedanimation::disabled() void tst_qdeclarativesmoothedanimation::simpleAnimation() { - QQuickRectangle rect; - QDeclarativeSmoothedAnimation animation; - animation.setTarget(&rect); - animation.setProperty("x"); - animation.setTo(200); - animation.setDuration(250); - QVERIFY(animation.target() == &rect); - QVERIFY(animation.property() == "x"); - QVERIFY(animation.to() == 200); - animation.start(); - QVERIFY(animation.isRunning()); - QTest::qWait(animation.duration()); - QTRY_COMPARE(rect.x(), qreal(200)); - - rect.setX(0); - animation.start(); - animation.pause(); - QVERIFY(animation.isRunning()); - QVERIFY(animation.isPaused()); - animation.setCurrentTime(125); - QVERIFY(animation.currentTime() == 125); - QCOMPARE(rect.x(), qreal(100)); + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, testFileUrl("simpleanimation.qml")); + QObject *obj = c.create(); + QVERIFY(obj); + + QQuickRectangle *rect = obj->findChild<QQuickRectangle*>("rect"); + QVERIFY(rect); + + QDeclarativeSmoothedAnimation *animation = obj->findChild<QDeclarativeSmoothedAnimation*>("anim"); + QVERIFY(animation); + + animation->setTarget(rect); + animation->setProperty("x"); + animation->setTo(200); + animation->setDuration(250); + QVERIFY(animation->target() == rect); + QVERIFY(animation->property() == "x"); + QVERIFY(animation->to() == 200); + animation->start(); + QVERIFY(animation->isRunning()); + QTest::qWait(animation->duration()); + QTRY_COMPARE(rect->x(), qreal(200)); + QTest::qWait(100); //smoothed animation doesn't report stopped until delayed timer fires + + QVERIFY(!animation->isRunning()); + rect->setX(0); + animation->start(); + QVERIFY(animation->isRunning()); + animation->pause(); + QVERIFY(animation->isRunning()); + QVERIFY(animation->isPaused()); + animation->setCurrentTime(125); + QVERIFY(animation->currentTime() == 125); + QCOMPARE(rect->x(), qreal(100)); } void tst_qdeclarativesmoothedanimation::valueSource() diff --git a/tests/auto/qtquick2/qdeclarativespringanimation/data/springanimation2.qml b/tests/auto/qtquick2/qdeclarativespringanimation/data/springanimation2.qml index 172cc57ca8..9f72e51533 100644 --- a/tests/auto/qtquick2/qdeclarativespringanimation/data/springanimation2.qml +++ b/tests/auto/qtquick2/qdeclarativespringanimation/data/springanimation2.qml @@ -1,9 +1,16 @@ import QtQuick 2.0 -SpringAnimation { - to: 1.44; velocity: 0.9 - spring: 1.0; damping: 0.5 - epsilon: 0.25; modulus: 360.0 - mass: 2.0; - running: true; +Item { + Item { + id: item + } + + SpringAnimation { + target: item; property: "x" + to: 1.44; velocity: 0.9 + spring: 1.0; damping: 0.5 + epsilon: 0.25; modulus: 360.0 + mass: 2.0; + running: true; + } } diff --git a/tests/auto/qtquick2/qdeclarativespringanimation/tst_qdeclarativespringanimation.cpp b/tests/auto/qtquick2/qdeclarativespringanimation/tst_qdeclarativespringanimation.cpp index 7c3723fff0..eae7d9db65 100644 --- a/tests/auto/qtquick2/qdeclarativespringanimation/tst_qdeclarativespringanimation.cpp +++ b/tests/auto/qtquick2/qdeclarativespringanimation/tst_qdeclarativespringanimation.cpp @@ -88,7 +88,9 @@ void tst_qdeclarativespringanimation::values() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, testFileUrl("springanimation2.qml")); - QDeclarativeSpringAnimation *obj = qobject_cast<QDeclarativeSpringAnimation*>(c.create()); + QObject *root = c.create(); + + QDeclarativeSpringAnimation *obj = root->findChild<QDeclarativeSpringAnimation*>(); QVERIFY(obj != 0); diff --git a/tests/benchmarks/declarative/animation/animation.pro b/tests/benchmarks/declarative/animation/animation.pro new file mode 100644 index 0000000000..7a659c0341 --- /dev/null +++ b/tests/benchmarks/declarative/animation/animation.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_animation +QT += declarative +macx:CONFIG -= app_bundle + +SOURCES += tst_animation.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" + +QT += core-private gui-private declarative-private v8-private diff --git a/tests/benchmarks/declarative/animation/data/animation.qml b/tests/benchmarks/declarative/animation/data/animation.qml new file mode 100644 index 0000000000..e9f2799b09 --- /dev/null +++ b/tests/benchmarks/declarative/animation/data/animation.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +ParallelAnimation { + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} + NumberAnimation {} +} diff --git a/tests/benchmarks/declarative/animation/tst_animation.cpp b/tests/benchmarks/declarative/animation/tst_animation.cpp new file mode 100644 index 0000000000..bf39adc3d8 --- /dev/null +++ b/tests/benchmarks/declarative/animation/tst_animation.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QDeclarativeEngine> +#include <QDeclarativeComponent> +#include <private/qdeclarativemetatype_p.h> +#include <private/qdeclarativeanimation_p_p.h> +#include <QDeclarativeContext> + +class tst_animation : public QObject +{ + Q_OBJECT +public: + tst_animation(); + +private slots: + void abstractAnimation(); + void bulkValueAnimator(); + void propertyUpdater(); + + void animationtree_qml(); + + void animationelements_data(); + void animationelements(); + + void numberAnimation(); + void numberAnimationStarted(); + void numberAnimationMultipleTargets(); + void numberAnimationEmpty(); + +private: + QDeclarativeEngine engine; +}; + +tst_animation::tst_animation() +{ +} + +inline QUrl TEST_FILE(const QString &filename) +{ + return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename); +} + +void tst_animation::abstractAnimation() +{ + QBENCHMARK { + //QAbstractAnimation2 animation; + QAbstractAnimation2 *animation = new QAbstractAnimation2; + delete animation; + } +} + +void tst_animation::bulkValueAnimator() +{ + QBENCHMARK { + //QDeclarativeBulkValueAnimator animator; + //QDeclarativeBulkValueAnimator animator2(animator); + QDeclarativeBulkValueAnimator *animator = new QDeclarativeBulkValueAnimator; + delete animator; + } +} + +void tst_animation::propertyUpdater() +{ + QBENCHMARK { + //QDeclarativeAnimationPropertyUpdater updater; + QDeclarativeAnimationPropertyUpdater *updater = new QDeclarativeAnimationPropertyUpdater; + delete updater; + } +} + +void tst_animation::animationtree_qml() +{ + QDeclarativeComponent component(&engine, TEST_FILE("animation.qml")); + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +void tst_animation::animationelements_data() +{ + QTest::addColumn<QString>("type"); + + QSet<QString> types = QDeclarativeMetaType::qmlTypeNames().toSet(); + foreach (const QString &type, types) { + if (type.contains(QLatin1String("Animation"))) + QTest::newRow(type.toLatin1()) << type; + } + + QTest::newRow("QtQuick/Behavior") << "QtQuick/Behavior"; + QTest::newRow("QtQuick/Transition") << "QtQuick/Transition"; +} + +void tst_animation::animationelements() +{ + QFETCH(QString, type); + QDeclarativeType *t = QDeclarativeMetaType::qmlType(type, 2, 0); + if (!t || !t->isCreatable()) + QSKIP("Non-creatable type", SkipSingle); + + QBENCHMARK { + QObject *obj = t->create(); + delete obj; + } +} + +void tst_animation::numberAnimation() +{ + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0\nItem { Rectangle { id: rect; NumberAnimation { target: rect; property: \"x\"; to: 100; duration: 500; easing.type: Easing.InOutQuad } } }", QUrl()); + + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +void tst_animation::numberAnimationStarted() +{ + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0\nItem { Rectangle { id: rect; NumberAnimation { target: rect; property: \"x\"; to: 100; duration: 500; easing.type: Easing.InOutQuad; running: true; Component.onCompleted: pause() } } }", QUrl()); + + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +void tst_animation::numberAnimationMultipleTargets() +{ + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0\nItem { Rectangle { id: rect; NumberAnimation { target: rect; properties: \"x,y,z,width,height,implicitWidth,implicitHeight\"; to: 100; duration: 500; easing.type: Easing.InOutQuad; running: true; Component.onCompleted: pause() } } }", QUrl()); + + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +void tst_animation::numberAnimationEmpty() +{ + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0\nNumberAnimation { }", QUrl()); + + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +QTEST_MAIN(tst_animation) + +#include "tst_animation.moc" |