summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/auto.pro6
-rw-r--r--tests/auto/qanimationgroup/qanimationgroup.pro5
-rw-r--r--tests/auto/qanimationgroup/tst_qanimationgroup.cpp347
-rw-r--r--tests/auto/qanimationstate/qanimationstate.pro5
-rw-r--r--tests/auto/qanimationstate/tst_qanimationstate.cpp625
-rw-r--r--tests/auto/qeasingcurve/qeasingcurve.pro3
-rw-r--r--tests/auto/qeasingcurve/tst_qeasingcurve.cpp488
-rw-r--r--tests/auto/qmake/testdata/bundle-spaces/some-file6
-rw-r--r--tests/auto/qparallelanimationgroup/qparallelanimationgroup.pro5
-rw-r--r--tests/auto/qparallelanimationgroup/tst_qparallelanimationgroup.cpp834
-rw-r--r--tests/auto/qpropertyanimation/qpropertyanimation.pro5
-rw-r--r--tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp831
-rw-r--r--tests/auto/qscriptqobject/tst_qscriptqobject.cpp66
-rw-r--r--tests/auto/qsequentialanimationgroup/qsequentialanimationgroup.pro5
-rw-r--r--tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp1649
-rw-r--r--tests/auto/qstate/qstate.pro5
-rw-r--r--tests/auto/qstate/tst_qstate.cpp372
-rw-r--r--tests/auto/qstatemachine/qstatemachine.pro4
-rw-r--r--tests/auto/qstatemachine/tst_qstatemachine.cpp2177
-rw-r--r--tests/benchmarks/benchmarks.pro1
-rw-r--r--tests/benchmarks/qanimation/dummyanimation.cpp20
-rw-r--r--tests/benchmarks/qanimation/dummyanimation.h19
-rw-r--r--tests/benchmarks/qanimation/dummyobject.cpp25
-rw-r--r--tests/benchmarks/qanimation/dummyobject.h23
-rw-r--r--tests/benchmarks/qanimation/main.cpp173
-rw-r--r--tests/benchmarks/qanimation/qanimation.pro18
-rw-r--r--tests/benchmarks/qanimation/rectanimation.cpp58
-rw-r--r--tests/benchmarks/qanimation/rectanimation.h30
-rw-r--r--tests/benchmarks/qvariant/qvariant.pro1
-rw-r--r--tests/benchmarks/qvariant/tst_qvariant.cpp115
30 files changed, 7853 insertions, 68 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 60e6657..f8f15a3 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -75,6 +75,7 @@ SUBDIRS += bic \
qaction \
qactiongroup \
qalgorithms \
+ qanimationgroup \
qapplication \
qatomicint \
qatomicpointer \
@@ -213,6 +214,7 @@ SUBDIRS += bic \
qpainter \
qpainterpath \
qpalette \
+ qparallelanimationgroup \
qpathclipper \
qpen \
qpicture \
@@ -228,6 +230,7 @@ SUBDIRS += bic \
qprocess \
qprogressbar \
qprogressdialog \
+ qpropertyanimation \
qpushbutton \
qqueue \
qradiobutton \
@@ -254,6 +257,7 @@ SUBDIRS += bic \
qscrollarea \
qsemaphore \
qsharedpointer \
+ qsequentialanimationgroup \
qset \
qsettings \
qshortcut \
@@ -287,6 +291,7 @@ SUBDIRS += bic \
qstackedwidget \
qstandarditem \
qstandarditemmodel \
+ qstate \
qstatusbar \
qstl \
qstring \
@@ -340,6 +345,7 @@ SUBDIRS += bic \
qtranslator \
qtransform \
qtransformedscreen \
+ qtransition \
qtreeview \
qtreewidget \
qtreewidgetitemiterator \
diff --git a/tests/auto/qanimationgroup/qanimationgroup.pro b/tests/auto/qanimationgroup/qanimationgroup.pro
new file mode 100644
index 0000000..97d33dd
--- /dev/null
+++ b/tests/auto/qanimationgroup/qanimationgroup.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core gui
+SOURCES += tst_qanimationgroup.cpp
+
+
diff --git a/tests/auto/qanimationgroup/tst_qanimationgroup.cpp b/tests/auto/qanimationgroup/tst_qanimationgroup.cpp
new file mode 100644
index 0000000..ff5c3b4
--- /dev/null
+++ b/tests/auto/qanimationgroup/tst_qanimationgroup.cpp
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtCore/qanimationgroup.h>
+#include <QtCore/qsequentialanimationgroup.h>
+#include <QtCore/qparallelanimationgroup.h>
+
+//TESTED_CLASS=QAnimationGroup
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QAbstractAnimation::State)
+
+class tst_QAnimationGroup : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QAnimationGroup();
+ virtual ~tst_QAnimationGroup();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ void construction();
+ void emptyGroup();
+ void setCurrentTime();
+ void statesAndSignals();
+ void setParentAutoAdd();
+ void beginNestedGroup();
+};
+
+tst_QAnimationGroup::tst_QAnimationGroup()
+{
+}
+
+tst_QAnimationGroup::~tst_QAnimationGroup()
+{
+}
+
+void tst_QAnimationGroup::init()
+{
+ qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
+}
+
+void tst_QAnimationGroup::cleanup()
+{
+}
+
+void tst_QAnimationGroup::construction()
+{
+ QSequentialAnimationGroup animationgroup;
+}
+
+class AnimationObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue)
+public:
+ AnimationObject(int startValue = 0)
+ : v(startValue)
+ { }
+
+ int value() const { return v; }
+ void setValue(int value) { v = value; }
+
+ int v;
+};
+
+class TestAnimation : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)};
+ virtual void updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+ {
+ Q_UNUSED(oldState)
+ Q_UNUSED(newState)
+ };
+};
+
+class UncontrolledAnimation : public QPropertyAnimation
+{
+ Q_OBJECT
+public:
+ UncontrolledAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0)
+ : QPropertyAnimation(target, propertyName, parent), id(0)
+ {
+ setDuration(250);
+ }
+
+ 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;
+};
+
+void tst_QAnimationGroup::emptyGroup()
+{
+ QSequentialAnimationGroup group;
+ QSignalSpy groupStateChangedSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ group.start();
+
+ QCOMPARE(groupStateChangedSpy.count(), 2);
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+
+ QTest::ignoreMessage(QtWarningMsg, "QAbstractAnimation::pause: Cannot pause a stopped animation");
+ group.pause();
+
+ QCOMPARE(groupStateChangedSpy.count(), 2);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+
+ group.start();
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(2).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(3).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+
+ group.stop();
+
+ QCOMPARE(groupStateChangedSpy.count(), 4);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QAnimationGroup::setCurrentTime()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject s_o3;
+ AnimationObject p_o1;
+ AnimationObject p_o2;
+ AnimationObject p_o3;
+ AnimationObject t_o1;
+ AnimationObject t_o2;
+
+ // sequence operating on same object/property
+ QSequentialAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ a2_s_o1->setIterationCount(3);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroup *sequence2 = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
+ QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value");
+ sequence2->addAnimation(a1_s_o2);
+ sequence2->addAnimation(a1_s_o3);
+
+ // parallel operating on different object/properties
+ QAnimationGroup *parallel = new QParallelAnimationGroup();
+ QVariantAnimation *a1_p_o1 = new QPropertyAnimation(&p_o1, "value");
+ QVariantAnimation *a1_p_o2 = new QPropertyAnimation(&p_o2, "value");
+ QVariantAnimation *a1_p_o3 = new QPropertyAnimation(&p_o3, "value");
+ a1_p_o2->setIterationCount(3);
+ parallel->addAnimation(a1_p_o1);
+ parallel->addAnimation(a1_p_o2);
+ parallel->addAnimation(a1_p_o3);
+
+ UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation(&t_o1, "value");
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ QVariantAnimation *loopsForever = new QPropertyAnimation(&t_o2, "value");
+ loopsForever->setIterationCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QParallelAnimationGroup group;
+ group.addAnimation(sequence);
+ group.addAnimation(sequence2);
+ group.addAnimation(parallel);
+ group.addAnimation(notTimeDriven);
+ group.addAnimation(loopsForever);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(parallel->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o3->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 1);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+ QCOMPARE(a1_p_o1->currentTime(), 1);
+ QCOMPARE(a1_p_o2->currentTime(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 1);
+ QCOMPARE(notTimeDriven->currentTime(), 1);
+ QCOMPARE(loopsForever->currentTime(), 1);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentTime(), 250);
+ QCOMPARE(sequence->currentTime(), 250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+ QCOMPARE(a1_p_o1->currentTime(), 250);
+ QCOMPARE(a1_p_o2->currentTime(), 0);
+ QCOMPARE(a1_p_o2->currentIteration(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 250);
+ QCOMPARE(loopsForever->currentTime(), 0);
+ QCOMPARE(loopsForever->currentIteration(), 1);
+ QCOMPARE(sequence->currentAnimation(), a2_s_o1);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentTime(), 251);
+ QCOMPARE(sequence->currentTime(), 251);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentIteration(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 251);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 1);
+ QCOMPARE(a1_p_o1->currentTime(), 250);
+ QCOMPARE(a1_p_o2->currentTime(), 1);
+ QCOMPARE(a1_p_o2->currentIteration(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 251);
+ QCOMPARE(loopsForever->currentTime(), 1);
+ QCOMPARE(sequence->currentAnimation(), a2_s_o1);
+}
+
+void tst_QAnimationGroup::statesAndSignals()
+{
+}
+
+void tst_QAnimationGroup::setParentAutoAdd()
+{
+ QParallelAnimationGroup group;
+ QVariantAnimation *animation = new QPropertyAnimation(&group);
+ QCOMPARE(animation->group(), &group);
+}
+
+void tst_QAnimationGroup::beginNestedGroup()
+{
+ QAnimationGroup *subGroup;
+ QAnimationGroup *parent = new QParallelAnimationGroup();
+
+ for (int i = 0; i < 10; ++i) {
+ if (i & 1)
+ subGroup = new QParallelAnimationGroup(parent);
+ else
+ subGroup = new QSequentialAnimationGroup(parent);
+
+ QCOMPARE(parent->animationCount(), 1);
+ QAnimationGroup *child = static_cast<QAnimationGroup *>(parent->animationAt(0));
+
+ QCOMPARE(child->parent(), static_cast<QObject *>(parent));
+ if (i & 1)
+ QVERIFY(qobject_cast<QParallelAnimationGroup *> (child));
+ else
+ QVERIFY(qobject_cast<QSequentialAnimationGroup *> (child));
+
+ parent = child;
+ }
+}
+
+QTEST_MAIN(tst_QAnimationGroup)
+#include "tst_qanimationgroup.moc"
diff --git a/tests/auto/qanimationstate/qanimationstate.pro b/tests/auto/qanimationstate/qanimationstate.pro
new file mode 100644
index 0000000..8862c27
--- /dev/null
+++ b/tests/auto/qanimationstate/qanimationstate.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core
+SOURCES += tst_qanimationstate.cpp
+
+
diff --git a/tests/auto/qanimationstate/tst_qanimationstate.cpp b/tests/auto/qanimationstate/tst_qanimationstate.cpp
new file mode 100644
index 0000000..085db24
--- /dev/null
+++ b/tests/auto/qanimationstate/tst_qanimationstate.cpp
@@ -0,0 +1,625 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/qstate.h>
+#include <QtCore/qstatemachine.h>
+#include <QtCore/qanimationstate.h>
+
+//TESTED_CLASS=QAnimationState
+//TESTED_FILES=
+
+#define QTRY_COMPARE(__expr, __expected) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if ((__expr) != (__expected)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QCOMPARE(__expr, __expected); \
+ } while(0)
+
+
+class tst_QAnimationState : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QAnimationState();
+ virtual ~tst_QAnimationState();
+
+private slots:
+ void init();
+ void cleanup();
+ void construction();
+ void noAnimation();
+ void simpleAnimation();
+ void twoAnimations();
+ void reuseAnimation();
+ void nestedTargetState();
+ void parallelTargetState();
+ void playTwice();
+ void twoAnimatedTransitions();
+ void globalRestoreProperty();
+ void specificRestoreProperty();
+ void someAnimationsNotSpecified();
+ void someActionsNotAnimated();
+ void specificTargetValueOfAnimation();
+ void persistentTargetValueOfAnimation();
+};
+
+tst_QAnimationState::tst_QAnimationState()
+{
+}
+
+tst_QAnimationState::~tst_QAnimationState()
+{
+}
+
+void tst_QAnimationState::init()
+{
+}
+
+void tst_QAnimationState::cleanup()
+{
+}
+
+void tst_QAnimationState::construction()
+{
+ QAnimationState as;
+}
+
+class EventTransition : public QTransition
+{
+public:
+ EventTransition(QEvent::Type type, QAbstractState *target)
+ : QTransition(), m_type(type) {
+ setTargetState(target);
+ }
+protected:
+ virtual bool eventTest(QEvent *e) const {
+ return (e->type() == m_type);
+ }
+private:
+ QEvent::Type m_type;
+};
+
+void tst_QAnimationState::noAnimation()
+{
+ QStateMachine machine;
+
+ QState *s1 = new QState(machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ s2->setProperty("entered", false);
+ s2->setPropertyOnEntry(s2, "entered", true);
+
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s1));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QVERIFY(machine.configuration().contains(s1));
+
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(s2->property("entered").toBool(), true);
+ QVERIFY(machine.configuration().contains(s2));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QVERIFY(machine.configuration().contains(s1));
+
+ s2->setProperty("entered", false);
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(s2->property("entered").toBool(), true);
+ QVERIFY(machine.configuration().contains(s2));
+}
+
+class ValueCheckerState: public QState
+{
+public:
+ ValueCheckerState(QState *parent)
+ : QState(parent)
+ {
+ }
+
+ void addPropertyToCheck(const QObject *object, const char *propertyName)
+ {
+ m_objects.append(object);
+ m_propertyNames.append(propertyName);
+ valueOnEntry.append(QVariant());
+ }
+
+ QVariantList valueOnEntry;
+
+protected:
+ virtual void onEntry()
+ {
+ for (int i=0; i<m_objects.size(); ++i)
+ valueOnEntry[i] = m_objects.at(i)->property(m_propertyNames.at(i));
+
+ QState::onEntry();
+ }
+
+ QList<const QObject *> m_objects;
+ QList<QByteArray> m_propertyNames;
+
+};
+
+void tst_QAnimationState::simpleAnimation()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("fooBar", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "fooBar");
+ s2->setPropertyOnEntry(object, "fooBar", 2.0);
+
+ QPropertyAnimation *animation = new QPropertyAnimation(object, "fooBar", s2);
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2), animation);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+}
+
+void tst_QAnimationState::twoAnimations()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+ s2->setPropertyOnEntry(object, "bar", 10.0);
+
+ QPropertyAnimation *animationFoo = new QPropertyAnimation(object, "foo", s2);
+ QPropertyAnimation *animationBar = new QPropertyAnimation(object, "bar", s2);
+ animationBar->setDuration(900);
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(animationFoo);
+ as->addAnimation(animationBar);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 10.0);
+}
+
+void tst_QAnimationState::parallelTargetState()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+ QState *s2 = new QState(QState::ParallelGroup, machine.rootState());
+
+ ValueCheckerState *c1 = new ValueCheckerState(s2);
+ c1->setPropertyOnEntry(object, "foo", 2.0);
+ c1->addPropertyToCheck(object, "foo");
+ c1->addPropertyToCheck(object, "bar");
+
+ QState *c2 = new QState(s2);
+ c2->setPropertyOnEntry(object, "bar", 10.0);
+
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(c1->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(c1->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(c1->valueOnEntry.at(1).toDouble(), 10.0);
+}
+
+
+void tst_QAnimationState::twoAnimatedTransitions()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->setPropertyOnEntry(object, "foo", 5.0);
+ ValueCheckerState *s3 = new ValueCheckerState(machine.rootState());
+ s3->setPropertyOnEntry(object, "foo", 2.0);
+ s3->addPropertyToCheck(object, "foo");
+
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2),
+ new QPropertyAnimation(object, "foo", s2));
+ s2->addAnimatedTransition(new EventTransition(QEvent::User, s3),
+ new QPropertyAnimation(object, "foo", s2));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 5.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s3->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s3->valueOnEntry.at(0).toDouble(), 2.0);
+}
+
+void tst_QAnimationState::playTwice()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->setPropertyOnEntry(object, "foo", 5.0);
+ QState *s3 = new QState(machine.rootState());
+ s3->setPropertyOnEntry(object, "foo", 2.0);
+
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2),
+ new QPropertyAnimation(object, "foo", s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+ s3->addTransition(s1);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 5.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+ QVERIFY(machine.configuration().contains(s1));
+ QCOMPARE(object->property("foo").toDouble(), 2.0);
+
+ s2->valueOnEntry[0] = QVariant();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(object->property("foo").toDouble(), 5.0);
+}
+
+void tst_QAnimationState::nestedTargetState()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ QState *s2Child = new QState(s2);
+ s2Child->setPropertyOnEntry(object, "bar", 10.0);
+ s2->setInitialState(s2Child);
+
+ QState *s2Child2 = new QState(s2);
+ s2Child2->setPropertyOnEntry(object, "bar", 11.0);
+ s2Child->addTransition(s2Child2); // should *not* be considered by QAnimationState as part of target
+
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 10.0);
+ QCOMPARE(object->property("bar").toDouble(), 11.0);
+}
+
+void tst_QAnimationState::reuseAnimation()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->setPropertyOnEntry(object, "foo", 5.0);
+ ValueCheckerState *s3 = new ValueCheckerState(machine.rootState());
+ s3->setPropertyOnEntry(object, "foo", 2.0);
+ s3->addPropertyToCheck(object, "foo");
+
+ QPropertyAnimation *anim = new QPropertyAnimation(object, "foo", s2);
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2), anim);
+ s2->addAnimatedTransition(new EventTransition(QEvent::User, s3), anim);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 5.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s3->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s3->valueOnEntry.at(0).toDouble(), 2.0);
+}
+
+void tst_QAnimationState::globalRestoreProperty()
+{
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QState::RestoreProperties);
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ ValueCheckerState *s3 = new ValueCheckerState(machine.rootState());
+ s3->addPropertyToCheck(object, "foo");
+ s3->addPropertyToCheck(object, "bar");
+ s3->setPropertyOnEntry(object, "bar", 5.0);
+
+ ValueCheckerState *s4 = new ValueCheckerState(machine.rootState());
+ s4->addPropertyToCheck(object, "foo");
+ s4->addPropertyToCheck(object, "bar");
+
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ as = s2->addAnimatedTransition(new EventTransition(QEvent::User, s3));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ as = s3->addAnimatedTransition(new EventTransition(QEvent::User, s4));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 3.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s3->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s3->valueOnEntry.at(0).toDouble(), 1.0);
+ QCOMPARE(s3->valueOnEntry.at(1).toDouble(), 5.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s4->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s4->valueOnEntry.at(0).toDouble(), 1.0);
+ QCOMPARE(s4->valueOnEntry.at(1).toDouble(), 3.0);
+
+}
+
+void tst_QAnimationState::specificRestoreProperty()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->setRestorePolicy(QState::RestoreProperties);
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ ValueCheckerState *s3 = new ValueCheckerState(machine.rootState());
+ s3->setRestorePolicy(QState::RestoreProperties);
+ s3->addPropertyToCheck(object, "foo");
+ s3->addPropertyToCheck(object, "bar");
+ s3->setPropertyOnEntry(object, "bar", 5.0);
+
+ ValueCheckerState *s4 = new ValueCheckerState(machine.rootState());
+ s4->setRestorePolicy(QState::RestoreProperties);
+ s4->addPropertyToCheck(object, "foo");
+ s4->addPropertyToCheck(object, "bar");
+
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+
+ as = s2->addAnimatedTransition(new EventTransition(QEvent::User, s3));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ as = s3->addAnimatedTransition(new EventTransition(QEvent::User, s4));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 3.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s3->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s3->valueOnEntry.at(0).toDouble(), 1.0);
+ QCOMPARE(s3->valueOnEntry.at(1).toDouble(), 5.0);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s4->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s4->valueOnEntry.at(0).toDouble(), 1.0);
+ QCOMPARE(s4->valueOnEntry.at(1).toDouble(), 3.0);
+}
+
+void tst_QAnimationState::someAnimationsNotSpecified()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ QAnimationState *as = s1->addAnimatedTransition(new EventTransition(QEvent::User, s2));
+ as->addAnimation(new QPropertyAnimation(object, "foo", as));
+ as->addAnimation(new QPropertyAnimation(object, "bar", as));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 3.0);
+}
+
+void tst_QAnimationState::someActionsNotAnimated()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+ object->setProperty("bar", 3.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->addPropertyToCheck(object, "bar");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+ s2->setPropertyOnEntry(object, "bar", 5.0);
+
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2),
+ new QPropertyAnimation(object, "foo", s1));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(s2->valueOnEntry.at(1).toDouble(), 3.0);
+ QCOMPARE(object->property("foo").toDouble(), 2.0);
+ QCOMPARE(object->property("bar").toDouble(), 5.0);
+}
+
+void tst_QAnimationState::specificTargetValueOfAnimation()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ QPropertyAnimation *anim = new QPropertyAnimation(object, "foo");
+ anim->setEndValue(10.0);
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2), anim);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 10.0);
+ QCOMPARE(object->property("foo").toDouble(), 2.0);
+}
+
+void tst_QAnimationState::persistentTargetValueOfAnimation()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("foo", 1.0);
+
+ QState *s1 = new QState(machine.rootState());
+
+ ValueCheckerState *s2 = new ValueCheckerState(machine.rootState());
+ s2->addPropertyToCheck(object, "foo");
+ s2->setPropertyOnEntry(object, "foo", 2.0);
+
+ QPropertyAnimation *anim = new QPropertyAnimation(object, "foo");
+ s1->addAnimatedTransition(new EventTransition(QEvent::User, s2), anim);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QTRY_COMPARE(s2->valueOnEntry.at(0).isValid(), true);
+ QCOMPARE(s2->valueOnEntry.at(0).toDouble(), 2.0);
+ QCOMPARE(anim->endValue().isValid(), false);
+}
+
+
+QTEST_MAIN(tst_QAnimationState)
+#include "tst_qanimationstate.moc"
diff --git a/tests/auto/qeasingcurve/qeasingcurve.pro b/tests/auto/qeasingcurve/qeasingcurve.pro
new file mode 100644
index 0000000..2b66081
--- /dev/null
+++ b/tests/auto/qeasingcurve/qeasingcurve.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT = core
+SOURCES += tst_qeasingcurve.cpp
diff --git a/tests/auto/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/qeasingcurve/tst_qeasingcurve.cpp
new file mode 100644
index 0000000..9e3ffcc
--- /dev/null
+++ b/tests/auto/qeasingcurve/tst_qeasingcurve.cpp
@@ -0,0 +1,488 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#if QT_VERSION < 0x040200
+QTEST_NOOP_MAIN
+#else
+
+#include <qeasingcurve.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QEasingCurve : public QObject {
+ Q_OBJECT
+
+public:
+ tst_QEasingCurve();
+ virtual ~tst_QEasingCurve();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ void type();
+ void propertyDefaults();
+ void valueForProgress_data();
+ void valueForProgress();
+ void setCustomType();
+ void operators();
+
+protected:
+};
+
+tst_QEasingCurve::tst_QEasingCurve()
+{
+}
+
+tst_QEasingCurve::~tst_QEasingCurve()
+{
+}
+
+void tst_QEasingCurve::init()
+{
+}
+
+void tst_QEasingCurve::cleanup()
+{
+}
+#include <qdebug.h>
+
+void tst_QEasingCurve::type()
+{
+ {
+ QEasingCurve curve(QEasingCurve::Linear);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+
+ curve.setPeriod(5);
+ curve.setAmplitude(3);
+ QCOMPARE(curve.period(), 5.0);
+ QCOMPARE(curve.amplitude(), 3.0);
+
+ curve.setType(QEasingCurve::InElastic);
+ QCOMPARE(curve.period(), 5.0);
+ QCOMPARE(curve.amplitude(), 3.0);
+ }
+
+ {
+ QEasingCurve curve(QEasingCurve::InElastic);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+ curve.setAmplitude(2);
+ QCOMPARE(curve.type(), QEasingCurve::InElastic);
+ curve.setType(QEasingCurve::Linear);
+ }
+
+ {
+ // check bounaries
+ QEasingCurve curve(QEasingCurve::InCubic);
+ QTest::ignoreMessage(QtWarningMsg, "QEasingCurve: Invalid curve type 9999");
+ curve.setType((QEasingCurve::Type)9999);
+ QCOMPARE(curve.type(), QEasingCurve::InCubic);
+ QTest::ignoreMessage(QtWarningMsg, "QEasingCurve: Invalid curve type -9999");
+ curve.setType((QEasingCurve::Type)-9999);
+ QCOMPARE(curve.type(), QEasingCurve::InCubic);
+ QTest::ignoreMessage(QtWarningMsg, QString::fromAscii("QEasingCurve: Invalid curve type %1")
+ .arg(QEasingCurve::NCurveTypes).toLatin1().constData());
+ curve.setType(QEasingCurve::NCurveTypes);
+ QCOMPARE(curve.type(), QEasingCurve::InCubic);
+ QTest::ignoreMessage(QtWarningMsg, QString::fromAscii("QEasingCurve: Invalid curve type %1")
+ .arg(QEasingCurve::Custom).toLatin1().constData());
+ curve.setType(QEasingCurve::Custom);
+ QCOMPARE(curve.type(), QEasingCurve::InCubic);
+ QTest::ignoreMessage(QtWarningMsg, QString::fromAscii("QEasingCurve: Invalid curve type %1")
+ .arg(-1).toLatin1().constData());
+ curve.setType((QEasingCurve::Type)-1);
+ QCOMPARE(curve.type(), QEasingCurve::InCubic);
+ curve.setType(QEasingCurve::Linear);
+ QCOMPARE(curve.type(), QEasingCurve::Linear);
+ curve.setType(QEasingCurve::CosineCurve);
+ QCOMPARE(curve.type(), QEasingCurve::CosineCurve);
+ }
+}
+
+void tst_QEasingCurve::propertyDefaults()
+{
+ {
+ // checks if the defaults are correct, but also demonstrates a weakness with the API.
+ QEasingCurve curve(QEasingCurve::InElastic);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+ QCOMPARE(curve.overshoot(), qreal(1.70158f));
+ curve.setType(QEasingCurve::InBounce);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+ QCOMPARE(curve.overshoot(), qreal(1.70158f));
+ curve.setType(QEasingCurve::Linear);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+ QCOMPARE(curve.overshoot(), qreal(1.70158f));
+ curve.setType(QEasingCurve::InElastic);
+ QCOMPARE(curve.period(), 0.3);
+ QCOMPARE(curve.amplitude(), 1.0);
+ QCOMPARE(curve.overshoot(), qreal(1.70158f));
+ curve.setPeriod(0.4);
+ curve.setAmplitude(0.6);
+ curve.setOvershoot(1.0);
+ curve.setType(QEasingCurve::Linear);
+ QCOMPARE(curve.period(), 0.4);
+ QCOMPARE(curve.amplitude(), 0.6);
+ QCOMPARE(curve.overshoot(), 1.0);
+ curve.setType(QEasingCurve::InElastic);
+ QCOMPARE(curve.period(), 0.4);
+ QCOMPARE(curve.amplitude(), 0.6);
+ QCOMPARE(curve.overshoot(), 1.0);
+ }
+}
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+
+void tst_QEasingCurve::valueForProgress_data()
+{
+ QTest::addColumn<int>("type");
+ QTest::addColumn<IntList>("at");
+ QTest::addColumn<IntList>("expected");
+ // automatically generated.
+ // note that values are scaled from range [0,1] to range [0, 100] in order to store them as
+ // integer values and avoid fp inaccuracies
+
+ QTest::newRow("Linear") << int(QEasingCurve::Linear)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100);
+
+ QTest::newRow("InQuad") << int(QEasingCurve::InQuad)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 4 << 16 << 36 << 64 << 100);
+
+ QTest::newRow("OutQuad") << int(QEasingCurve::OutQuad)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 36 << 64 << 84 << 96 << 100);
+
+ QTest::newRow("InOutQuad") << int(QEasingCurve::InOutQuad)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 8 << 32 << 68 << 92 << 100);
+
+ QTest::newRow("OutInQuad") << int(QEasingCurve::OutInQuad)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 32 << 48 << 52 << 68 << 100);
+
+ QTest::newRow("InCubic") << int(QEasingCurve::InCubic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 6 << 21 << 51 << 100);
+
+ QTest::newRow("OutCubic") << int(QEasingCurve::OutCubic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 48 << 78 << 93 << 99 << 100);
+
+ QTest::newRow("InOutCubic") << int(QEasingCurve::InOutCubic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 3 << 25 << 74 << 96 << 100);
+
+ QTest::newRow("OutInCubic") << int(QEasingCurve::OutInCubic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 39 << 49 << 50 << 60 << 100);
+
+ QTest::newRow("InQuart") << int(QEasingCurve::InQuart)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 2 << 12 << 40 << 100);
+
+ QTest::newRow("OutQuart") << int(QEasingCurve::OutQuart)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 59 << 87 << 97 << 99 << 100);
+
+ QTest::newRow("InOutQuart") << int(QEasingCurve::InOutQuart)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 1 << 20 << 79 << 98 << 100);
+
+ QTest::newRow("OutInQuart") << int(QEasingCurve::OutInQuart)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 43 << 49 << 50 << 56 << 100);
+
+ QTest::newRow("InQuint") << int(QEasingCurve::InQuint)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 1 << 7 << 32 << 100);
+
+ QTest::newRow("OutQuint") << int(QEasingCurve::OutQuint)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 67 << 92 << 98 << 99 << 100);
+
+ QTest::newRow("InOutQuint") << int(QEasingCurve::InOutQuint)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 16 << 83 << 99 << 100);
+
+ QTest::newRow("OutInQuint") << int(QEasingCurve::OutInQuint)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 46 << 49 << 50 << 53 << 100);
+
+ QTest::newRow("InSine") << int(QEasingCurve::InSine)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 4 << 19 << 41 << 69 << 100);
+
+ QTest::newRow("OutSine") << int(QEasingCurve::OutSine)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 30 << 58 << 80 << 95 << 100);
+
+ QTest::newRow("InOutSine") << int(QEasingCurve::InOutSine)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 9 << 34 << 65 << 90 << 100);
+
+ QTest::newRow("OutInSine") << int(QEasingCurve::OutInSine)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 29 << 47 << 52 << 70 << 100);
+
+ QTest::newRow("InExpo") << int(QEasingCurve::InExpo)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 1 << 6 << 24 << 100);
+
+ QTest::newRow("OutExpo") << int(QEasingCurve::OutExpo)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 75 << 93 << 98 << 99 << 100);
+
+ QTest::newRow("InOutExpo") << int(QEasingCurve::InOutExpo)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 12 << 87 << 99 << 100);
+
+ QTest::newRow("OutInExpo") << int(QEasingCurve::OutInExpo)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 46 << 49 << 50 << 53 << 100);
+
+ QTest::newRow("InCirc") << int(QEasingCurve::InCirc)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 2 << 8 << 19 << 40 << 100);
+
+ QTest::newRow("OutCirc") << int(QEasingCurve::OutCirc)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 59 << 80 << 91 << 97 << 100);
+
+ QTest::newRow("InOutCirc") << int(QEasingCurve::InOutCirc)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 4 << 20 << 80 << 95 << 100);
+
+ QTest::newRow("OutInCirc") << int(QEasingCurve::OutInCirc)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 40 << 48 << 51 << 60 << 100);
+
+ QTest::newRow("InElastic") << int(QEasingCurve::InElastic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << 1 << -3 << -12 << 100);
+
+ QTest::newRow("OutElastic") << int(QEasingCurve::OutElastic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 112 << 103 << 98 << 100 << 100);
+
+ QTest::newRow("InOutElastic") << int(QEasingCurve::InOutElastic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 0 << -6 << 106 << 99 << 100);
+
+ QTest::newRow("OutInElastic") << int(QEasingCurve::OutInElastic)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 56 << 49 << 49 << 53 << 100);
+
+ QTest::newRow("InBack") << int(QEasingCurve::InBack)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << -4 << -9 << -2 << 29 << 100);
+
+ QTest::newRow("OutBack") << int(QEasingCurve::OutBack)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 70 << 102 << 109 << 104 << 100);
+
+ QTest::newRow("InOutBack") << int(QEasingCurve::InOutBack)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << -9 << 8 << 91 << 109 << 100);
+
+ QTest::newRow("OutInBack") << int(QEasingCurve::OutInBack)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 51 << 52 << 47 << 48 << 100);
+
+ QTest::newRow("InBounce") << int(QEasingCurve::InBounce)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 6 << 22 << 8 << 69 << 100);
+
+ QTest::newRow("OutBounce") << int(QEasingCurve::OutBounce)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 30 << 91 << 77 << 93 << 100);
+
+ QTest::newRow("InOutBounce") << int(QEasingCurve::InOutBounce)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 11 << 34 << 65 << 88 << 100);
+
+ QTest::newRow("OutInBounce") << int(QEasingCurve::OutInBounce)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 41 << 43 << 56 << 58 << 100);
+
+ QTest::newRow("InCurve") << int(QEasingCurve::InCurve)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 10 << 37 << 60 << 80 << 100);
+
+ QTest::newRow("OutCurve") << int(QEasingCurve::OutCurve)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 20 << 39 << 62 << 89 << 100);
+
+ QTest::newRow("SineCurve") << int(QEasingCurve::SineCurve)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 0 << 34 << 90 << 90 << 34 << 0);
+
+ QTest::newRow("CosineCurve") << int(QEasingCurve::CosineCurve)
+ << (IntList() << 0 << 20 << 40 << 60 << 80 << 100)
+ << (IntList() << 50 << 97 << 79 << 20 << 2 << 49);
+
+
+}
+
+
+void tst_QEasingCurve::valueForProgress()
+{
+#if 0
+ // used to generate data tables...
+ QFile out;
+ out.open(stdout, QIODevice::WriteOnly);
+ for (int c = QEasingCurve::Linear; c < QEasingCurve::NCurveTypes - 1; ++c) {
+ QEasingCurve curve((QEasingCurve::Type)c);
+ QMetaObject mo = QEasingCurve::staticMetaObject;
+ QString strCurve = QLatin1String(mo.enumerator(mo.indexOfEnumerator("Type")).key(c));
+ QString strInputs;
+ QString strOutputs;
+
+ for (int t = 0; t <= 100; t+= 20) {
+ qreal ease = curve.valueForProgress(t/qreal(100));
+ strInputs += QString::fromAscii(" << %1").arg(t);
+ strOutputs += QString::fromAscii(" << %1").arg(int(100*ease));
+
+ }
+ QString str = QString::fromAscii(" QTest::newRow(\"%1\") << int(QEasingCurve::%2)\n"
+ "\t\t << (IntList() %3)\n"
+ "\t\t << (IntList() %4);\n\n")
+ .arg(strCurve)
+ .arg(strCurve)
+ .arg(strInputs)
+ .arg(strOutputs);
+ out.write(str.toLatin1().constData());
+ }
+ out.close();
+ exit(1);
+#else
+ QFETCH(int, type);
+ QFETCH(IntList, at);
+ QFETCH(IntList, expected);
+
+ QEasingCurve curve((QEasingCurve::Type)type);
+ for (int i = 0; i < at.count(); ++i) {
+ qreal ease = curve.valueForProgress(at.at(i)/qreal(100));
+ int ex = expected.at(i);
+ QCOMPARE(int(100*ease), ex);
+ }
+#endif
+}
+
+static qreal discreteEase(qreal progress)
+{
+ return qFloor(progress * 10) / qreal(10.0);
+}
+
+void tst_QEasingCurve::setCustomType()
+{
+ QEasingCurve curve;
+ curve.setCustomType(&discreteEase);
+ QCOMPARE(curve.type(), QEasingCurve::Custom);
+ QCOMPARE(curve.valueForProgress(0.0), 0.0);
+ QCOMPARE(curve.valueForProgress(0.05), 0.0);
+ QCOMPARE(curve.valueForProgress(0.10), 0.1);
+ QCOMPARE(curve.valueForProgress(0.15), 0.1);
+ QCOMPARE(curve.valueForProgress(0.20), 0.2);
+ QCOMPARE(curve.valueForProgress(0.25), 0.2);
+ QCOMPARE(curve.valueForProgress(0.30), 0.3);
+ QCOMPARE(curve.valueForProgress(0.35), 0.3);
+ QCOMPARE(curve.valueForProgress(0.999999), 0.9);
+
+ curve.setType(QEasingCurve::Linear);
+ QCOMPARE(curve.type(), QEasingCurve::Linear);
+ QCOMPARE(curve.valueForProgress(0.0), 0.0);
+ QCOMPARE(curve.valueForProgress(0.1), 0.1);
+ QCOMPARE(curve.valueForProgress(0.5), 0.5);
+ QCOMPARE(curve.valueForProgress(0.99), 0.99);
+}
+
+void tst_QEasingCurve::operators()
+{
+ // operator=
+ QEasingCurve curve;
+ QEasingCurve curve2;
+ curve.setCustomType(&discreteEase);
+ curve2 = curve;
+ QCOMPARE(curve2.type(), QEasingCurve::Custom);
+ QCOMPARE(curve2.valueForProgress(0.0), 0.0);
+ QCOMPARE(curve2.valueForProgress(0.05), 0.0);
+ QCOMPARE(curve2.valueForProgress(0.15), 0.1);
+ QCOMPARE(curve2.valueForProgress(0.25), 0.2);
+ QCOMPARE(curve2.valueForProgress(0.35), 0.3);
+ QCOMPARE(curve2.valueForProgress(0.999999), 0.9);
+
+ // operator==
+ curve.setType(QEasingCurve::InBack);
+ curve2 = curve;
+ curve2.setOvershoot(qreal(1.70158f));
+ QCOMPARE(curve.overshoot(), curve2.overshoot());
+ QVERIFY(curve2 == curve);
+
+ curve.setOvershoot(3.0);
+ QVERIFY(curve2 != curve);
+ curve2.setOvershoot(3.0);
+ QVERIFY(curve2 == curve);
+
+ curve2.setType(QEasingCurve::Linear);
+ QCOMPARE(curve.overshoot(), curve2.overshoot());
+ QVERIFY(curve2 != curve);
+ curve2.setType(QEasingCurve::InBack);
+ QCOMPARE(curve.overshoot(), curve2.overshoot());
+ QVERIFY(curve2 == curve);
+}
+
+
+QTEST_MAIN(tst_QEasingCurve)
+#include "tst_qeasingcurve.moc"
+
+#endif //QT_VERSION
diff --git a/tests/auto/qmake/testdata/bundle-spaces/some-file b/tests/auto/qmake/testdata/bundle-spaces/some-file
index e69de29..9975dba 100644
--- a/tests/auto/qmake/testdata/bundle-spaces/some-file
+++ b/tests/auto/qmake/testdata/bundle-spaces/some-file
@@ -0,0 +1,6 @@
+all:
+ C:\git\qt-kinetic-animations\bin\qmake qdir.pro -o Makefile -spec win32-msvc2008
+ nmake -f Makefile
+first: all
+qmake:
+ C:\git\qt-kinetic-animations\bin\qmake qdir.pro -o Makefile -spec win32-msvc2008
diff --git a/tests/auto/qparallelanimationgroup/qparallelanimationgroup.pro b/tests/auto/qparallelanimationgroup/qparallelanimationgroup.pro
new file mode 100644
index 0000000..f2cacd3
--- /dev/null
+++ b/tests/auto/qparallelanimationgroup/qparallelanimationgroup.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core gui
+SOURCES += tst_qparallelanimationgroup.cpp
+
+
diff --git a/tests/auto/qparallelanimationgroup/tst_qparallelanimationgroup.cpp b/tests/auto/qparallelanimationgroup/tst_qparallelanimationgroup.cpp
new file mode 100644
index 0000000..c7f33b7
--- /dev/null
+++ b/tests/auto/qparallelanimationgroup/tst_qparallelanimationgroup.cpp
@@ -0,0 +1,834 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtCore/qparallelanimationgroup.h>
+
+//TESTED_CLASS=QParallelAnimationGroup
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QAbstractAnimation::State)
+
+class tst_QParallelAnimationGroup : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QParallelAnimationGroup();
+ virtual ~tst_QParallelAnimationGroup();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ void construction();
+ void setCurrentTime();
+ void clearGroup();
+ void propagateGroupUpdateToChildren();
+ void updateChildrenWithRunningGroup();
+ void deleteChildrenWithRunningGroup();
+ void startChildrenWithStoppedGroup();
+ void stopGroupWithRunningChild();
+ void startGroupWithRunningChild();
+ void zeroDurationAnimation();
+ void stopUncontrolledAnimations();
+ void iterationCount_data();
+ void iterationCount();
+ void autoAdd();
+};
+
+tst_QParallelAnimationGroup::tst_QParallelAnimationGroup()
+{
+}
+
+tst_QParallelAnimationGroup::~tst_QParallelAnimationGroup()
+{
+}
+
+void tst_QParallelAnimationGroup::init()
+{
+ qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
+}
+
+void tst_QParallelAnimationGroup::cleanup()
+{
+}
+
+void tst_QParallelAnimationGroup::construction()
+{
+ QParallelAnimationGroup animationgroup;
+}
+
+class AnimationObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue)
+public:
+ AnimationObject(int startValue = 0)
+ : v(startValue)
+ { }
+
+ int value() const { return v; }
+ void setValue(int value) { v = value; }
+
+ int v;
+};
+
+class TestAnimation : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)};
+ virtual void updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+ {
+ Q_UNUSED(oldState)
+ Q_UNUSED(newState)
+ };
+};
+
+class TestAnimation2 : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ TestAnimation2(QAbstractAnimation *animation) : QVariantAnimation(animation) {}
+ TestAnimation2(int duration, QAbstractAnimation *animation) : QVariantAnimation(animation), m_duration(duration) {}
+
+ virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)};
+ virtual void updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+ {
+ Q_UNUSED(oldState)
+ Q_UNUSED(newState)
+ };
+
+ virtual int duration() const {
+ return m_duration;
+ }
+private:
+ int m_duration;
+};
+
+class UncontrolledAnimation : public QPropertyAnimation
+{
+ Q_OBJECT
+public:
+ UncontrolledAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0)
+ : QPropertyAnimation(target, propertyName, parent), id(0)
+ {
+ setDuration(250);
+ }
+
+ 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;
+};
+
+void tst_QParallelAnimationGroup::setCurrentTime()
+{
+ AnimationObject p_o1;
+ AnimationObject p_o2;
+ AnimationObject p_o3;
+ AnimationObject t_o1;
+ AnimationObject t_o2;
+
+ // parallel operating on different object/properties
+ QAnimationGroup *parallel = new QParallelAnimationGroup();
+ QVariantAnimation *a1_p_o1 = new QPropertyAnimation(&p_o1, "value");
+ QVariantAnimation *a1_p_o2 = new QPropertyAnimation(&p_o2, "value");
+ QVariantAnimation *a1_p_o3 = new QPropertyAnimation(&p_o3, "value");
+ a1_p_o2->setIterationCount(3);
+ parallel->addAnimation(a1_p_o1);
+ parallel->addAnimation(a1_p_o2);
+ parallel->addAnimation(a1_p_o3);
+
+ UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation(&t_o1, "value");
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ QVariantAnimation *loopsForever = new QPropertyAnimation(&t_o2, "value");
+ loopsForever->setIterationCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QParallelAnimationGroup group;
+ group.addAnimation(parallel);
+ group.addAnimation(notTimeDriven);
+ group.addAnimation(loopsForever);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(parallel->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_p_o3->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(a1_p_o1->currentTime(), 1);
+ QCOMPARE(a1_p_o2->currentTime(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 1);
+ QCOMPARE(notTimeDriven->currentTime(), 1);
+ QCOMPARE(loopsForever->currentTime(), 1);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentTime(), 250);
+ QCOMPARE(a1_p_o1->currentTime(), 250);
+ QCOMPARE(a1_p_o2->currentTime(), 0);
+ QCOMPARE(a1_p_o2->currentIteration(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 250);
+ QCOMPARE(loopsForever->currentTime(), 0);
+ QCOMPARE(loopsForever->currentIteration(), 1);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentTime(), 251);
+ QCOMPARE(a1_p_o1->currentTime(), 250);
+ QCOMPARE(a1_p_o2->currentTime(), 1);
+ QCOMPARE(a1_p_o2->currentIteration(), 1);
+ QCOMPARE(a1_p_o3->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 251);
+ QCOMPARE(loopsForever->currentTime(), 1);
+}
+
+void tst_QParallelAnimationGroup::clearGroup()
+{
+ QParallelAnimationGroup group;
+
+ for (int i = 0; i < 10; ++i) {
+ new QParallelAnimationGroup(&group);
+ }
+
+ QCOMPARE(group.animationCount(), 10);
+
+ int count = group.animationCount();
+ QPointer<QAbstractAnimation> *children = new QPointer<QAbstractAnimation>[count];
+ for (int i = 0; i < count; ++i) {
+ QVERIFY(group.animationAt(i) != 0);
+ children[i] = group.animationAt(i);
+ }
+
+ group.clearAnimations();
+ QCOMPARE(group.animationCount(), 0);
+ QCOMPARE(group.currentTime(), 0);
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(children[i], QPointer<QAbstractAnimation>());
+
+ delete[] children;
+}
+
+void tst_QParallelAnimationGroup::propagateGroupUpdateToChildren()
+{
+ // this test verifies if group state changes are updating its children correctly
+ QParallelAnimationGroup group;
+
+ QObject o;
+ o.setProperty("ole", 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ QPropertyAnimation anim1(&o, "ole");
+ anim1.setEndValue(43);
+ anim1.setDuration(100);
+ QVERIFY(!anim1.currentValue().isValid());
+ QCOMPARE(anim1.currentValue().toInt(), 0);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QVERIFY(anim2.currentValue().isValid());
+ QCOMPARE(anim2.currentValue().toInt(), 0);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Running);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(anim1.state(), QAnimationGroup::Paused);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QParallelAnimationGroup::updateChildrenWithRunningGroup()
+{
+ // assert that its possible to modify a child's state directly while their group is running
+ QParallelAnimationGroup group;
+
+ TestAnimation anim;
+ anim.setStartValue(0);
+ anim.setEndValue(100);
+ anim.setDuration(200);
+
+ QSignalSpy groupStateChangedSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy childStateChangedSpy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QCOMPARE(groupStateChangedSpy.count(), 0);
+ QCOMPARE(childStateChangedSpy.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Running);
+
+ QCOMPARE(groupStateChangedSpy.count(), 1);
+ QCOMPARE(childStateChangedSpy.count(), 1);
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(childStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::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(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Paused);
+
+ // in the animation stops directly, the group will still be running
+ anim.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QParallelAnimationGroup::deleteChildrenWithRunningGroup()
+{
+ // test if children can be activated when their group is stopped
+ QParallelAnimationGroup group;
+
+ QVariantAnimation *anim1 = new TestAnimation;
+ anim1->setStartValue(0);
+ anim1->setEndValue(100);
+ anim1->setDuration(200);
+ group.addAnimation(anim1);
+
+ QCOMPARE(group.duration(), anim1->duration());
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1->state(), QAnimationGroup::Running);
+
+ QTest::qWait(50);
+ QVERIFY(group.currentTime() > 0);
+
+ delete anim1;
+ QVERIFY(group.animationCount() == 0);
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.currentTime(), 0); //that's the invariant
+}
+
+void tst_QParallelAnimationGroup::startChildrenWithStoppedGroup()
+{
+ // test if children can be activated when their group is stopped
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(200);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+}
+
+void tst_QParallelAnimationGroup::stopGroupWithRunningChild()
+{
+ // children that started independently will not be affected by a group stop
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(200);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ anim1.stop();
+ anim2.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QParallelAnimationGroup::startGroupWithRunningChild()
+{
+ // as the group has precedence over its children, starting a group will restart all the children
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(200);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QSignalSpy stateChangedSpy1(&anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy stateChangedSpy2(&anim2, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ QCOMPARE(stateChangedSpy2.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(1).at(1)),
+ QAnimationGroup::Paused);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ group.start();
+
+ QCOMPARE(stateChangedSpy1.count(), 3);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(1).at(1)),
+ QAnimationGroup::Stopped);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(2).at(1)),
+ QAnimationGroup::Running);
+
+ QCOMPARE(stateChangedSpy2.count(), 4);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(2).at(1)),
+ QAnimationGroup::Stopped);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(3).at(1)),
+ QAnimationGroup::Running);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Running);
+}
+
+void tst_QParallelAnimationGroup::zeroDurationAnimation()
+{
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(0);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(100);
+
+ QSignalSpy stateChangedSpy1(&anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy finishedSpy1(&anim1, SIGNAL(finished()));
+
+ QSignalSpy stateChangedSpy2(&anim2, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy finishedSpy2(&anim2, SIGNAL(finished()));
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ group.start();
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(finishedSpy1.count(), 1);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(1).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ QCOMPARE(finishedSpy2.count(), 0);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy1.at(0).at(1)),
+ QAnimationGroup::Running);
+
+
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Running);
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+
+
+ group.stop();
+ group.setIterationCount(4);
+ stateChangedSpy1.clear();
+ stateChangedSpy2.clear();
+
+ group.start();
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ group.setCurrentTime(50);
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ group.setCurrentTime(150);
+ QCOMPARE(stateChangedSpy1.count(), 4);
+ QCOMPARE(stateChangedSpy2.count(), 3);
+ group.setCurrentTime(50);
+ QCOMPARE(stateChangedSpy1.count(), 6);
+ QCOMPARE(stateChangedSpy2.count(), 5);
+
+}
+
+void tst_QParallelAnimationGroup::stopUncontrolledAnimations()
+{
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(0);
+
+ AnimationObject o1;
+ UncontrolledAnimation notTimeDriven(&o1, "value");
+ QCOMPARE(notTimeDriven.totalDuration(), -1);
+
+ TestAnimation loopsForever;
+ loopsForever.setStartValue(0);
+ loopsForever.setEndValue(100);
+ loopsForever.setDuration(100);
+ loopsForever.setIterationCount(-1);
+
+ QSignalSpy stateChangedSpy(&anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&notTimeDriven);
+ group.addAnimation(&loopsForever);
+
+ group.start();
+
+ QCOMPARE(stateChangedSpy.count(), 2);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+
+ notTimeDriven.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::Running);
+
+ loopsForever.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::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 QAbstractAnimation::Running
+#define Stopped QAbstractAnimation::Stopped
+
+Q_DECLARE_METATYPE(AnimState)
+void tst_QParallelAnimationGroup::iterationCount_data()
+{
+ QTest::addColumn<bool>("directionBackward");
+ QTest::addColumn<int>("setIterationCount");
+ 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_QParallelAnimationGroup::iterationCount()
+{
+ QFETCH(bool, directionBackward);
+ QFETCH(int, setIterationCount);
+ QFETCH(int, initialGroupTime);
+ QFETCH(int, currentGroupTime);
+ QFETCH(AnimState, expected1);
+ QFETCH(AnimState, expected2);
+ QFETCH(AnimState, expected3);
+
+ QParallelAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(100);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(60); //total 120
+ anim2.setIterationCount(2);
+
+ TestAnimation anim3;
+ anim3.setStartValue(0);
+ anim3.setEndValue(100);
+ anim3.setDuration(0);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+ group.addAnimation(&anim3);
+
+ group.setIterationCount(setIterationCount);
+ if (initialGroupTime >= 0)
+ group.setCurrentTime(initialGroupTime);
+ if (directionBackward)
+ group.setDirection(QAbstractAnimation::Backward);
+
+ group.start();
+ if (initialGroupTime >= 0)
+ group.setCurrentTime(initialGroupTime);
+
+ anim1.setCurrentTime(42); // 42 is "untouched"
+ anim2.setCurrentTime(42);
+
+ group.setCurrentTime(currentGroupTime);
+
+ QCOMPARE(anim1.currentTime(), expected1.time);
+ QCOMPARE(anim2.currentTime(), expected2.time);
+ QCOMPARE(anim3.currentTime(), 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_QParallelAnimationGroup::autoAdd()
+{
+ QParallelAnimationGroup group;
+ QCOMPARE(group.duration(), 0);
+ TestAnimation2 *test = new TestAnimation2(250, &group); // 0, duration = 250;
+ QCOMPARE(test->group(), &group);
+ QCOMPARE(test->duration(), 250);
+ QCOMPARE(group.duration(), 250);
+
+ test = new TestAnimation2(750, &group); // 1
+ QCOMPARE(test->group(), &group);
+ QCOMPARE(group.duration(), 750);
+ test = new TestAnimation2(500, &group); // 2
+ QCOMPARE(test->group(), &group);
+ QCOMPARE(group.duration(), 750);
+
+ delete group.animationAt(1); // remove the one with duration = 750
+ QCOMPARE(group.duration(), 500);
+
+ delete group.animationAt(1); // remove the one with duration = 500
+ QCOMPARE(group.duration(), 250);
+
+ test = static_cast<TestAnimation2*>(group.animationAt(0));
+ test->setParent(0); // remove the last one (with duration = 250)
+ QCOMPARE(test->group(), static_cast<QAnimationGroup*>(0));
+ QCOMPARE(group.duration(), 0);
+}
+
+QTEST_MAIN(tst_QParallelAnimationGroup)
+#include "tst_qparallelanimationgroup.moc"
diff --git a/tests/auto/qpropertyanimation/qpropertyanimation.pro b/tests/auto/qpropertyanimation/qpropertyanimation.pro
new file mode 100644
index 0000000..6d6ddbf
--- /dev/null
+++ b/tests/auto/qpropertyanimation/qpropertyanimation.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core gui
+SOURCES += tst_qpropertyanimation.cpp
+
+
diff --git a/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp
new file mode 100644
index 0000000..f61df49
--- /dev/null
+++ b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp
@@ -0,0 +1,831 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtCore/qpropertyanimation.h>
+#include <QtGui/qitemanimation.h>
+#include <QtGui/qwidget.h>
+
+//TESTED_CLASS=QPropertyAnimation
+//TESTED_FILES=
+
+class UncontrolledAnimation : public QPropertyAnimation
+{
+ Q_OBJECT
+public:
+ int duration() const { return -1; /* not time driven */ }
+
+protected:
+ void updateCurrentTime(int msecs)
+ {
+ QPropertyAnimation::updateCurrentTime(msecs);
+ if (msecs >= QPropertyAnimation::duration())
+ stop();
+ }
+};
+
+class tst_QPropertyAnimation : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QPropertyAnimation();
+ virtual ~tst_QPropertyAnimation();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ void construction();
+ void setCurrentTime_data();
+ void setCurrentTime();
+ void statesAndSignals_data();
+ void statesAndSignals();
+ void deletion1();
+ void deletion2();
+ void deletion3();
+ void duration0();
+ void noStartValue();
+ void startWhenAnotherIsRunning();
+ void easingcurve_data();
+ void easingcurve();
+ void startWithoutStartValue();
+ void playForwardBackward();
+ void interpolated();
+ void setStartEndValues();
+ void zeroDurationStart();
+ void operationsInStates_data();
+ void operationsInStates();
+};
+
+tst_QPropertyAnimation::tst_QPropertyAnimation()
+{
+}
+
+tst_QPropertyAnimation::~tst_QPropertyAnimation()
+{
+}
+
+void tst_QPropertyAnimation::init()
+{
+ qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
+ qRegisterMetaType<QAbstractAnimation::DeletionPolicy>("QAbstractAnimation::DeletionPolicy");
+}
+
+void tst_QPropertyAnimation::cleanup()
+{
+}
+
+class AnimationObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue)
+ Q_PROPERTY(qreal realValue READ realValue WRITE setRealValue)
+public:
+ AnimationObject(int startValue = 0)
+ : v(startValue)
+ { }
+
+ int value() const { return v; }
+ void setValue(int value) { v = value; }
+
+ qreal realValue() const { return rv; }
+ void setRealValue(qreal value) { rv = value; }
+
+ int v;
+ qreal rv;
+};
+
+
+void tst_QPropertyAnimation::construction()
+{
+ QPropertyAnimation panimation;
+}
+
+void tst_QPropertyAnimation::setCurrentTime_data()
+{
+ QTest::addColumn<int>("duration");
+ QTest::addColumn<int>("iterationCount");
+ QTest::addColumn<int>("currentTime");
+ QTest::addColumn<int>("testCurrentTime");
+ QTest::addColumn<int>("testCurrentLoop");
+
+ QTest::newRow("-1") << -1 << 1 << 0 << 0 << 0;
+ QTest::newRow("0") << 0 << 1 << 0 << 0 << 0;
+ QTest::newRow("1") << 0 << 1 << 1 << 0 << 0;
+ QTest::newRow("2") << 0 << 2 << 1 << 0 << 0;
+ QTest::newRow("3") << 1 << 1 << 0 << 0 << 0;
+ QTest::newRow("4") << 1 << 1 << 1 << 1 << 0;
+ QTest::newRow("5") << 1 << 2 << 1 << 0 << 1;
+ QTest::newRow("6") << 1 << 2 << 2 << 1 << 1;
+ QTest::newRow("7") << 1 << 2 << 3 << 1 << 1;
+ QTest::newRow("8") << 1 << 3 << 2 << 0 << 2;
+ QTest::newRow("9") << 1 << 3 << 3 << 1 << 2;
+ QTest::newRow("a") << 10 << 1 << 0 << 0 << 0;
+ QTest::newRow("b") << 10 << 1 << 1 << 1 << 0;
+ QTest::newRow("c") << 10 << 1 << 10 << 10 << 0;
+ QTest::newRow("d") << 10 << 2 << 10 << 0 << 1;
+ QTest::newRow("e") << 10 << 2 << 11 << 1 << 1;
+ QTest::newRow("f") << 10 << 2 << 20 << 10 << 1;
+ QTest::newRow("g") << 10 << 2 << 21 << 10 << 1;
+ QTest::newRow("negloop 0") << 10 << -1 << 0 << 0 << 0;
+ QTest::newRow("negloop 1") << 10 << -1 << 10 << 0 << 1;
+ QTest::newRow("negloop 2") << 10 << -1 << 15 << 5 << 1;
+ QTest::newRow("negloop 3") << 10 << -1 << 20 << 0 << 2;
+ QTest::newRow("negloop 4") << 10 << -1 << 30 << 0 << 3;
+}
+
+void tst_QPropertyAnimation::setCurrentTime()
+{
+ QFETCH(int, duration);
+ QFETCH(int, iterationCount);
+ QFETCH(int, currentTime);
+ QFETCH(int, testCurrentTime);
+ QFETCH(int, testCurrentLoop);
+
+ QPropertyAnimation animation;
+ if (duration < 0)
+ QTest::ignoreMessage(QtWarningMsg, "QVariantAnimation::setDuration: cannot set a negative duration");
+ animation.setDuration(duration);
+ animation.setIterationCount(iterationCount);
+ animation.setCurrentTime(currentTime);
+
+ QCOMPARE(animation.currentTime(), testCurrentTime);
+ QCOMPARE(animation.currentIteration(), testCurrentLoop);
+}
+
+void tst_QPropertyAnimation::statesAndSignals_data()
+{
+ QTest::addColumn<bool>("uncontrolled");
+ QTest::newRow("normal animation") << false;
+ QTest::newRow("animation with undefined duration") << true;
+}
+
+void tst_QPropertyAnimation::statesAndSignals()
+{
+ QFETCH(bool, uncontrolled);
+ QPropertyAnimation *anim = uncontrolled ? new UncontrolledAnimation : new QPropertyAnimation;
+ anim->setDuration(100);
+
+ QSignalSpy finishedSpy(anim, SIGNAL(finished()));
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy currentLoopSpy(anim, SIGNAL(currentIterationChanged(int)));
+
+ anim->setCurrentTime(1);
+ anim->setCurrentTime(100);
+ QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(runningSpy.count(), 0);
+ QCOMPARE(currentLoopSpy.count(), 0);
+ QCOMPARE(anim->state(), QAnimationGroup::Stopped);
+
+ anim->setIterationCount(3);
+ anim->setCurrentTime(101);
+
+ if (uncontrolled)
+ QSKIP("Uncontrolled animations don't handle looping", SkipSingle);
+
+ QCOMPARE(currentLoopSpy.count(), 1);
+ QCOMPARE(anim->currentIteration(), 1);
+
+ anim->setCurrentTime(0);
+ QCOMPARE(currentLoopSpy.count(), 2);
+ QCOMPARE(anim->currentIteration(), 0);
+
+ anim->start();
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QCOMPARE(runningSpy.count(), 1); //anim must have started
+ QCOMPARE(anim->currentIteration(), 0);
+ runningSpy.clear();
+
+ anim->stop();
+ QCOMPARE(anim->state(), QAnimationGroup::Stopped);
+ QCOMPARE(runningSpy.count(), 1); //anim must have stopped
+ QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(anim->currentTime(), 0);
+ QCOMPARE(anim->currentIteration(), 0);
+ QCOMPARE(currentLoopSpy.count(), 2);
+ runningSpy.clear();
+
+ anim->start();
+ QTest::qWait(1000);
+ QCOMPARE(anim->state(), QAnimationGroup::Stopped);
+ QCOMPARE(runningSpy.count(), 2); //started and stopped again
+ runningSpy.clear();
+ QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(anim->currentTime(), 100);
+ QCOMPARE(anim->currentIteration(), 2);
+ QCOMPARE(currentLoopSpy.count(), 4);
+
+ anim->start(); // auto-rewinds
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QCOMPARE(anim->currentTime(), 0);
+ QCOMPARE(anim->currentIteration(), 0);
+ QCOMPARE(currentLoopSpy.count(), 5);
+ QCOMPARE(runningSpy.count(), 1); // anim has started
+ QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(anim->currentIteration(), 0);
+ runningSpy.clear();
+
+ QTest::qWait(1000);
+
+ QCOMPARE(currentLoopSpy.count(), 7);
+ QCOMPARE(anim->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim->currentIteration(), 2);
+ QCOMPARE(runningSpy.count(), 1); // anim has stopped
+ QCOMPARE(finishedSpy.count(), 2);
+ QCOMPARE(anim->currentTime(), 100);
+
+ delete anim;
+}
+
+void tst_QPropertyAnimation::deletion1()
+{
+ QObject *object = new QWidget;
+ QPointer<QPropertyAnimation> anim = new QPropertyAnimation(object,"minimumWidth");
+
+ //test that the animation is deleted correctly depending of the deletion flag passed in start()
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy finishedSpy(anim, SIGNAL(finished()));
+ anim->setStartValue(10);
+ anim->setEndValue(20);
+ anim->setDuration(200);
+ anim->start();
+ QCOMPARE(runningSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+
+ QVERIFY(anim);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QTest::qWait(100);
+ QVERIFY(anim);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QTest::qWait(150);
+ QVERIFY(anim); //The animation should not have been deleted
+ QCOMPARE(anim->state(), QAnimationGroup::Stopped);
+ QCOMPARE(runningSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 1);
+
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+ QVERIFY(anim);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QTest::qWait(100);
+ QVERIFY(anim);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QTest::qWait(150);
+ QVERIFY(!anim); //The animation must have been deleted
+ QCOMPARE(runningSpy.count(), 4);
+ QCOMPARE(finishedSpy.count(), 2);
+ delete object;
+}
+
+void tst_QPropertyAnimation::deletion2()
+{
+ //test that the animation get deleted if the object is deleted
+ QObject *object = new QWidget;
+ QPointer<QPropertyAnimation> anim = new QPropertyAnimation(object,"minimumWidth");
+ anim->setStartValue(10);
+ anim->setEndValue(20);
+ anim->setDuration(200);
+
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy finishedSpy(anim, SIGNAL(finished()));
+
+ anim->setStartValue(10);
+ anim->setEndValue(20);
+ anim->setDuration(200);
+ anim->start();
+
+ QTest::qWait(50);
+ QVERIFY(anim);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+
+ QCOMPARE(runningSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+
+ //we can't call deletaLater directly because the delete would only happen in the next iteration of _this_ event loop
+ QTimer::singleShot(0, object, SLOT(deleteLater()));
+ QTest::qWait(50);
+
+ QVERIFY(anim->targetObject() == 0);
+}
+
+void tst_QPropertyAnimation::deletion3()
+{
+ //test that the stopped signal is emit when the animation is destroyed
+ QObject *object = new QWidget;
+ QPropertyAnimation *anim = new QPropertyAnimation(object,"minimumWidth");
+ anim->setStartValue(10);
+ anim->setEndValue(20);
+ anim->setDuration(200);
+
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy finishedSpy(anim, SIGNAL(finished()));
+ anim->start();
+
+ QTest::qWait(50);
+ QCOMPARE(anim->state(), QAnimationGroup::Running);
+ QCOMPARE(runningSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+ delete anim;
+ QCOMPARE(runningSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 0);
+}
+
+void tst_QPropertyAnimation::duration0()
+{
+ QObject o;
+ o.setProperty("ole", 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ QPropertyAnimation animation(&o, "ole");
+ animation.setEndValue(43);
+ QVERIFY(!animation.currentValue().isValid());
+ QCOMPARE(animation.currentValue().toInt(), 0);
+ QCOMPARE(o.property("ole").toInt(), 42);
+ animation.setDuration(0);
+ animation.start();
+ QCOMPARE(animation.state(), QAnimationGroup::Stopped);
+ QCOMPARE(animation.currentTime(), 0);
+ QCOMPARE(o.property("ole").toInt(), 43);
+}
+
+class StartValueTester : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int ole READ ole WRITE setOle)
+public:
+ StartValueTester() : o(0) { }
+ int ole() const { return o; }
+ void setOle(int v) { o = v; values << v; }
+
+ int o;
+ QList<int> values;
+};
+
+void tst_QPropertyAnimation::noStartValue()
+{
+ StartValueTester o;
+ o.setProperty("ole", 42);
+ o.values.clear();
+
+ QPropertyAnimation a(&o, "ole");
+ a.setEndValue(420);
+ a.setDuration(250);
+ a.start();
+
+ QTest::qWait(300);
+
+ QCOMPARE(o.values.first(), 42);
+ QCOMPARE(o.values.last(), 420);
+}
+
+void tst_QPropertyAnimation::startWhenAnotherIsRunning()
+{
+ StartValueTester o;
+ o.setProperty("ole", 42);
+ o.values.clear();
+
+ {
+ //normal case: the animation finishes and is deleted
+ QPointer<QVariantAnimation> anim = new QPropertyAnimation(&o, "ole");
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+ QTest::qWait(anim->duration() + 50);
+ QCOMPARE(runningSpy.count(), 2); //started and then stopped
+ QVERIFY(!anim);
+ }
+
+ {
+ QPointer<QVariantAnimation> anim = new QPropertyAnimation(&o, "ole");
+ QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+ QTest::qWait(anim->duration()/2);
+ QPointer<QVariantAnimation> anim2 = new QPropertyAnimation(&o, "ole");
+ QCOMPARE(runningSpy.count(), 1);
+ QCOMPARE(anim->state(), QVariantAnimation::Running);
+
+ //anim2 will interrupt anim1
+ QMetaObject::invokeMethod(anim2, "start", Qt::QueuedConnection, Q_ARG(QAbstractAnimation::DeletionPolicy, QVariantAnimation::DeleteWhenStopped));
+ QTest::qWait(50);
+ QVERIFY(!anim); //anim should have been deleted
+ QVERIFY(anim2);
+ QTest::qWait(anim2->duration());
+ QVERIFY(!anim2); //anim2 is finished: it should have been deleted by now
+ QVERIFY(!anim);
+ }
+
+}
+
+// copy from easing.cpp in case that function changes definition
+static qreal easeInOutBack(qreal t)
+{
+ qreal s = 1.70158;
+ qreal t_adj = 2.0f * (qreal)t;
+ if (t_adj < 1) {
+ s *= 1.525f;
+ return 1.0/2*(t_adj*t_adj*((s+1)*t_adj - s));
+ } else {
+ t_adj -= 2;
+ s *= 1.525f;
+ return 1.0/2*(t_adj*t_adj*((s+1)*t_adj + s) + 2);
+ }
+}
+
+void tst_QPropertyAnimation::easingcurve_data()
+{
+ QTest::addColumn<int>("currentTime");
+ QTest::addColumn<int>("expectedvalue");
+
+ QTest::newRow("interpolation1") << 0 << 0;
+ QTest::newRow("interpolation2") << 1000 << 1000;
+ QTest::newRow("extrapolationbelow") << 250 << -99;
+ QTest::newRow("extrapolationabove") << 750 << 1099;
+}
+
+void tst_QPropertyAnimation::easingcurve()
+{
+ QFETCH(int, currentTime);
+ QFETCH(int, expectedvalue);
+ QObject o;
+ o.setProperty("ole", 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ QPropertyAnimation pAnimation(&o, "ole");
+ pAnimation.setStartValue(0);
+ pAnimation.setEndValue(1000);
+ pAnimation.setDuration(1000);
+
+ // this easingcurve assumes that we extrapolate before startValue and after endValue
+ QEasingCurve easingCurve;
+ easingCurve.setCustomType(easeInOutBack);
+ pAnimation.setEasingCurve(easingCurve);
+ pAnimation.start();
+ pAnimation.pause();
+ pAnimation.setCurrentTime(currentTime);
+ QCOMPARE(o.property("ole").toInt(), expectedvalue);
+}
+
+void tst_QPropertyAnimation::startWithoutStartValue()
+{
+ QObject o;
+ o.setProperty("ole", 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ QPropertyAnimation anim(&o, "ole");
+ anim.setEndValue(100);
+
+ anim.start();
+
+ QTest::qWait(100);
+ int current = anim.currentValue().toInt();
+ //it is somewhere in the animation
+ QVERIFY(current > 42);
+ QVERIFY(current < 100);
+
+ QTest::qWait(200);
+ QCOMPARE(anim.state(), QVariantAnimation::Stopped);
+
+ anim.setEndValue(110);
+ anim.start();
+ current = anim.currentValue().toInt();
+ QCOMPARE(current, 42); // the initial default start value
+
+ QTest::qWait(100);
+ current = anim.currentValue().toInt();
+ //it is somewhere in the animation
+ QVERIFY(current > 42);
+ QVERIFY(current < 110);
+}
+
+void tst_QPropertyAnimation::playForwardBackward()
+{
+ QObject o;
+ o.setProperty("ole", 0);
+ QCOMPARE(o.property("ole").toInt(), 0);
+
+ QPropertyAnimation anim(&o, "ole");
+ anim.setEndValue(100);
+ anim.start();
+ QTest::qWait(anim.duration() + 50);
+ QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
+ QCOMPARE(anim.currentTime(), anim.duration());
+
+ //the animation is at the end
+ anim.setDirection(QVariantAnimation::Backward);
+ anim.start();
+ QCOMPARE(anim.state(), QAbstractAnimation::Running);
+ QTest::qWait(anim.duration() + 50);
+ QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
+ QCOMPARE(anim.currentTime(), 0);
+
+ //the direction is backward
+ //restarting should jump to the end
+ anim.start();
+ QCOMPARE(anim.state(), QAbstractAnimation::Running);
+ QCOMPARE(anim.currentTime(), anim.duration());
+ QTest::qWait(anim.duration() + 50);
+ QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
+ QCOMPARE(anim.currentTime(), 0);
+}
+
+struct Number
+{
+ Number() {}
+ Number(int n)
+ : n(n) {}
+
+ Number(const Number &other)
+ : n(other.n){}
+
+ Number &operator=(const Number &other) {
+ n = other.n;
+ return *this;
+ }
+ bool operator==(const Number &other) const {
+ return n == other.n;
+ }
+
+ int n;
+};
+
+Q_DECLARE_METATYPE(Number)
+Q_DECLARE_METATYPE(QAbstractAnimation::State)
+
+QVariant numberInterpolator(const Number &f, const Number &t, qreal progress)
+{
+ return qVariantFromValue<Number>(Number(f.n + (t.n - f.n)*progress));
+}
+
+QVariant xaxisQPointInterpolator(const QPointF &f, const QPointF &t, qreal progress)
+{
+ return QPointF(f.x() + (t.x() - f.x())*progress, f.y());
+}
+
+void tst_QPropertyAnimation::interpolated()
+{
+ QObject o;
+ o.setProperty("number", qVariantFromValue<Number>(Number(42)));
+ QCOMPARE(qVariantValue<Number>(o.property("number")), Number(42));
+ {
+ qRegisterAnimationInterpolator<Number>(numberInterpolator);
+ QPropertyAnimation anim(&o, "number");
+ anim.setStartValue(qVariantFromValue<Number>(Number(0)));
+ anim.setEndValue(qVariantFromValue<Number>(Number(100)));
+ anim.setDuration(1000);
+ anim.start();
+ anim.pause();
+ anim.setCurrentTime(100);
+ Number t(qVariantValue<Number>(o.property("number")));
+ QCOMPARE(t, Number(10));
+ anim.setCurrentTime(500);
+ QCOMPARE(qVariantValue<Number>(o.property("number")), Number(50));
+ }
+ {
+ qRegisterAnimationInterpolator<QPointF>(xaxisQPointInterpolator);
+ QPropertyAnimation anim(&o, "point");
+ anim.setStartValue(QPointF(0,0));
+ anim.setEndValue(QPointF(100, 100));
+ anim.setDuration(1000);
+ anim.start();
+ anim.pause();
+ anim.setCurrentTime(100);
+ QCOMPARE(o.property("point").toPointF(), QPointF(10, 0));
+ anim.setCurrentTime(500);
+ QCOMPARE(o.property("point").toPointF(), QPointF(50, 0));
+ }
+ {
+ // unregister it and see if we get back the default behaviour
+ qRegisterAnimationInterpolator<QPointF>(0);
+ QPropertyAnimation anim(&o, "point");
+ anim.setStartValue(QPointF(0,0));
+ anim.setEndValue(QPointF(100, 100));
+ anim.setDuration(1000);
+ anim.start();
+ anim.pause();
+ anim.setCurrentTime(100);
+ QCOMPARE(o.property("point").toPointF(), QPointF(10, 10));
+ anim.setCurrentTime(500);
+ QCOMPARE(o.property("point").toPointF(), QPointF(50, 50));
+ }
+
+ {
+ // Interpolate a qreal property with a int interpolator
+ AnimationObject o1;
+ o1.setRealValue(42.42);
+ QPropertyAnimation anim(&o1, "realValue");
+ anim.setStartValue(0);
+ anim.setEndValue(100);
+ anim.start();
+ QCOMPARE(o1.realValue(), qreal(0));
+ anim.setCurrentTime(250);
+ QCOMPARE(o1.realValue(), qreal(100));
+ }
+}
+
+void tst_QPropertyAnimation::setStartEndValues()
+{
+ //this tests the start value, end value and default start value
+ QObject o;
+ o.setProperty("ole", 42);
+ QPropertyAnimation anim(&o, "ole");
+ QVariantAnimation::KeyValues values;
+ QCOMPARE(anim.keyValues(), values);
+
+ //let's add a start value
+ anim.setStartValue(0);
+ values << QVariantAnimation::KeyValue(0, 0);
+ QCOMPARE(anim.keyValues(), values);
+
+ anim.setEndValue(10);
+ values << QVariantAnimation::KeyValue(1, 10);
+ QCOMPARE(anim.keyValues(), values);
+
+ //now we can play with objects
+ QCOMPARE(o.property("ole").toInt(), 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+ anim.start();
+ QVERIFY(anim.startValue().isValid());
+ QCOMPARE(o.property("ole"), anim.startValue());
+
+ //now we remove the explicit start value and test the implicit one
+ anim.stop();
+ o.setProperty("ole", 42);
+ values.remove(0);
+ anim.setStartValue(QVariant()); //reset the start value
+ QCOMPARE(anim.keyValues(), values);
+ QVERIFY(!anim.startValue().isValid());
+ anim.start();
+ QCOMPARE(o.property("ole").toInt(), 42);
+ anim.setCurrentTime(anim.duration()/2);
+ QCOMPARE(o.property("ole").toInt(), 26); //just in the middle of the animation
+ anim.setCurrentTime(anim.duration());
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped); //it should have stopped
+ QVERIFY(anim.endValue().isValid());
+ QCOMPARE(o.property("ole"), anim.endValue()); //end of the animations
+
+ //now we set back the startValue
+ anim.setStartValue(5);
+ QVERIFY(anim.startValue().isValid());
+ anim.start();
+ QCOMPARE(o.property("ole").toInt(), 5);
+}
+
+void tst_QPropertyAnimation::zeroDurationStart()
+{
+ QPropertyAnimation anim;
+ QSignalSpy spy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ anim.setDuration(0);
+ QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
+ anim.start();
+ //the animation stops immediately
+ QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
+ QCOMPARE(spy.count(), 2);
+
+ //let's check the first state change
+ const QVariantList firstChange = spy.first();
+ //old state
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(firstChange.first()), QAbstractAnimation::Stopped);
+ //new state
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(firstChange.last()), QAbstractAnimation::Running);
+
+ //let's check the first state change
+ const QVariantList secondChange = spy.last();
+ //old state
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(secondChange.first()), QAbstractAnimation::Running);
+ //new state
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(secondChange.last()), QAbstractAnimation::Stopped);
+}
+
+#define Pause 1
+#define Start 2
+#define Resume 3
+#define Stop 4
+
+void tst_QPropertyAnimation::operationsInStates_data()
+{
+ QTest::addColumn<QAbstractAnimation::State>("originState");
+ QTest::addColumn<int>("operation");
+ QTest::addColumn<QString>("expectedWarning");
+ QTest::addColumn<QAbstractAnimation::State>("expectedState");
+
+ QString pauseWarn(QLatin1String("QAbstractAnimation::pause: Cannot pause a stopped animation"));
+ QString resumeWarn(QLatin1String("QAbstractAnimation::resume: Cannot resume an animation that is not paused"));
+
+ QTest::newRow("S-pause") << QAbstractAnimation::Stopped << Pause << pauseWarn << QAbstractAnimation::Stopped;
+ QTest::newRow("S-start") << QAbstractAnimation::Stopped << Start << QString() << QAbstractAnimation::Running;
+ QTest::newRow("S-resume") << QAbstractAnimation::Stopped << Resume << resumeWarn << QAbstractAnimation::Stopped;
+ QTest::newRow("S-stop") << QAbstractAnimation::Stopped << Stop << QString() << QAbstractAnimation::Stopped;
+
+ QTest::newRow("P-pause") << QAbstractAnimation::Paused << Pause << QString() << QAbstractAnimation::Paused;
+ QTest::newRow("P-start") << QAbstractAnimation::Paused << Start << QString() << QAbstractAnimation::Running;
+ QTest::newRow("P-resume") << QAbstractAnimation::Paused << Resume << QString() << QAbstractAnimation::Running;
+ QTest::newRow("P-stop") << QAbstractAnimation::Paused << Stop << QString() << QAbstractAnimation::Stopped;
+
+ QTest::newRow("R-pause") << QAbstractAnimation::Running << Pause << QString() << QAbstractAnimation::Paused;
+ QTest::newRow("R-start") << QAbstractAnimation::Running << Start << QString() << QAbstractAnimation::Running;
+ QTest::newRow("R-resume") << QAbstractAnimation::Running << Resume << resumeWarn << QAbstractAnimation::Running;
+ QTest::newRow("R-stop") << QAbstractAnimation::Running << Stop << QString() << QAbstractAnimation::Stopped;
+}
+
+void tst_QPropertyAnimation::operationsInStates()
+{
+/**
+ * | pause() |start() |resume() |stop()
+ * ----------+------------+-----------+-----------+-------------------+
+ * Stopped | Stopped |Running |Stopped |Stopped |
+ * _| qWarning | |qWarning |- |
+ * Paused | Paused |Running |Running |Stopped |
+ * _| - | | | |
+ * Running | Paused |Running |Running |Stopped |
+ * | |restart |qWarning | |
+ * ----------+------------+-----------+-----------+-------------------+
+**/
+
+ QFETCH(QAbstractAnimation::State, originState);
+ QFETCH(int, operation);
+ QFETCH(QString, expectedWarning);
+ QFETCH(QAbstractAnimation::State, expectedState);
+
+ QObject o;
+ o.setProperty("ole", 42);
+ QPropertyAnimation anim(&o, "ole");
+ QSignalSpy spy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ anim.stop();
+ switch (originState) {
+ case QAbstractAnimation::Stopped:
+ break;
+ case QAbstractAnimation::Paused:
+ anim.start();
+ anim.pause();
+ break;
+ case QAbstractAnimation::Running:
+ anim.start();
+ break;
+ }
+ if (!expectedWarning.isEmpty()) {
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning));
+ }
+ QCOMPARE(anim.state(), originState);
+ switch (operation) {
+ case Pause:
+ anim.pause();
+ break;
+ case Start:
+ anim.start();
+ break;
+ case Resume:
+ anim.resume();
+ break;
+ case Stop:
+ anim.stop();
+ break;
+ }
+
+ QCOMPARE(anim.state(), expectedState);
+}
+#undef Pause
+#undef Start
+#undef Resume
+#undef Stop
+
+QTEST_MAIN(tst_QPropertyAnimation)
+#include "tst_qpropertyanimation.moc"
diff --git a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp b/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
index 9b9dd16..1025d2a 100644
--- a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
+++ b/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
@@ -107,6 +107,7 @@ class MyQObject : public QObject
Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
+ Q_PROPERTY(Policy enumProperty READ enumProperty WRITE setEnumProperty)
Q_ENUMS(Policy Strategy)
Q_FLAGS(Ability)
@@ -144,6 +145,7 @@ public:
m_hiddenValue(456.0),
m_writeOnlyValue(789),
m_readOnlyValue(987),
+ m_enumValue(BarPolicy),
m_qtFunctionInvoked(-1)
{ }
@@ -205,6 +207,11 @@ public:
void setPropWithCustomType(const CustomType &c)
{ m_customType = c; }
+ Policy enumProperty() const
+ { return m_enumValue; }
+ void setEnumProperty(Policy policy)
+ { m_enumValue = policy; }
+
int qtFunctionInvoked() const
{ return m_qtFunctionInvoked; }
@@ -255,8 +262,8 @@ public:
{ m_qtFunctionInvoked = 36; m_actuals << policy; }
Q_INVOKABLE Policy myInvokableReturningEnum()
{ m_qtFunctionInvoked = 37; return BazPolicy; }
- Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum()
- { m_qtFunctionInvoked = 38; return BazPolicy; }
+ Q_INVOKABLE MyQObject::Strategy myInvokableReturningQualifiedEnum()
+ { m_qtFunctionInvoked = 38; return BazStrategy; }
Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt()
{ m_qtFunctionInvoked = 11; return QVector<int>(); }
Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &)
@@ -410,6 +417,7 @@ protected:
int m_readOnlyValue;
QKeySequence m_shortcut;
CustomType m_customType;
+ Policy m_enumValue;
int m_qtFunctionInvoked;
QVariantList m_actuals;
QByteArray m_connectedSignal;
@@ -417,6 +425,7 @@ protected:
};
Q_DECLARE_METATYPE(MyQObject*)
+Q_DECLARE_METATYPE(MyQObject::Policy)
class MyOtherQObject : public MyQObject
{
@@ -530,6 +539,24 @@ static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *)
return ctx->callee().property("value");
}
+static QScriptValue policyToScriptValue(QScriptEngine *engine, const MyQObject::Policy &policy)
+{
+ return qScriptValueFromValue(engine, policy);
+}
+
+static void policyFromScriptValue(const QScriptValue &value, MyQObject::Policy &policy)
+{
+ QString str = value.toString();
+ if (str == QLatin1String("red"))
+ policy = MyQObject::FooPolicy;
+ else if (str == QLatin1String("green"))
+ policy = MyQObject::BarPolicy;
+ else if (str == QLatin1String("blue"))
+ policy = MyQObject::BazPolicy;
+ else
+ policy = (MyQObject::Policy)-1;
+}
+
void tst_QScriptExtQObject::getSetStaticProperty()
{
QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true);
@@ -751,6 +778,31 @@ void tst_QScriptExtQObject::getSetStaticProperty()
QScriptValue::ReadOnly);
}
+ // enum property
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ {
+ QScriptValue val = m_engine->evaluate("myObject.enumProperty");
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), (int)MyQObject::BarPolicy);
+ }
+ m_engine->evaluate("myObject.enumProperty = 2");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'BarPolicy'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'ScoobyDoo'");
+ // ### ouch! Shouldn't QMetaProperty::write() rather not change the value...?
+ QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
+ // enum property with custom conversion
+ qScriptRegisterMetaType<MyQObject::Policy>(m_engine, policyToScriptValue, policyFromScriptValue);
+ m_engine->evaluate("myObject.enumProperty = 'red'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::FooPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'green'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'blue'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'nada'");
+ QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
+
// auto-dereferencing of pointers
{
QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE);
@@ -1879,6 +1931,16 @@ void tst_QScriptExtQObject::classEnums()
QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg('BarPolicy')").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BarPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithEnumArg('NoSuchPolicy')").isError());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+
+ m_myObject->resetQtFunctionInvoked();
QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
diff --git a/tests/auto/qsequentialanimationgroup/qsequentialanimationgroup.pro b/tests/auto/qsequentialanimationgroup/qsequentialanimationgroup.pro
new file mode 100644
index 0000000..ad861c3
--- /dev/null
+++ b/tests/auto/qsequentialanimationgroup/qsequentialanimationgroup.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core gui
+SOURCES += tst_qsequentialanimationgroup.cpp
+
+
diff --git a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp
new file mode 100644
index 0000000..18b57b2
--- /dev/null
+++ b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp
@@ -0,0 +1,1649 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include "../../shared/util.h"
+
+#include <QtCore/qanimationgroup.h>
+#include <QtCore/qsequentialanimationgroup.h>
+
+//TESTED_CLASS=QSequentialAnimationGroup
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QAbstractAnimation::State)
+Q_DECLARE_METATYPE(QAbstractAnimation*)
+
+class tst_QSequentialAnimationGroup : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QSequentialAnimationGroup();
+ virtual ~tst_QSequentialAnimationGroup();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+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 clearAnimations();
+};
+
+tst_QSequentialAnimationGroup::tst_QSequentialAnimationGroup()
+{
+}
+
+tst_QSequentialAnimationGroup::~tst_QSequentialAnimationGroup()
+{
+}
+
+void tst_QSequentialAnimationGroup::init()
+{
+ qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
+ qRegisterMetaType<QAbstractAnimation*>("QAbstractAnimation*");
+}
+
+void tst_QSequentialAnimationGroup::cleanup()
+{
+}
+
+void tst_QSequentialAnimationGroup::construction()
+{
+ QSequentialAnimationGroup animationgroup;
+}
+
+class AnimationObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue)
+public:
+ AnimationObject(int startValue = 0)
+ : v(startValue)
+ { }
+
+ int value() const { return v; }
+ void setValue(int value) { v = value; }
+
+ int v;
+};
+
+class TestAnimation : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)};
+ virtual void updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+ {
+ Q_UNUSED(oldState)
+ Q_UNUSED(newState)
+ };
+};
+
+class UncontrolledAnimation : public QPropertyAnimation
+{
+ Q_OBJECT
+public:
+ UncontrolledAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0)
+ : QPropertyAnimation(target, propertyName, parent)
+ {
+ setDuration(250);
+ }
+
+ int duration() const { return -1; /* not time driven */ }
+
+protected:
+ void updateCurrentTime(int msecs)
+ {
+ QPropertyAnimation::updateCurrentTime(msecs);
+ if (msecs >= QPropertyAnimation::duration())
+ stop();
+ }
+};
+
+void tst_QSequentialAnimationGroup::setCurrentTime()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject s_o3;
+
+ // sequence operating on same object/property
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ a2_s_o1->setIterationCount(3);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroup *sequence2 = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
+ QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value");
+ sequence2->addAnimation(a1_s_o2);
+ sequence2->addAnimation(a1_s_o3);
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+ group.addAnimation(sequence2);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentTime(), 250);
+ QCOMPARE(sequence->currentTime(), 250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentTime(), 251);
+ QCOMPARE(sequence->currentTime(), 251);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentIteration(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 750
+ group.setCurrentTime(750);
+ QCOMPARE(group.currentTime(), 750);
+ QCOMPARE(sequence->currentTime(), 750);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1000
+ group.setCurrentTime(1000);
+ QCOMPARE(group.currentTime(), 1000);
+ QCOMPARE(sequence->currentTime(), 1000);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1010
+ group.setCurrentTime(1010);
+ QCOMPARE(group.currentTime(), 1010);
+ QCOMPARE(sequence->currentTime(), 1010);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 10);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1250
+ group.setCurrentTime(1250);
+ QCOMPARE(group.currentTime(), 1250);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1500
+ group.setCurrentTime(1500);
+ QCOMPARE(group.currentTime(), 1500);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentTime(), 1750);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 500);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 250);
+
+ // Current time = 2000
+ group.setCurrentTime(2000);
+ QCOMPARE(group.currentTime(), 1750);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 500);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 250);
+}
+
+void tst_QSequentialAnimationGroup::setCurrentTimeWithUncontrolledAnimation()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject t_o1;
+ AnimationObject t_o2;
+
+ // sequence operating on different object/properties
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a1_s_o2);
+
+ UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation(&t_o1, "value");
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ QVariantAnimation *loopsForever = new QPropertyAnimation(&t_o2, "value");
+ loopsForever->setIterationCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+ group.addAnimation(notTimeDriven);
+ group.addAnimation(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(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 1);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(notTimeDriven->currentTime(), 0);
+ QCOMPARE(loopsForever->currentTime(), 0);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentTime(), 250);
+ QCOMPARE(sequence->currentTime(), 250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(notTimeDriven->currentTime(), 0);
+ QCOMPARE(loopsForever->currentTime(), 0);
+
+ // Current time = 500
+ group.setCurrentTime(500);
+ QCOMPARE(group.currentTime(), 500);
+ QCOMPARE(sequence->currentTime(), 500);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 0);
+ QCOMPARE(loopsForever->currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), notTimeDriven);
+
+ // Current time = 505
+ group.setCurrentTime(505);
+ QCOMPARE(group.currentTime(), 505);
+ QCOMPARE(sequence->currentTime(), 500);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 5);
+ QCOMPARE(loopsForever->currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), notTimeDriven);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Paused);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
+
+ // Current time = 750 (end of notTimeDriven animation)
+ group.setCurrentTime(750);
+ QCOMPARE(group.currentTime(), 750);
+ QCOMPARE(sequence->currentTime(), 500);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 250);
+ QCOMPARE(loopsForever->currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), loopsForever);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Paused);
+
+ // Current time = 800 (as notTimeDriven was finished at 750, loopsforever should still run)
+ group.setCurrentTime(800);
+ QCOMPARE(group.currentTime(), 800);
+ QCOMPARE(group.currentAnimation(), loopsForever);
+ QCOMPARE(sequence->currentTime(), 500);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(notTimeDriven->currentTime(), 250);
+ QCOMPARE(loopsForever->currentTime(), 50);
+
+ loopsForever->stop(); // this should stop the group
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::seekingForwards()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject s_o3;
+
+ // sequence operating on same object/property
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ a2_s_o1->setIterationCount(3);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroup *sequence2 = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
+ QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value");
+ sequence2->addAnimation(a1_s_o2);
+ sequence2->addAnimation(a1_s_o3);
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+ group.addAnimation(sequence2);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentTime(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // Current time = 1500
+ group.setCurrentTime(1500);
+ QCOMPARE(group.currentTime(), 1500);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 250);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ // this will restart the group
+ group.start();
+ group.pause();
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped);
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentTime(), 1750);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 500);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 250);
+}
+
+void tst_QSequentialAnimationGroup::seekingBackwards()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject s_o3;
+
+ // sequence operating on same object/property
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ a2_s_o1->setIterationCount(3);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroup *sequence2 = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
+ QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value");
+ sequence2->addAnimation(a1_s_o2);
+ sequence2->addAnimation(a1_s_o3);
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+ group.addAnimation(sequence2);
+
+ group.start();
+
+ // Current time = 1600
+ group.setCurrentTime(1600);
+ QCOMPARE(group.currentTime(), 1600);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 350);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 100);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Running);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroup::Running);
+
+ // Seeking backwards, current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.currentTime(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 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->currentTime(), 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->currentIteration(), 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->currentTime(), 0);
+ QCOMPARE(sequence2->currentTime(), 0);
+ QCOMPARE(a1_s_o2->currentTime(), 0);
+ QCOMPARE(a1_s_o3->currentTime(), 0);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(sequence->state(), QAnimationGroup::Running);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Running);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped);
+
+ // Current time = 2000
+ group.setCurrentTime(2000);
+ QCOMPARE(group.currentTime(), 1750);
+ QCOMPARE(sequence->currentTime(), 1250);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 2);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+ QCOMPARE(sequence2->currentTime(), 500);
+ QCOMPARE(a1_s_o2->currentTime(), 250);
+ QCOMPARE(a1_s_o3->currentTime(), 250);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped);
+}
+
+typedef QList<QAbstractAnimation::State> StateList;
+
+static bool compareStates(const QSignalSpy& 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;
+ }
+ QList<QVariant> args = spy.at(i);
+ QAbstractAnimation::State st = expectedStates.at(i);
+ QAbstractAnimation::State actual = qVariantValue<QAbstractAnimation::State>(args.value(1));
+ 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()) {
+ QList<QVariant> args = spy.at(i);
+ QAbstractAnimation::State actual = qVariantValue<QAbstractAnimation::State>(args.value(1));
+ 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_QSequentialAnimationGroup::pauseAndResume()
+{
+ AnimationObject s_o1;
+
+ // sequence operating on same object/property
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ a2_s_o1->setIterationCount(2);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+ sequence->setIterationCount(2);
+
+ QSignalSpy a1StateChangedSpy(a1_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy seqStateChangedSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+
+ group.start();
+ group.pause();
+
+ // Current time = 1751
+ group.setCurrentTime(1751);
+ QCOMPARE(group.currentTime(), 1751);
+ QCOMPARE(sequence->currentTime(), 751);
+ QCOMPARE(sequence->currentIteration(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 1);
+ QCOMPARE(a3_s_o1->currentIteration(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 1);
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused);
+
+ QCOMPARE(a1StateChangedSpy.count(), 5); // Running,Paused,Stopped,Running,Stopped
+ QCOMPARE(seqStateChangedSpy.count(), 2); // Running,Paused
+
+ QVERIFY(compareStates(a1StateChangedSpy, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running
+ << QAbstractAnimation::Stopped)));
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(a1StateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(a1StateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Paused);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(a1StateChangedSpy.at(2).at(1)),
+ QAnimationGroup::Stopped);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(a1StateChangedSpy.at(3).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(a1StateChangedSpy.at(4).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Paused);
+
+ group.resume();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(sequence->state(), QAnimationGroup::Running);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroup::Running);
+
+ QVERIFY(group.currentTime() >= 1751);
+ QVERIFY(sequence->currentTime() >= 751);
+ QCOMPARE(sequence->currentIteration(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 1);
+ QCOMPARE(a3_s_o1->currentIteration(), 0);
+ QVERIFY(a3_s_o1->currentTime() >= 1);
+
+ QCOMPARE(seqStateChangedSpy.count(), 3); // Running,Paused,Running
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(2).at(1)),
+ QAnimationGroup::Running);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused);
+
+ QVERIFY(group.currentTime() >= 1751);
+ QVERIFY(sequence->currentTime() >= 751);
+ QCOMPARE(sequence->currentIteration(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 1);
+ QCOMPARE(a3_s_o1->currentIteration(), 0);
+ QVERIFY(a3_s_o1->currentTime() >= 1);
+
+ QCOMPARE(seqStateChangedSpy.count(), 4); // Running,Paused,Running,Paused
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(3).at(1)),
+ QAnimationGroup::Paused);
+
+ group.stop();
+
+ QCOMPARE(seqStateChangedSpy.count(), 5); // Running,Paused,Running,Paused,Stopped
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(4).at(1)),
+ QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::restart()
+{
+ AnimationObject s_o1;
+
+ // sequence operating on same object/property
+ QAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QSignalSpy seqCurrentAnimChangedSpy(sequence, SIGNAL(currentAnimationChanged(QAbstractAnimation*)));
+ QSignalSpy seqStateChangedSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QVariantAnimation *anims[3];
+ QSignalSpy *animsStateChanged[3];
+
+ for (int i = 0; i < 3; i++) {
+ anims[i] = new QPropertyAnimation(&s_o1, "value");
+ anims[i]->setDuration(100);
+ animsStateChanged[i] = new QSignalSpy(anims[i], SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ }
+
+ anims[1]->setIterationCount(2);
+ sequence->addAnimation(anims[0]);
+ sequence->addAnimation(anims[1]);
+ sequence->addAnimation(anims[2]);
+ sequence->setIterationCount(2);
+
+ QSequentialAnimationGroup group;
+ group.addAnimation(sequence);
+
+ group.start();
+
+ QTest::qWait(500);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+
+ QTest::qWait(300);
+ QTRY_COMPARE(group.state(), QAnimationGroup::Stopped);
+
+ for (int i = 0; i < 3; i++) {
+ QCOMPARE(animsStateChanged[i]->count(), 4);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(animsStateChanged[i]->at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(animsStateChanged[i]->at(1).at(1)),
+ QAnimationGroup::Stopped);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(animsStateChanged[i]->at(2).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(animsStateChanged[i]->at(3).at(1)),
+ QAnimationGroup::Stopped);
+ }
+
+ QCOMPARE(seqStateChangedSpy.count(), 2);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(seqStateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(seqCurrentAnimChangedSpy.count(), 6);
+ for(int i=0; i<seqCurrentAnimChangedSpy.count(); i++)
+ QCOMPARE(anims[i%3], qVariantValue<QAbstractAnimation*>(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_QSequentialAnimationGroup::looping()
+{
+ AnimationObject s_o1;
+ AnimationObject s_o2;
+ AnimationObject s_o3;
+
+ // sequence operating on same object/property
+ QSequentialAnimationGroup *sequence = new QSequentialAnimationGroup();
+ QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
+ QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
+
+ QSignalSpy a1Spy(a1_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy a2Spy(a2_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy a3Spy(a3_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy seqSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ a2_s_o1->setIterationCount(2);
+ sequence->addAnimation(a1_s_o1);
+ sequence->addAnimation(a2_s_o1);
+ sequence->addAnimation(a3_s_o1);
+ sequence->setIterationCount(2);
+
+ QSequentialAnimationGroup group;
+ QSignalSpy groupSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ group.addAnimation(sequence);
+ group.setIterationCount(2);
+
+ group.start();
+ group.pause();
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentTime(), 1750);
+ QCOMPARE(sequence->currentTime(), 750);
+ QCOMPARE(sequence->currentIteration(), 1);
+ QCOMPARE(a1_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 1);
+ // this animation is at the beginning because it is the current one inside sequence
+ QCOMPARE(a3_s_o1->currentIteration(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 0);
+ QCOMPARE(sequence->currentAnimation(), a3_s_o1);
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused);
+
+ QCOMPARE(a1Spy.count(), 5); // Running,Paused,Stopped,Running,Stopped
+ QVERIFY(compareStates(a1Spy, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running
+ << QAbstractAnimation::Stopped)));
+
+ QCOMPARE(a2Spy.count(), 4); // Running,Stopped,Running,Stopped
+ QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running
+ << QAbstractAnimation::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.currentTime(), 1);
+ QCOMPARE(group.currentIteration(), 1);
+ QCOMPARE(sequence->currentTime(), 1);
+ QCOMPARE(sequence->currentIteration(), 0);
+ QCOMPARE(a1_s_o1->currentTime(), 1);
+ QCOMPARE(a2_s_o1->currentTime(), 250);
+ QCOMPARE(a2_s_o1->currentIteration(), 1);
+ // this animation is at the end because it was run on the previous loop
+ QCOMPARE(a3_s_o1->currentIteration(), 0);
+ QCOMPARE(a3_s_o1->currentTime(), 250);
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroup::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroup::Stopped);
+
+ QCOMPARE(a1Spy.count(), 7); // Running,Paused,Stopped,Running,Stopped,Running,Stopped
+ QCOMPARE(a2Spy.count(), 4); // Running, Stopped, Running, Stopped
+ QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused
+ << QAbstractAnimation::Stopped)));
+ QVERIFY(compareStates(seqSpy, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused)));
+ QCOMPARE(groupSpy.count(), 2);
+}
+
+void tst_QSequentialAnimationGroup::startDelay()
+{
+ QSequentialAnimationGroup group;
+ group.addPause(250);
+ group.addPause(125);
+ QCOMPARE(group.totalDuration(), 375);
+
+ QEventLoop loop;
+ QObject::connect(&group, SIGNAL(finished()), &loop, SLOT(quit()));
+
+ QTime time;
+ time.start();
+ group.start();
+ loop.exec();
+
+ QVERIFY(time.elapsed() >= 375);
+ QVERIFY(time.elapsed() < 1000);
+}
+
+void tst_QSequentialAnimationGroup::clearGroup()
+{
+ QSequentialAnimationGroup group;
+
+ for (int i = 0; i < 10; ++i) {
+ QSequentialAnimationGroup *subGroup = new QSequentialAnimationGroup(&group);
+ group.addPause(100);
+ subGroup->addPause(10);
+ }
+
+ QCOMPARE(group.animationCount(), 20);
+
+ int count = group.animationCount();
+ QPointer<QAbstractAnimation> *children = new QPointer<QAbstractAnimation>[count];
+ for (int i = 0; i < count; ++i) {
+ QVERIFY(group.animationAt(i) != 0);
+ children[i] = group.animationAt(i);
+ }
+
+ group.clearAnimations();
+ QCOMPARE(group.animationCount(), 0);
+ QCOMPARE(group.currentTime(), 0);
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(children[i], QPointer<QAbstractAnimation>());
+
+ delete[] children;
+}
+
+void tst_QSequentialAnimationGroup::groupWithZeroDurationAnimations()
+{
+ QObject o;
+ QObject o2;
+
+ o.setProperty("myProperty", 42);
+ o.setProperty("myOtherProperty", 13);
+ o2.setProperty("myProperty", 42);
+ o2.setProperty("myOtherProperty", 13);
+
+ QSequentialAnimationGroup group;
+
+ QVariantAnimation *a1 = new QPropertyAnimation(&o, "myProperty");
+ a1->setDuration(0);
+ a1->setEndValue(43);
+ group.addAnimation(a1);
+
+ //this should just run fine and change nothing
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), a1);
+
+ QVariantAnimation *a2 = new QPropertyAnimation(&o2, "myOtherProperty");
+ a2->setDuration(500);
+ a2->setEndValue(31);
+ group.addAnimation(a2);
+
+ QVariantAnimation *a3 = new QPropertyAnimation(&o, "myProperty");
+ a3->setDuration(0);
+ a3->setEndValue(44);
+ group.addAnimation(a3);
+
+ QVariantAnimation *a4 = new QPropertyAnimation(&o, "myOtherProperty");
+ a4->setDuration(250);
+ a4->setEndValue(75);
+ group.addAnimation(a4);
+
+ QVariantAnimation *a5 = new QPropertyAnimation(&o2, "myProperty");
+ a5->setDuration(0);
+ a5->setEndValue(12);
+ group.addAnimation(a5);
+
+ QCOMPARE(o.property("myProperty").toInt(), 42);
+ QCOMPARE(o.property("myOtherProperty").toInt(), 13);
+ QCOMPARE(o2.property("myProperty").toInt(), 42);
+ QCOMPARE(o2.property("myOtherProperty").toInt(), 13);
+
+
+ group.start();
+
+ QCOMPARE(o.property("myProperty").toInt(), 43);
+ QCOMPARE(o.property("myOtherProperty").toInt(), 13);
+ QCOMPARE(o2.property("myProperty").toInt(), 42);
+ QCOMPARE(o2.property("myOtherProperty").toInt(), 13);
+
+ QTest::qWait(50);
+
+ int o2val = o2.property("myOtherProperty").toInt();
+ QVERIFY(o2val > 13);
+ QVERIFY(o2val < 31);
+ QCOMPARE(o.property("myProperty").toInt(), 43);
+ QCOMPARE(o.property("myOtherProperty").toInt(), 13);
+
+ QTest::qWait(500);
+
+ QCOMPARE(o.property("myProperty").toInt(), 44);
+ QCOMPARE(o2.property("myProperty").toInt(), 42);
+ QCOMPARE(o2.property("myOtherProperty").toInt(), 31);
+ QCOMPARE(a1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a4->state(), QAnimationGroup::Running);
+ QCOMPARE(a5->state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QTest::qWait(500);
+
+ QTRY_COMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(o.property("myProperty").toInt(), 44);
+ QCOMPARE(o.property("myOtherProperty").toInt(), 75);
+ QCOMPARE(o2.property("myProperty").toInt(), 12);
+ QCOMPARE(o2.property("myOtherProperty").toInt(), 31);
+ QCOMPARE(a1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a2->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a3->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a4->state(), QAnimationGroup::Stopped);
+ QCOMPARE(a5->state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::propagateGroupUpdateToChildren()
+{
+ // this test verifies if group state changes are updating its children correctly
+ QSequentialAnimationGroup group;
+
+ QObject o;
+ o.setProperty("ole", 42);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ QPropertyAnimation anim1(&o, "ole");
+ anim1.setEndValue(43);
+ anim1.setDuration(100);
+ QVERIFY(!anim1.currentValue().isValid());
+ QCOMPARE(anim1.currentValue().toInt(), 0);
+ QCOMPARE(o.property("ole").toInt(), 42);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QVERIFY(anim2.currentValue().isValid());
+ QCOMPARE(anim2.currentValue().toInt(), 0);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Paused);
+ QCOMPARE(anim1.state(), QAnimationGroup::Paused);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::updateChildrenWithRunningGroup()
+{
+ // assert that its possible to modify a child's state directly while their group is running
+ QSequentialAnimationGroup group;
+
+ TestAnimation anim;
+ anim.setStartValue(0);
+ anim.setEndValue(100);
+ anim.setDuration(200);
+
+ QSignalSpy groupStateChangedSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy childStateChangedSpy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QCOMPARE(groupStateChangedSpy.count(), 0);
+ QCOMPARE(childStateChangedSpy.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Running);
+
+ QCOMPARE(groupStateChangedSpy.count(), 1);
+ QCOMPARE(childStateChangedSpy.count(), 1);
+
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(groupStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(childStateChangedSpy.at(0).at(1)),
+ QAnimationGroup::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(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Paused);
+
+ // in the animation stops directly, the group will still be running
+ anim.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::deleteChildrenWithRunningGroup()
+{
+ // test if children can be activated when their group is stopped
+ QSequentialAnimationGroup group;
+
+ QVariantAnimation *anim1 = new TestAnimation;
+ anim1->setStartValue(0);
+ anim1->setEndValue(100);
+ anim1->setDuration(200);
+ group.addAnimation(anim1);
+
+ QCOMPARE(group.duration(), anim1->duration());
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1->state(), QAnimationGroup::Running);
+
+ QTest::qWait(50);
+ QVERIFY(group.currentTime() > 0);
+
+ delete anim1;
+ QCOMPARE(group.animationCount(), 0);
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.currentTime(), 0); //that's the invariant
+}
+
+void tst_QSequentialAnimationGroup::startChildrenWithStoppedGroup()
+{
+ // test if children can be activated when their group is stopped
+ QSequentialAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(200);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+}
+
+void tst_QSequentialAnimationGroup::stopGroupWithRunningChild()
+{
+ // children that started independently will not be affected by a group stop
+ QSequentialAnimationGroup group;
+
+ TestAnimation anim1;
+ anim1.setStartValue(0);
+ anim1.setEndValue(100);
+ anim1.setDuration(200);
+
+ TestAnimation anim2;
+ anim2.setStartValue(0);
+ anim2.setEndValue(100);
+ anim2.setDuration(200);
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(&anim1);
+ group.addAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Running);
+ QCOMPARE(anim2.state(), QAnimationGroup::Paused);
+
+ anim1.stop();
+ anim2.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::startGroupWithRunningChild()
+{
+ // as the group has precedence over its children, starting a group will restart all the children
+ QSequentialAnimationGroup group;
+
+ TestAnimation *anim1 = new TestAnimation();
+ anim1->setStartValue(0);
+ anim1->setEndValue(100);
+ anim1->setDuration(200);
+
+ TestAnimation *anim2 = new TestAnimation();
+ anim2->setStartValue(0);
+ anim2->setEndValue(100);
+ anim2->setDuration(200);
+
+ QSignalSpy stateChangedSpy1(anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+ QSignalSpy stateChangedSpy2(anim2, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ QCOMPARE(stateChangedSpy2.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroup::Stopped);
+
+ group.addAnimation(anim1);
+ group.addAnimation(anim2);
+
+ anim1->start();
+ anim2->start();
+ anim2->pause();
+
+ QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimation::Running)));
+
+ QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused)));
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroup::Running);
+ QCOMPARE(anim2->state(), QAnimationGroup::Paused);
+
+ group.start();
+
+ QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Stopped
+ << QAbstractAnimation::Running)));
+ QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimation::Running
+ << QAbstractAnimation::Paused)));
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1->state(), QAnimationGroup::Running);
+ QCOMPARE(anim2->state(), QAnimationGroup::Paused);
+
+ QTest::qWait(300);
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroup::Running);
+
+ QCOMPARE(stateChangedSpy2.count(), 4);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(2).at(1)),
+ QAnimationGroup::Stopped);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy2.at(3).at(1)),
+ QAnimationGroup::Running);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::zeroDurationAnimation()
+{
+ QSequentialAnimationGroup group;
+
+ TestAnimation *anim1 = new TestAnimation();
+ anim1->setStartValue(0);
+ anim1->setEndValue(100);
+ anim1->setDuration(0);
+
+ TestAnimation *anim2 = new TestAnimation();
+ anim2->setStartValue(0);
+ anim2->setEndValue(100);
+ anim2->setDuration(100);
+
+ AnimationObject o1;
+ QPropertyAnimation *anim3 = new QPropertyAnimation(&o1, "value");
+ anim3->setEndValue(100);
+ anim3->setDuration(0);
+
+ QSignalSpy stateChangedSpy(anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ group.addAnimation(anim1);
+ group.addAnimation(anim2);
+ group.addAnimation(anim3);
+ group.setIterationCount(2);
+ group.start();
+
+ QCOMPARE(stateChangedSpy.count(), 2);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy.at(0).at(1)),
+ QAnimationGroup::Running);
+ QCOMPARE(qVariantValue<QAbstractAnimation::State>(stateChangedSpy.at(1).at(1)),
+ QAnimationGroup::Stopped);
+
+ QCOMPARE(anim1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroup::Running);
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+
+ //now let's try to seek to the next loop
+ group.setCurrentTime(group.duration() + 1);
+ QCOMPARE(anim1->state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroup::Running);
+ QCOMPARE(anim3->state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(o1.value(), 100); //anim3 should have been run
+}
+
+void tst_QSequentialAnimationGroup::stopUncontrolledAnimations()
+{
+ QSequentialAnimationGroup group;
+
+ AnimationObject o1;
+ UncontrolledAnimation notTimeDriven(&o1, "value");
+ QCOMPARE(notTimeDriven.totalDuration(), -1);
+
+ TestAnimation loopsForever;
+ loopsForever.setStartValue(0);
+ loopsForever.setEndValue(100);
+ loopsForever.setDuration(100);
+ loopsForever.setIterationCount(-1);
+
+ group.addAnimation(&notTimeDriven);
+ group.addAnimation(&loopsForever);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::Stopped);
+
+ notTimeDriven.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::Running);
+
+ loopsForever.stop();
+
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroup::Stopped);
+}
+
+void tst_QSequentialAnimationGroup::finishWithUncontrolledAnimation()
+{
+ AnimationObject o1;
+
+ //1st case:
+ //first we test a group with one uncontrolled animation
+ QSequentialAnimationGroup group;
+ UncontrolledAnimation notTimeDriven(&o1, "value", &group);
+ QSignalSpy spy(&group, SIGNAL(finished()));
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running);
+ QCOMPARE(group.currentTime(), 0);
+ QCOMPARE(notTimeDriven.currentTime(), 0);
+
+ QTest::qWait(300); //wait for the end of notTimeDriven
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ const int actualDuration = notTimeDriven.currentTime();
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.currentTime(), actualDuration);
+ QCOMPARE(spy.count(), 1);
+
+ //2nd case:
+ // lets make sure the seeking will work again
+ spy.clear();
+ QPropertyAnimation anim(&group);
+ QSignalSpy animStateChangedSpy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+
+ group.setCurrentTime(300);
+ QCOMPARE(group.state(), QAnimationGroup::Stopped);
+ QCOMPARE(notTimeDriven.currentTime(), actualDuration);
+ QCOMPARE(group.currentAnimation(), &anim);
+
+ //3rd case:
+ //now let's add a perfectly defined animation at the end
+ QCOMPARE(animStateChangedSpy.count(), 0);
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running);
+ QCOMPARE(group.currentTime(), 0);
+ QCOMPARE(notTimeDriven.currentTime(), 0);
+
+ QCOMPARE(animStateChangedSpy.count(), 0);
+
+ QTest::qWait(300); //wait for the end of notTimeDriven
+ QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped);
+ QCOMPARE(group.state(), QAnimationGroup::Running);
+ QCOMPARE(anim.state(), QAnimationGroup::Running);
+ QCOMPARE(group.currentAnimation(), &anim);
+ QCOMPARE(animStateChangedSpy.count(), 1);
+ QTest::qWait(300); //wait for the end of anim
+
+ QCOMPARE(anim.state(), QAnimationGroup::Stopped);
+ QCOMPARE(anim.currentTime(), anim.duration());
+
+ //we should simply be at the end
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(animStateChangedSpy.count(), 2);
+ QCOMPARE(group.currentTime(), notTimeDriven.currentTime() + anim.currentTime());
+}
+
+void tst_QSequentialAnimationGroup::addRemoveAnimation()
+{
+ //this test is specific to the sequential animation group
+ QSequentialAnimationGroup group;
+
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.currentTime(), 0);
+ QVariantAnimation *anim1 = new QPropertyAnimation;
+ group.addAnimation(anim1);
+ QCOMPARE(group.duration(), 250);
+ QCOMPARE(group.currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim1);
+
+ //let's append an animation
+ QVariantAnimation *anim2 = new QPropertyAnimation;
+ group.addAnimation(anim2);
+ QCOMPARE(group.duration(), 500);
+ QCOMPARE(group.currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim1);
+
+ //let's prepend an animation
+ QVariantAnimation *anim0 = new QPropertyAnimation;
+ group.insertAnimationAt(0, anim0);
+ QCOMPARE(group.duration(), 750);
+ QCOMPARE(group.currentTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim0); //anim0 has become the new currentAnimation
+
+ group.setCurrentTime(300); //anim0 | anim1 | anim2
+ QCOMPARE(group.currentTime(), 300);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentTime(), 50);
+
+ group.removeAnimation(anim0); //anim1 | anim2
+ QCOMPARE(group.currentTime(), 50);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentTime(), 50);
+
+ group.setCurrentTime(0);
+ group.insertAnimationAt(0, anim0); //anim0 | anim1 | anim2
+ group.setCurrentTime(300);
+ QCOMPARE(group.currentTime(), 300);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentTime(), 50);
+
+ group.removeAnimation(anim1); //anim0 | anim2
+ QCOMPARE(group.currentTime(), 250);
+ QCOMPARE(group.currentAnimation(), anim2);
+ QCOMPARE(anim0->currentTime(), 250);
+}
+
+void tst_QSequentialAnimationGroup::currentAnimation()
+{
+ QSequentialAnimationGroup group;
+ QVERIFY(group.currentAnimation() == 0);
+
+ QPropertyAnimation anim;
+ anim.setDuration(0);
+ group.addAnimation(&anim);
+ QCOMPARE(group.currentAnimation(), &anim);
+}
+
+void tst_QSequentialAnimationGroup::currentAnimationWithZeroDuration()
+{
+ QSequentialAnimationGroup group;
+ QVERIFY(group.currentAnimation() == 0);
+
+ QPropertyAnimation zero1;
+ zero1.setDuration(0);
+ QPropertyAnimation zero2;
+ zero2.setDuration(0);
+
+ QPropertyAnimation anim;
+
+ QPropertyAnimation zero3;
+ zero3.setDuration(0);
+ QPropertyAnimation zero4;
+ zero4.setDuration(0);
+
+
+ group.addAnimation(&zero1);
+ group.addAnimation(&zero2);
+ group.addAnimation(&anim);
+ group.addAnimation(&zero3);
+ group.addAnimation(&zero4);
+
+ QCOMPARE(group.currentAnimation(), &zero1);
+
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), &anim);
+
+ group.setCurrentTime(group.duration());
+ QCOMPARE(group.currentAnimation(), &zero4);
+
+ group.setDirection(QAbstractAnimation::Backward);
+
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), &zero1);
+
+ group.setCurrentTime(group.duration());
+ QCOMPARE(group.currentAnimation(), &anim);
+}
+
+void tst_QSequentialAnimationGroup::insertAnimation()
+{
+ QSequentialAnimationGroup group;
+ group.setIterationCount(2);
+ QPropertyAnimation *anim = new QPropertyAnimation(&group);
+ QCOMPARE(group.duration(), anim->duration());
+ group.setCurrentTime(300);
+ QCOMPARE(group.currentIteration(), 1);
+
+ //this will crash if the sequential group calls duration on the created animation
+ new QPropertyAnimation(&group);
+}
+
+
+class SequentialAnimationGroup : public QSequentialAnimationGroup
+{
+ Q_OBJECT
+public slots:
+ void clearAnimations()
+ {
+ QSequentialAnimationGroup::clearAnimations();
+ }
+
+ void refill()
+ {
+ stop();
+ clearAnimations();
+ new QPropertyAnimation(this);
+ start();
+ }
+
+};
+
+
+void tst_QSequentialAnimationGroup::clearAnimations()
+{
+ SequentialAnimationGroup group;
+ QPointer<QAbstractAnimation> anim1 = new QPropertyAnimation(&group);
+ group.connect(anim1, SIGNAL(finished()), SLOT(clearAnimations()));
+ new QPropertyAnimation(&group);
+ QCOMPARE(group.animationCount(), 2);
+
+ group.start();
+ QTest::qWait(anim1->duration() + 100);
+ QCOMPARE(group.animationCount(), 0);
+ QCOMPARE(group.state(), QAbstractAnimation::Stopped);
+ QCOMPARE(group.currentTime(), 0);
+
+ anim1 = new QPropertyAnimation(&group);
+ group.connect(anim1, SIGNAL(finished()), SLOT(refill()));
+ group.start();
+ QTest::qWait(anim1->duration() + 100);
+ QVERIFY(anim1 == 0); //anim1 should have been deleted
+ QCOMPARE(group.state(), QAbstractAnimation::Running);
+}
+
+QTEST_MAIN(tst_QSequentialAnimationGroup)
+#include "tst_qsequentialanimationgroup.moc"
diff --git a/tests/auto/qstate/qstate.pro b/tests/auto/qstate/qstate.pro
new file mode 100644
index 0000000..9131fa8
--- /dev/null
+++ b/tests/auto/qstate/qstate.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core
+SOURCES += tst_qstate.cpp
+
+
diff --git a/tests/auto/qstate/tst_qstate.cpp b/tests/auto/qstate/tst_qstate.cpp
new file mode 100644
index 0000000..c4a0050
--- /dev/null
+++ b/tests/auto/qstate/tst_qstate.cpp
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include "qstate.h"
+#include "qstatemachine.h"
+#include "qtransition.h"
+#include "qsignaltransition.h"
+#include "qstateaction.h"
+
+// Will try to wait for the condition while allowing event processing
+#define QTRY_COMPARE(__expr, __expected) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if ((__expr) != (__expected)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QCOMPARE(__expr, __expected); \
+ } while(0)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QState : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QState();
+ virtual ~tst_QState();
+
+private slots:
+#if 0
+ void test();
+#endif
+ void setPropertyOnEntry();
+ void setPropertyOnEntryTwice();
+ void setPropertyOnExit();
+ void setPropertyOnExitTwice();
+ void historyInitialState();
+ void addEntryAction();
+};
+
+tst_QState::tst_QState()
+{
+}
+
+tst_QState::~tst_QState()
+{
+}
+
+#if 0
+void tst_QState::test()
+{
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+
+ QCOMPARE(s1->machine(), &machine);
+ QCOMPARE(s1->parentState(), machine.rootState());
+ QCOMPARE(s1->initialState(), (QState*)0);
+ QVERIFY(s1->childStates().isEmpty());
+ QVERIFY(s1->transitions().isEmpty());
+
+ QCOMPARE(s1->isFinal(), false);
+ s1->setFinal(true);
+ QCOMPARE(s1->isFinal(), true);
+ s1->setFinal(false);
+ QCOMPARE(s1->isFinal(), false);
+
+ QCOMPARE(s1->isParallel(), false);
+ s1->setParallel(true);
+ QCOMPARE(s1->isParallel(), true);
+ s1->setParallel(false);
+ QCOMPARE(s1->isParallel(), false);
+
+ QCOMPARE(s1->isAtomic(), true);
+ QCOMPARE(s1->isCompound(), false);
+ QCOMPARE(s1->isComplex(), false);
+
+ QState *s11 = new QState(s1);
+ QCOMPARE(s11->parentState(), s1);
+ QCOMPARE(s11->isAtomic(), true);
+ QCOMPARE(s11->isCompound(), false);
+ QCOMPARE(s11->isComplex(), false);
+ QCOMPARE(s11->machine(), s1->machine());
+ QVERIFY(s11->isDescendantOf(s1));
+
+ QCOMPARE(s1->initialState(), (QState*)0);
+ QCOMPARE(s1->childStates().size(), 1);
+ QCOMPARE(s1->childStates().at(0), s11);
+
+ QCOMPARE(s1->isAtomic(), false);
+ QCOMPARE(s1->isCompound(), true);
+ QCOMPARE(s1->isComplex(), true);
+
+ s1->setParallel(true);
+ QCOMPARE(s1->isAtomic(), false);
+ QCOMPARE(s1->isCompound(), false);
+ QCOMPARE(s1->isComplex(), true);
+
+ QState *s12 = new QState(s1);
+ QCOMPARE(s12->parentState(), s1);
+ QCOMPARE(s12->isAtomic(), true);
+ QCOMPARE(s12->isCompound(), false);
+ QCOMPARE(s12->isComplex(), false);
+ QCOMPARE(s12->machine(), s1->machine());
+ QVERIFY(s12->isDescendantOf(s1));
+ QVERIFY(!s12->isDescendantOf(s11));
+
+ QCOMPARE(s1->initialState(), (QState*)0);
+ QCOMPARE(s1->childStates().size(), 2);
+ QCOMPARE(s1->childStates().at(0), s11);
+ QCOMPARE(s1->childStates().at(1), s12);
+
+ QCOMPARE(s1->isAtomic(), false);
+ QCOMPARE(s1->isCompound(), false);
+ QCOMPARE(s1->isComplex(), true);
+
+ s1->setParallel(false);
+ QCOMPARE(s1->isAtomic(), false);
+ QCOMPARE(s1->isCompound(), true);
+ QCOMPARE(s1->isComplex(), true);
+
+ s1->setInitialState(s11);
+ QCOMPARE(s1->initialState(), s11);
+
+ s1->setInitialState(0);
+ QCOMPARE(s1->initialState(), (QState*)0);
+
+ s1->setInitialState(s12);
+ QCOMPARE(s1->initialState(), s12);
+
+ QState *s13 = new QState();
+ s1->setInitialState(s13);
+ QCOMPARE(s13->parentState(), s1);
+ QCOMPARE(s1->childStates().size(), 3);
+ QCOMPARE(s1->childStates().at(0), s11);
+ QCOMPARE(s1->childStates().at(1), s12);
+ QCOMPARE(s1->childStates().at(2), s13);
+ QVERIFY(s13->isDescendantOf(s1));
+
+ QVERIFY(s12->childStates().isEmpty());
+
+ QState *s121 = new QState(s12);
+ QCOMPARE(s121->parentState(), s12);
+ QCOMPARE(s121->isAtomic(), true);
+ QCOMPARE(s121->isCompound(), false);
+ QCOMPARE(s121->isComplex(), false);
+ QCOMPARE(s121->machine(), s12->machine());
+ QVERIFY(s121->isDescendantOf(s12));
+ QVERIFY(s121->isDescendantOf(s1));
+ QVERIFY(!s121->isDescendantOf(s11));
+
+ QCOMPARE(s12->childStates().size(), 1);
+ QCOMPARE(s12->childStates().at(0), (QState*)s121);
+
+ QCOMPARE(s1->childStates().size(), 3);
+ QCOMPARE(s1->childStates().at(0), s11);
+ QCOMPARE(s1->childStates().at(1), s12);
+ QCOMPARE(s1->childStates().at(2), s13);
+
+ s11->addTransition(s12);
+ QCOMPARE(s11->transitions().size(), 1);
+ QCOMPARE(s11->transitions().at(0)->sourceState(), s11);
+ QCOMPARE(s11->transitions().at(0)->targetStates().size(), 1);
+ QCOMPARE(s11->transitions().at(0)->targetStates().at(0), s12);
+ QCOMPARE(s11->transitions().at(0)->eventType(), QEvent::None);
+
+ QState *s14 = new QState();
+ s12->addTransition(QList<QState*>() << s13 << s14);
+ QCOMPARE(s12->transitions().size(), 1);
+ QCOMPARE(s12->transitions().at(0)->sourceState(), s12);
+ QCOMPARE(s12->transitions().at(0)->targetStates().size(), 2);
+ QCOMPARE(s12->transitions().at(0)->targetStates().at(0), s13);
+ QCOMPARE(s12->transitions().at(0)->targetStates().at(1), s14);
+ QCOMPARE(s12->transitions().at(0)->eventType(), QEvent::None);
+
+ s13->addTransition(this, SIGNAL(destroyed()), s14);
+ QCOMPARE(s13->transitions().size(), 1);
+ QCOMPARE(s13->transitions().at(0)->sourceState(), s13);
+ QCOMPARE(s13->transitions().at(0)->targetStates().size(), 1);
+ QCOMPARE(s13->transitions().at(0)->targetStates().at(0), s14);
+ QCOMPARE(s13->transitions().at(0)->eventType(), QEvent::Signal);
+ QVERIFY(qobject_cast<QSignalTransition*>(s13->transitions().at(0)) != 0);
+
+ delete s13->transitions().at(0);
+ QCOMPARE(s13->transitions().size(), 0);
+
+ s12->addTransition(this, SIGNAL(destroyed()), s11);
+ QCOMPARE(s12->transitions().size(), 2);
+}
+#endif
+
+void tst_QState::addEntryAction()
+{
+ QStateMachine sm;
+ QState *s0 = new QState(sm.rootState());
+ s0->addEntryAction(new QStateSetPropertyAction(this, "objectName", "commandTest"));
+ sm.setInitialState(s0);
+
+ sm.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(this->objectName(), QString::fromLatin1("commandTest"));
+}
+
+void tst_QState::setPropertyOnEntry()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("fooBar", 10);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnEntry(object, "fooBar", 20);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 20);
+}
+
+void tst_QState::setPropertyOnEntryTwice()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("fooBar", 10);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnEntry(object, "fooBar", 20);
+ s1->setPropertyOnEntry(object, "fooBar", 30);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 30);
+}
+
+void tst_QState::setPropertyOnExit()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("fooBar", 10);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnExit(object, "fooBar", 20);
+
+ QState *s2 = new QState(machine.rootState());
+ s1->addTransition(new QTransition(QEvent::User), s2);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 10);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 20);
+}
+
+void tst_QState::setPropertyOnExitTwice()
+{
+ QStateMachine machine;
+
+ QObject *object = new QObject();
+ object->setProperty("fooBar", 10);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnExit(object, "fooBar", 20);
+ s1->setPropertyOnExit(object, "fooBar", 30);
+
+ QState *s2 = new QState(machine.rootState());
+ s1->addTransition(new QTransition(QEvent::User), s2);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 10);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("fooBar").toInt(), 30);
+}
+
+void tst_QState::historyInitialState()
+{
+ QStateMachine machine;
+
+ QState *s1 = new QState(machine.rootState());
+
+ QState *s2 = new QState(machine.rootState());
+ QHistoryState *h1 = s2->addHistoryState();
+
+ s2->setInitialState(h1);
+
+ QState *s3 = new QState(s2);
+ h1->setDefaultState(s3);
+
+ QState *s4 = new QState(s2);
+
+ s1->addTransition(new QTransition(QEvent::User), s2);
+ s2->addTransition(new QTransition(QEvent::User), s1);
+ s3->addTransition(new QTransition(QEvent::Type(QEvent::User+1)), s4);
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s2));
+ QVERIFY(machine.configuration().contains(s3));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s2));
+ QVERIFY(machine.configuration().contains(s3));
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User+1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s2));
+ QVERIFY(machine.configuration().contains(s4));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s2));
+ QVERIFY(machine.configuration().contains(s4));
+}
+
+
+QTEST_MAIN(tst_QState)
+#include "tst_qstate.moc"
diff --git a/tests/auto/qstatemachine/qstatemachine.pro b/tests/auto/qstatemachine/qstatemachine.pro
new file mode 100644
index 0000000..e5b32b5
--- /dev/null
+++ b/tests/auto/qstatemachine/qstatemachine.pro
@@ -0,0 +1,4 @@
+load(qttest_p4)
+QT = core gui
+SOURCES += tst_qstatemachine.cpp
+
diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp
new file mode 100644
index 0000000..729581e
--- /dev/null
+++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp
@@ -0,0 +1,2177 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/QCoreApplication>
+#include <QtGui/QPushButton>
+
+#include "qstatemachine.h"
+#include "qstate.h"
+#include "qtransition.h"
+#include "qhistorystate.h"
+#include "qkeyeventtransition.h"
+#include "qmouseeventtransition.h"
+#include "private/qstatemachine_p.h"
+
+// Will try to wait for the condition while allowing event processing
+#define QTRY_COMPARE(__expr, __expected) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if ((__expr) != (__expected)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QCOMPARE(__expr, __expected); \
+ } while(0)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+static int globalTick;
+
+class tst_QStateMachine : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QStateMachine();
+ virtual ~tst_QStateMachine();
+
+private slots:
+ void init();
+ void cleanup();
+
+ void rootState();
+ void addAndRemoveState();
+ void stateEntryAndExit();
+ void postEvent();
+ void stateFinished();
+ void parallelStates();
+ void allSourceToTargetConfigurations();
+ void signalTransitions();
+ void eventTransitions();
+ void historyStates();
+ void stateActions();
+ void transitionActions();
+ void transitionToRootState();
+ void transitionEntersParent();
+
+ void defaultErrorState();
+ void customGlobalErrorState();
+ void customLocalErrorStateInBrokenState();
+ void customLocalErrorStateInOtherState();
+ void customLocalErrorStateInParentOfBrokenState();
+ void customLocalErrorStateOverridesParent();
+ void errorStateHasChildren();
+ void errorStateHasErrors();
+ void errorStateIsRootState();
+ void errorStateEntersParentFirst();
+ void customErrorStateIsNull();
+ void clearError();
+ void historyStateHasNowhereToGo();
+ void brokenStateIsNeverEntered();
+ void customErrorStateNotInGraph();
+ void transitionToStateNotInGraph();
+ void restoreProperties();
+ void defaultGlobalRestorePolicy();
+ void globalRestorePolicySetToRestore();
+ void globalRestorePolicySetToDoNotRestore();
+ void restorePolicyNotInherited();
+ void mixedRestoreProperties();
+ void setRestorePolicyToDoNotRestore();
+ void setGlobalRestorePolicyToGlobalRestore();
+ void restorePolicyOnChildState();
+ void addAnimatedTransition();
+ void transitionWithParent();
+};
+
+tst_QStateMachine::tst_QStateMachine()
+{
+}
+
+tst_QStateMachine::~tst_QStateMachine()
+{
+}
+
+class TestState : public QState
+{
+public:
+ enum Event {
+ Entry,
+ Exit
+ };
+ TestState(QState *parent)
+ : QState(parent) {}
+ QList<QPair<int, Event> > events;
+protected:
+ virtual void onEntry() {
+ events.append(qMakePair(globalTick++, Entry));
+ }
+ virtual void onExit() {
+ events.append(qMakePair(globalTick++, Exit));
+ }
+};
+
+class TestTransition : public QAbstractTransition
+{
+public:
+ TestTransition(QAbstractState *target)
+ : QAbstractTransition(QList<QAbstractState*>() << target) {}
+ QList<int> triggers;
+protected:
+ virtual bool eventTest(QEvent *) const {
+ return true;
+ }
+ virtual void onTransition() {
+ triggers.append(globalTick++);
+ }
+};
+
+static QtMsgType s_msgType;
+static QByteArray s_msg;
+static bool s_countWarnings;
+static QtMsgHandler s_oldHandler;
+
+static void defaultErrorStateTestMessageHandler(QtMsgType type, const char *msg)
+{
+ s_msgType = type;
+ s_msg = msg;
+
+ if (s_countWarnings)
+ s_oldHandler(type, msg);
+}
+
+void tst_QStateMachine::init()
+{
+ s_msg = QByteArray();
+ s_msgType = QtDebugMsg;
+ s_countWarnings = true;
+
+ s_oldHandler = qInstallMsgHandler(defaultErrorStateTestMessageHandler);
+}
+
+void tst_QStateMachine::cleanup()
+{
+ qInstallMsgHandler(s_oldHandler);
+}
+
+class EventTransition : public QTransition
+{
+public:
+ EventTransition(QEvent::Type type, QAbstractState *target, QState *parent = 0)
+ : QTransition(QList<QAbstractState*>() << target, parent), m_type(type) {}
+protected:
+ virtual bool eventTest(QEvent *e) const {
+ return (e->type() == m_type);
+ }
+private:
+ QEvent::Type m_type;
+};
+
+void tst_QStateMachine::transitionToRootState()
+{
+ QStateMachine machine;
+
+ QState *initialState = new QState();
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ initialState->addTransition(new EventTransition(QEvent::User, machine.rootState()));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 2);
+ QVERIFY(machine.configuration().contains(initialState));
+ QVERIFY(machine.configuration().contains(machine.rootState()));
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 2);
+ QVERIFY(machine.configuration().contains(initialState));
+ QVERIFY(machine.configuration().contains(machine.rootState()));
+}
+
+void tst_QStateMachine::transitionEntersParent()
+{
+ QStateMachine machine;
+
+ QObject *entryController = new QObject(&machine);
+ entryController->setObjectName("entryController");
+ entryController->setProperty("greatGrandParentEntered", false);
+ entryController->setProperty("grandParentEntered", false);
+ entryController->setProperty("parentEntered", false);
+ entryController->setProperty("stateEntered", false);
+
+ QState *greatGrandParent = new QState();
+ greatGrandParent->setObjectName("grandParent");
+ greatGrandParent->setPropertyOnEntry(entryController, "greatGrandParentEntered", true);
+ machine.addState(greatGrandParent);
+ machine.setInitialState(greatGrandParent);
+
+ QState *grandParent = new QState(greatGrandParent);
+ grandParent->setObjectName("grandParent");
+ grandParent->setPropertyOnEntry(entryController, "grandParentEntered", true);
+
+ QState *parent = new QState(grandParent);
+ parent->setObjectName("parent");
+ parent->setPropertyOnEntry(entryController, "parentEntered", true);
+
+ QState *state = new QState(parent);
+ state->setObjectName("state");
+ state->setPropertyOnEntry(entryController, "stateEntered", true);
+
+ QState *initialStateOfGreatGrandParent = new QState(greatGrandParent);
+ initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent");
+ greatGrandParent->setInitialState(initialStateOfGreatGrandParent);
+
+ initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, state));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true);
+ QCOMPARE(entryController->property("grandParentEntered").toBool(), false);
+ QCOMPARE(entryController->property("parentEntered").toBool(), false);
+ QCOMPARE(entryController->property("stateEntered").toBool(), false);
+ QCOMPARE(machine.configuration().count(), 2);
+ QVERIFY(machine.configuration().contains(greatGrandParent));
+ QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent));
+
+ entryController->setProperty("greatGrandParentEntered", false);
+ entryController->setProperty("grandParentEntered", false);
+ entryController->setProperty("parentEntered", false);
+ entryController->setProperty("stateEntered", false);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false);
+ QCOMPARE(entryController->property("grandParentEntered").toBool(), true);
+ QCOMPARE(entryController->property("parentEntered").toBool(), true);
+ QCOMPARE(entryController->property("stateEntered").toBool(), true);
+ QCOMPARE(machine.configuration().count(), 4);
+ QVERIFY(machine.configuration().contains(greatGrandParent));
+ QVERIFY(machine.configuration().contains(grandParent));
+ QVERIFY(machine.configuration().contains(parent));
+ QVERIFY(machine.configuration().contains(state));
+}
+
+void tst_QStateMachine::defaultErrorState()
+{
+ s_countWarnings = false; // we expect warnings here
+
+ QStateMachine machine;
+ QVERIFY(machine.errorState() != 0);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("MyInitialState");
+
+ machine.addState(brokenState);
+ machine.setInitialState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ // initialState has no initial state
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(s_msgType, QtWarningMsg);
+ QCOMPARE(QString::fromLatin1(s_msg.data()),
+ QString::fromLatin1("Unrecoverable error detected in running state machine: Missing initial state in compound state 'MyInitialState'"));
+
+ QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
+ QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'MyInitialState'"));
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(machine.errorState()));
+}
+
+class CustomErrorState: public QState
+{
+public:
+ CustomErrorState(QStateMachine *machine, QState *parent = 0)
+ : QState(parent), error(QStateMachine::NoError), m_machine(machine)
+ {
+ }
+
+ void onEntry()
+ {
+ error = m_machine->error();
+ errorString = m_machine->errorString();
+ }
+
+ QStateMachine::Error error;
+ QString errorString;
+
+private:
+ QStateMachine *m_machine;
+};
+
+void tst_QStateMachine::customGlobalErrorState()
+{
+ QStateMachine machine;
+
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ customErrorState->setObjectName("customErrorState");
+ machine.addState(customErrorState);
+ machine.setErrorState(customErrorState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+ machine.addState(brokenState);
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.errorState(), customErrorState);
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(initialState));
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(initialState));
+
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(customErrorState));
+ QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError);
+ QCOMPARE(customErrorState->errorString, QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
+ QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
+ QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
+ QVERIFY(s_msg.isEmpty());
+ QCOMPARE(s_msgType, QtDebugMsg);
+}
+
+void tst_QStateMachine::customLocalErrorStateInBrokenState()
+{
+ QStateMachine machine;
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ machine.addState(customErrorState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+ machine.addState(brokenState);
+ brokenState->setErrorState(customErrorState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(customErrorState));
+ QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError);
+ QVERIFY(s_msg.isEmpty());
+}
+
+void tst_QStateMachine::customLocalErrorStateInOtherState()
+{
+ s_countWarnings = false;
+
+ QStateMachine machine;
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ machine.addState(customErrorState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ initialState->setErrorState(customErrorState);
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+
+ machine.addState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(machine.errorState()));
+ QCOMPARE(s_msgType, QtWarningMsg);
+}
+
+void tst_QStateMachine::customLocalErrorStateInParentOfBrokenState()
+{
+ QStateMachine machine;
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ machine.addState(customErrorState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *parentOfBrokenState = new QState();
+ machine.addState(parentOfBrokenState);
+ parentOfBrokenState->setObjectName("parentOfBrokenState");
+ parentOfBrokenState->setErrorState(customErrorState);
+
+
+ QState *brokenState = new QState(parentOfBrokenState);
+ brokenState->setObjectName("brokenState");
+ parentOfBrokenState->setInitialState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(customErrorState));
+ QVERIFY(s_msg.isEmpty());
+}
+
+void tst_QStateMachine::customLocalErrorStateOverridesParent()
+{
+ QStateMachine machine;
+ CustomErrorState *customErrorStateForParent = new CustomErrorState(&machine);
+ machine.addState(customErrorStateForParent);
+
+ CustomErrorState *customErrorStateForBrokenState = new CustomErrorState(&machine);
+ machine.addState(customErrorStateForBrokenState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *parentOfBrokenState = new QState();
+ machine.addState(parentOfBrokenState);
+ parentOfBrokenState->setObjectName("parentOfBrokenState");
+ parentOfBrokenState->setErrorState(customErrorStateForParent);
+
+ QState *brokenState = new QState(parentOfBrokenState);
+ brokenState->setObjectName("brokenState");
+ brokenState->setErrorState(customErrorStateForBrokenState);
+ parentOfBrokenState->setInitialState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(customErrorStateForBrokenState));
+ QCOMPARE(customErrorStateForBrokenState->error, QStateMachine::NoInitialStateError);
+ QCOMPARE(customErrorStateForParent->error, QStateMachine::NoError);
+ QVERIFY(s_msg.isEmpty());
+}
+
+void tst_QStateMachine::errorStateHasChildren()
+{
+ QStateMachine machine;
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ customErrorState->setObjectName("customErrorState");
+ machine.addState(customErrorState);
+
+ machine.setErrorState(customErrorState);
+
+ QState *childOfErrorState = new QState(customErrorState);
+ childOfErrorState->setObjectName("childOfErrorState");
+ customErrorState->setInitialState(childOfErrorState);
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+ machine.addState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 2);
+ QVERIFY(machine.configuration().contains(customErrorState));
+ QVERIFY(machine.configuration().contains(childOfErrorState));
+ QVERIFY(s_msg.isEmpty());
+}
+
+
+void tst_QStateMachine::errorStateHasErrors()
+{
+ s_countWarnings = false;
+
+ QStateMachine machine;
+ CustomErrorState *customErrorState = new CustomErrorState(&machine);
+ customErrorState->setObjectName("customErrorState");
+ machine.addState(customErrorState);
+
+ QAbstractState *oldErrorState = machine.errorState();
+ machine.setErrorState(customErrorState);
+
+ QState *childOfErrorState = new QState(customErrorState);
+ childOfErrorState->setObjectName("childOfErrorState");
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+ machine.addState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(oldErrorState)); // Fall back to default
+ QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
+ QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'customErrorState'"));
+
+ QCOMPARE(s_msgType, QtWarningMsg);
+}
+
+void tst_QStateMachine::errorStateIsRootState()
+{
+ QStateMachine machine;
+ machine.setErrorState(machine.rootState());
+
+ QState *initialState = new QState();
+ initialState->setObjectName("initialState");
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ brokenState->setObjectName("brokenState");
+ machine.addState(brokenState);
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QEXPECT_FAIL("", "Covered by transitionToRootState test. Remove this when that test passes", Continue);
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(initialState));
+}
+
+void tst_QStateMachine::errorStateEntersParentFirst()
+{
+ QStateMachine machine;
+
+ QObject *entryController = new QObject(&machine);
+ entryController->setObjectName("entryController");
+ entryController->setProperty("greatGrandParentEntered", false);
+ entryController->setProperty("grandParentEntered", false);
+ entryController->setProperty("parentEntered", false);
+ entryController->setProperty("errorStateEntered", false);
+
+ QState *greatGrandParent = new QState();
+ greatGrandParent->setObjectName("greatGrandParent");
+ greatGrandParent->setPropertyOnEntry(entryController, "greatGrandParentEntered", true);
+ machine.addState(greatGrandParent);
+ machine.setInitialState(greatGrandParent);
+
+ QState *grandParent = new QState(greatGrandParent);
+ grandParent->setObjectName("grandParent");
+ grandParent->setPropertyOnEntry(entryController, "grandParentEntered", true);
+
+ QState *parent = new QState(grandParent);
+ parent->setObjectName("parent");
+ parent->setPropertyOnEntry(entryController, "parentEntered", true);
+
+ QState *errorState = new QState(parent);
+ errorState->setObjectName("errorState");
+ errorState->setPropertyOnEntry(entryController, "errorStateEntered", true);
+ machine.setErrorState(errorState);
+
+ QState *initialStateOfGreatGrandParent = new QState(greatGrandParent);
+ initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent");
+ greatGrandParent->setInitialState(initialStateOfGreatGrandParent);
+
+ QState *brokenState = new QState(greatGrandParent);
+ brokenState->setObjectName("brokenState");
+
+ QState *childState = new QState(brokenState);
+ childState->setObjectName("childState");
+
+ initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true);
+ QCOMPARE(entryController->property("grandParentEntered").toBool(), false);
+ QCOMPARE(entryController->property("parentEntered").toBool(), false);
+ QCOMPARE(entryController->property("errorStateEntered").toBool(), false);
+ QCOMPARE(machine.configuration().count(), 2);
+ QVERIFY(machine.configuration().contains(greatGrandParent));
+ QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent));
+
+ entryController->setProperty("greatGrandParentEntered", false);
+ entryController->setProperty("grandParentEntered", false);
+ entryController->setProperty("parentEntered", false);
+ entryController->setProperty("errorStateEntered", false);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false);
+ QCOMPARE(entryController->property("grandParentEntered").toBool(), true);
+ QCOMPARE(entryController->property("parentEntered").toBool(), true);
+ QCOMPARE(entryController->property("errorStateEntered").toBool(), true);
+ QCOMPARE(machine.configuration().count(), 4);
+ QVERIFY(machine.configuration().contains(greatGrandParent));
+ QVERIFY(machine.configuration().contains(grandParent));
+ QVERIFY(machine.configuration().contains(parent));
+ QVERIFY(machine.configuration().contains(errorState));
+}
+
+void tst_QStateMachine::customErrorStateIsNull()
+{
+ s_countWarnings = false;
+
+ QStateMachine machine;
+ QAbstractState *oldErrorState = machine.errorState();
+ machine.rootState()->setErrorState(0);
+
+ QState *initialState = new QState();
+ machine.addState(initialState);
+ machine.setInitialState(initialState);
+
+ QState *brokenState = new QState();
+ machine.addState(brokenState);
+
+ new QState(brokenState);
+ initialState->addTransition(new EventTransition(QEvent::User, brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.errorState(), reinterpret_cast<void *>(0));
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(oldErrorState));
+ QCOMPARE(s_msgType, QtWarningMsg);
+}
+
+void tst_QStateMachine::clearError()
+{
+ QStateMachine machine;
+ machine.setErrorState(new QState(machine.rootState())); // avoid warnings
+
+ QState *brokenState = new QState(machine.rootState());
+ brokenState->setObjectName("brokenState");
+ machine.setInitialState(brokenState);
+ new QState(brokenState);
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
+ QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
+
+ machine.clearError();
+
+ QCOMPARE(machine.error(), QStateMachine::NoError);
+ QVERIFY(machine.errorString().isEmpty());
+}
+
+void tst_QStateMachine::historyStateHasNowhereToGo()
+{
+ QStateMachine machine;
+
+ QState *initialState = new QState(machine.rootState());
+ machine.setInitialState(initialState);
+ machine.setErrorState(new QState(machine.rootState())); // avoid warnings
+
+ QState *brokenState = new QState(machine.rootState());
+ brokenState->setObjectName("brokenState");
+ brokenState->setInitialState(new QState(brokenState));
+
+ QHistoryState *historyState = brokenState->addHistoryState();
+ historyState->setObjectName("historyState");
+ initialState->addTransition(new EventTransition(QEvent::User, historyState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(machine.errorState()));
+ QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryState);
+ QCOMPARE(machine.errorString(), QString::fromLatin1("Missing transition from history state 'historyState'"));
+}
+
+void tst_QStateMachine::brokenStateIsNeverEntered()
+{
+ QStateMachine machine;
+
+ QObject *entryController = new QObject();
+ entryController->setProperty("brokenStateEntered", false);
+ entryController->setProperty("childStateEntered", false);
+ entryController->setProperty("errorStateEntered", false);
+
+ QState *initialState = new QState(machine.rootState());
+ machine.setInitialState(initialState);
+
+ QState *errorState = new QState(machine.rootState());
+ errorState->setPropertyOnEntry(entryController, "errorStateEntered", true);
+ machine.setErrorState(errorState);
+
+ QState *brokenState = new QState(machine.rootState());
+ brokenState->setPropertyOnEntry(entryController, "brokenStateEntered", true);
+ brokenState->setObjectName("brokenState");
+
+ QState *childState = new QState(brokenState);
+ childState->setPropertyOnEntry(entryController, "childStateEntered", true);
+
+ initialState->addTransition(new EventTransition(QEvent::User, brokenState));
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(entryController->property("errorStateEntered").toBool(), true);
+ QCOMPARE(entryController->property("brokenStateEntered").toBool(), false);
+ QCOMPARE(entryController->property("childStateEntered").toBool(), false);
+}
+
+void tst_QStateMachine::transitionToStateNotInGraph()
+{
+ QSKIP("Hangs", SkipAll);
+
+ s_countWarnings = false;
+
+ QStateMachine machine;
+
+ QState *initialState = new QState(machine.rootState());
+ initialState->setObjectName("initialState");
+ machine.setInitialState(initialState);
+
+ QState *independentState = new QState();
+ initialState->addTransition(independentState);
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(initialState));
+}
+
+void tst_QStateMachine::customErrorStateNotInGraph()
+{
+ s_countWarnings = false;
+
+ QStateMachine machine;
+
+ QState *errorState = new QState();
+ errorState->setObjectName("errorState");
+ machine.setErrorState(errorState);
+ QVERIFY(errorState != machine.errorState());
+
+ QState *initialBrokenState = new QState(machine.rootState());
+ initialBrokenState->setObjectName("initialBrokenState");
+ machine.setInitialState(initialBrokenState);
+ new QState(initialBrokenState);
+
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(machine.errorState()));
+}
+
+void tst_QStateMachine::restoreProperties()
+{
+ QObject *object = new QObject();
+ object->setProperty("a", 1);
+ object->setProperty("b", 2);
+
+ QStateMachine machine;
+
+ QState *S1 = new QState();
+ S1->setObjectName("S1");
+ S1->setPropertyOnEntry(object, "a", 3);
+ S1->setRestorePolicy(QState::RestoreProperties);
+ machine.addState(S1);
+
+ QState *S2 = new QState();
+ S2->setObjectName("S2");
+ S2->setPropertyOnEntry(object, "b", 5);
+ S2->setRestorePolicy(QState::RestoreProperties);
+ machine.addState(S2);
+
+ QState *S3 = new QState();
+ S3->setObjectName("S3");
+ S3->setRestorePolicy(QState::RestoreProperties);
+ machine.addState(S3);
+
+ QFinalState *S4 = new QFinalState();
+ machine.addState(S4);
+
+ S1->addTransition(new EventTransition(QEvent::User, S2));
+ S2->addTransition(new EventTransition(QEvent::User, S3));
+ S3->addTransition(S4);
+
+ machine.setInitialState(S1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 3);
+ QCOMPARE(object->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 1);
+ QCOMPARE(object->property("b").toInt(), 5);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 1);
+ QCOMPARE(object->property("b").toInt(), 2);
+}
+
+void tst_QStateMachine::rootState()
+{
+ QStateMachine machine;
+ QVERIFY(machine.rootState() != 0);
+ QVERIFY(qobject_cast<QState*>(machine.rootState()) != 0);
+ QCOMPARE(qobject_cast<QState*>(machine.rootState())->parentState(), (QState*)0);
+ QCOMPARE(machine.rootState()->parent(), (QObject*)&machine);
+
+ QState *s1 = new QState(machine.rootState());
+ QCOMPARE(s1->parentState(), machine.rootState());
+
+ QState *s2 = new QState();
+ s2->setParent(&machine);
+ QCOMPARE(s2->parentState(), machine.rootState());
+}
+
+void tst_QStateMachine::addAndRemoveState()
+{
+ QStateMachine machine;
+ QCOMPARE(machine.states().size(), 1); // the error state
+ QCOMPARE(machine.states().at(0), (QAbstractState*)machine.errorState());
+
+ QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: cannot add null state");
+ machine.addState(0);
+
+ QState *s1 = new QState();
+ QCOMPARE(s1->parentState(), (QState*)0);
+ machine.addState(s1);
+ QCOMPARE(s1->parentState(), machine.rootState());
+ QCOMPARE(machine.states().size(), 2);
+ QCOMPARE(machine.states().at(0), (QAbstractState*)machine.errorState());
+ QCOMPARE(machine.states().at(1), (QAbstractState*)s1);
+
+ QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine");
+ machine.addState(s1);
+
+ QState *s2 = new QState();
+ QCOMPARE(s2->parentState(), (QState*)0);
+ machine.addState(s2);
+ QCOMPARE(s2->parentState(), machine.rootState());
+ QCOMPARE(machine.states().size(), 3);
+ QCOMPARE(machine.states().at(0), (QAbstractState*)machine.errorState());
+ QCOMPARE(machine.states().at(1), (QAbstractState*)s1);
+ QCOMPARE(machine.states().at(2), (QAbstractState*)s2);
+
+ QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine");
+ machine.addState(s2);
+
+ machine.removeState(s1);
+ QCOMPARE(s1->parentState(), (QState*)0);
+ QCOMPARE(machine.states().size(), 2);
+ QCOMPARE(machine.states().at(0), (QAbstractState*)machine.errorState());
+ QCOMPARE(machine.states().at(1), (QAbstractState*)s2);
+
+ machine.removeState(s2);
+ QCOMPARE(s2->parentState(), (QState*)0);
+ QCOMPARE(machine.states().size(), 1);
+ QCOMPARE(machine.states().at(0), (QAbstractState*)machine.errorState());
+
+ QTest::ignoreMessage(QtWarningMsg, "QStateMachine::removeState: cannot remove null state");
+ machine.removeState(0);
+
+ delete s1;
+ delete s2;
+ // ### how to deal with this?
+ // machine.removeState(machine.errorState());
+}
+
+void tst_QStateMachine::stateEntryAndExit()
+{
+ // Two top-level states
+ {
+ QStateMachine machine;
+
+ TestState *s1 = new TestState(machine.rootState());
+ TestState *s2 = new TestState(machine.rootState());
+ QFinalState *s3 = new QFinalState(machine.rootState());
+ TestTransition *t = new TestTransition(s2);
+ s1->addTransition(t);
+ s2->addTransition(s3);
+
+ QSignalSpy startedSpy(&machine, SIGNAL(started()));
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s1);
+ QVERIFY(machine.configuration().isEmpty());
+ globalTick = 0;
+ machine.start();
+
+ QTRY_COMPARE(startedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(s3));
+
+ // s1 is entered
+ QCOMPARE(s1->events.count(), 2);
+ QCOMPARE(s1->events.at(0).first, 0);
+ QCOMPARE(s1->events.at(0).second, TestState::Entry);
+ // s1 is exited
+ QCOMPARE(s1->events.at(1).first, 1);
+ QCOMPARE(s1->events.at(1).second, TestState::Exit);
+ // t is triggered
+ QCOMPARE(t->triggers.count(), 1);
+ QCOMPARE(t->triggers.at(0), 2);
+ // s2 is entered
+ QCOMPARE(s2->events.count(), 2);
+ QCOMPARE(s2->events.at(0).first, 3);
+ QCOMPARE(s2->events.at(0).second, TestState::Entry);
+ // s2 is exited
+ QCOMPARE(s2->events.at(1).first, 4);
+ QCOMPARE(s2->events.at(1).second, TestState::Exit);
+ }
+ // Two top-level states, one has two child states
+ {
+ QStateMachine machine;
+
+ TestState *s1 = new TestState(machine.rootState());
+ TestState *s11 = new TestState(s1);
+ TestState *s12 = new TestState(s1);
+ TestState *s2 = new TestState(machine.rootState());
+ QFinalState *s3 = new QFinalState(machine.rootState());
+ s1->setInitialState(s11);
+ TestTransition *t1 = new TestTransition(s12);
+ s11->addTransition(t1);
+ TestTransition *t2 = new TestTransition(s2);
+ s12->addTransition(t2);
+ s2->addTransition(s3);
+
+ QSignalSpy startedSpy(&machine, SIGNAL(started()));
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s1);
+ globalTick = 0;
+ machine.start();
+
+ QTRY_COMPARE(startedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(machine.configuration().count(), 1);
+ QVERIFY(machine.configuration().contains(s3));
+
+ // s1 is entered
+ QCOMPARE(s1->events.count(), 2);
+ QCOMPARE(s1->events.at(0).first, 0);
+ QCOMPARE(s1->events.at(0).second, TestState::Entry);
+ // s11 is entered
+ QCOMPARE(s11->events.count(), 2);
+ QCOMPARE(s11->events.at(0).first, 1);
+ QCOMPARE(s11->events.at(0).second, TestState::Entry);
+ // s11 is exited
+ QCOMPARE(s11->events.at(1).first, 2);
+ QCOMPARE(s11->events.at(1).second, TestState::Exit);
+ // t1 is triggered
+ QCOMPARE(t1->triggers.count(), 1);
+ QCOMPARE(t1->triggers.at(0), 3);
+ // s12 is entered
+ QCOMPARE(s12->events.count(), 2);
+ QCOMPARE(s12->events.at(0).first, 4);
+ QCOMPARE(s12->events.at(0).second, TestState::Entry);
+ // s12 is exited
+ QCOMPARE(s12->events.at(1).first, 5);
+ QCOMPARE(s12->events.at(1).second, TestState::Exit);
+ // s1 is exited
+ QCOMPARE(s1->events.at(1).first, 6);
+ QCOMPARE(s1->events.at(1).second, TestState::Exit);
+ // t2 is triggered
+ QCOMPARE(t2->triggers.count(), 1);
+ QCOMPARE(t2->triggers.at(0), 7);
+ // s2 is entered
+ QCOMPARE(s2->events.count(), 2);
+ QCOMPARE(s2->events.at(0).first, 8);
+ QCOMPARE(s2->events.at(0).second, TestState::Entry);
+ // s2 is exited
+ QCOMPARE(s2->events.at(1).first, 9);
+ QCOMPARE(s2->events.at(1).second, TestState::Exit);
+ }
+}
+
+struct StringEvent : public QEvent
+{
+public:
+ StringEvent(const QString &val)
+ : QEvent(QEvent::Type(QEvent::User+2)),
+ value(val) {}
+
+ QString value;
+};
+
+class StringTransition : public QAbstractTransition
+{
+public:
+ StringTransition(const QString &value, QAbstractState *target)
+ : QAbstractTransition(QList<QAbstractState*>() << target), m_value(value) {}
+
+protected:
+ virtual bool eventTest(QEvent *e) const
+ {
+ if (e->type() != QEvent::Type(QEvent::User+2))
+ return false;
+ StringEvent *se = static_cast<StringEvent*>(e);
+ return (m_value == se->value) && (!m_cond.isValid() || (m_cond.indexIn(m_value) != -1));
+ }
+ virtual void onTransition() {}
+
+private:
+ QString m_value;
+ QRegExp m_cond;
+};
+
+class StringEventPoster : public QState
+{
+public:
+ StringEventPoster(QStateMachine *machine, const QString &value, QState *parent = 0)
+ : QState(parent), m_machine(machine), m_value(value) {}
+
+ void setString(const QString &value)
+ { m_value = value; }
+
+protected:
+ virtual void onEntry()
+ {
+ m_machine->postEvent(new StringEvent(m_value));
+ }
+ virtual void onExit() {}
+
+private:
+ QStateMachine *m_machine;
+ QString m_value;
+};
+
+void tst_QStateMachine::postEvent()
+{
+ QStateMachine machine;
+ StringEventPoster *s1 = new StringEventPoster(&machine, "a");
+ QFinalState *s2 = new QFinalState;
+ s1->addTransition(new StringTransition("a", s2));
+ machine.addState(s1);
+ machine.addState(s2);
+ machine.setInitialState(s1);
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s2));
+
+ s1->setString("b");
+ QFinalState *s3 = new QFinalState();
+ machine.addState(s3);
+ s1->addTransition(new StringTransition("b", s3));
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s3));
+}
+
+void tst_QStateMachine::stateFinished()
+{
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+ QState *s1_1 = new QState(s1);
+ QFinalState *s1_2 = new QFinalState(s1);
+ s1_1->addTransition(s1_2);
+ s1->setInitialState(s1_1);
+ QFinalState *s2 = new QFinalState(machine.rootState());
+ s1->addTransition(new QStateFinishedTransition(s1, QList<QAbstractState*>() << s2));
+ machine.setInitialState(s1);
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s2));
+}
+
+void tst_QStateMachine::parallelStates()
+{
+ QStateMachine machine;
+
+ QState *s1 = new QState(QState::ParallelGroup);
+ QState *s1_1 = new QState(s1);
+ QState *s1_1_1 = new QState(s1_1);
+ QFinalState *s1_1_f = new QFinalState(s1_1);
+ s1_1_1->addTransition(s1_1_f);
+ s1_1->setInitialState(s1_1_1);
+ QState *s1_2 = new QState(s1);
+ QState *s1_2_1 = new QState(s1_2);
+ QFinalState *s1_2_f = new QFinalState(s1_2);
+ s1_2_1->addTransition(s1_2_f);
+ s1_2->setInitialState(s1_2_1);
+ machine.addState(s1);
+
+ QFinalState *s2 = new QFinalState();
+ machine.addState(s2);
+
+ s1->addFinishedTransition(s2);
+
+ machine.setInitialState(s1);
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+}
+
+void tst_QStateMachine::allSourceToTargetConfigurations()
+{
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ s0->setObjectName("s0");
+ QState *s1 = new QState(s0);
+ s1->setObjectName("s1");
+ QState *s11 = new QState(s1);
+ s11->setObjectName("s11");
+ QState *s2 = new QState(s0);
+ s2->setObjectName("s2");
+ QState *s21 = new QState(s2);
+ s21->setObjectName("s21");
+ QState *s211 = new QState(s21);
+ s211->setObjectName("s211");
+ QFinalState *f = new QFinalState(machine.rootState());
+ f->setObjectName("f");
+
+ s0->setInitialState(s1);
+ s1->setInitialState(s11);
+ s2->setInitialState(s21);
+ s21->setInitialState(s211);
+
+ s11->addTransition(new StringTransition("g", s211));
+ s1->addTransition(new StringTransition("a", s1));
+ s1->addTransition(new StringTransition("b", s11));
+ s1->addTransition(new StringTransition("c", s2));
+ s1->addTransition(new StringTransition("d", s0));
+ s1->addTransition(new StringTransition("f", s211));
+ s211->addTransition(new StringTransition("d", s21));
+ s211->addTransition(new StringTransition("g", s0));
+ s211->addTransition(new StringTransition("h", f));
+ s21->addTransition(new StringTransition("b", s211));
+ s2->addTransition(new StringTransition("c", s1));
+ s2->addTransition(new StringTransition("f", s11));
+ s0->addTransition(new StringTransition("e", s211));
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new StringEvent("a"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("b"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("c"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("d"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("e"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("f"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("g"));
+ QCoreApplication::processEvents();
+ machine.postEvent(new StringEvent("h"));
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+}
+
+class SignalEmitter : public QObject
+{
+Q_OBJECT
+ public:
+ SignalEmitter(QObject *parent = 0)
+ : QObject(parent) {}
+ void emitSignalWithNoArg()
+ { emit signalWithNoArg(); }
+ void emitSignalWithIntArg(int arg)
+ { emit signalWithIntArg(arg); }
+ void emitSignalWithStringArg(const QString &arg)
+ { emit signalWithStringArg(arg); }
+Q_SIGNALS:
+ void signalWithNoArg();
+ void signalWithIntArg(int);
+ void signalWithStringArg(const QString &);
+};
+
+class TestSignalTransition : public QSignalTransition
+{
+public:
+ TestSignalTransition()
+ : QSignalTransition() {}
+ TestSignalTransition(QObject *sender, const char *signal,
+ QAbstractState *target)
+ : QSignalTransition(sender, signal, QList<QAbstractState*>() << target) {}
+ QVariantList argumentsReceived() const {
+ return m_args;
+ }
+protected:
+ bool eventTest(QEvent *e) const {
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ const_cast<TestSignalTransition*>(this)->m_args = se->arguments();
+ return true;
+ }
+private:
+ QVariantList m_args;
+};
+
+void tst_QStateMachine::signalTransitions()
+{
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+ SignalEmitter emitter;
+ s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ emitter.emitSignalWithNoArg();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+ SignalEmitter emitter;
+ TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithIntArg(int)), s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ emitter.emitSignalWithIntArg(123);
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(trans->argumentsReceived().size(), 1);
+ QCOMPARE(trans->argumentsReceived().at(0).toInt(), 123);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+ SignalEmitter emitter;
+ TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithStringArg(QString)), s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QString testString = QString::fromLatin1("hello");
+ emitter.emitSignalWithStringArg(testString);
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(trans->argumentsReceived().size(), 1);
+ QCOMPARE(trans->argumentsReceived().at(0).toString(), testString);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ TestSignalTransition *trans = new TestSignalTransition();
+ QCOMPARE(trans->senderObject(), (QObject*)0);
+ QCOMPARE(trans->signal(), QByteArray());
+
+ SignalEmitter emitter;
+ trans->setSenderObject(&emitter);
+ QCOMPARE(trans->senderObject(), (QObject*)&emitter);
+ trans->setSignal(SIGNAL(signalWithNoArg()));
+ QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg())));
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ emitter.emitSignalWithNoArg();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+}
+
+void tst_QStateMachine::eventTransitions()
+{
+ QPushButton button;
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ QMouseEventTransition *trans = new QMouseEventTransition(&button, QEvent::MouseButtonPress, Qt::LeftButton);
+ QCOMPARE(trans->eventType(), QEvent::MouseButtonPress);
+ QCOMPARE(trans->button(), Qt::LeftButton);
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ QEventTransition *trans = new QEventTransition();
+ QCOMPARE(trans->eventSource(), (QObject*)0);
+ QCOMPARE(trans->eventType(), QEvent::None);
+ trans->setEventSource(&button);
+ QCOMPARE(trans->eventSource(), (QObject*)&button);
+ trans->setEventType(QEvent::MouseButtonPress);
+ QCOMPARE(trans->eventType(), QEvent::MouseButtonPress);
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ QMouseEventTransition *trans = new QMouseEventTransition();
+ QCOMPARE(trans->eventSource(), (QObject*)0);
+ QCOMPARE(trans->eventType(), QEvent::None);
+ QCOMPARE(trans->button(), Qt::NoButton);
+ trans->setEventSource(&button);
+ trans->setEventType(QEvent::MouseButtonPress);
+ trans->setButton(Qt::LeftButton);
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ QKeyEventTransition *trans = new QKeyEventTransition(&button, QEvent::KeyPress, Qt::Key_A);
+ QCOMPARE(trans->eventType(), QEvent::KeyPress);
+ QCOMPARE(trans->key(), (int)Qt::Key_A);
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QTest::keyPress(&button, Qt::Key_A);
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QFinalState *s1 = new QFinalState(machine.rootState());
+
+ QKeyEventTransition *trans = new QKeyEventTransition();
+ QCOMPARE(trans->eventSource(), (QObject*)0);
+ QCOMPARE(trans->eventType(), QEvent::None);
+ QCOMPARE(trans->key(), 0);
+ trans->setEventSource(&button);
+ trans->setEventType(QEvent::KeyPress);
+ trans->setKey(Qt::Key_A);
+ trans->setTargetState(s1);
+ s0->addTransition(trans);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QTest::keyPress(&button, Qt::Key_A);
+ QCoreApplication::processEvents();
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ }
+}
+
+void tst_QStateMachine::historyStates()
+{
+ QStateMachine machine;
+ QState *root = machine.rootState();
+ QState *s0 = new QState(root);
+ QState *s00 = new QState(s0);
+ QState *s01 = new QState(s0);
+ QHistoryState *s0h = s0->addHistoryState();
+ QState *s1 = new QState(root);
+ QFinalState *s2 = new QFinalState(root);
+
+ s00->addTransition(new StringTransition("a", s01));
+ s0->addTransition(new StringTransition("b", s1));
+ s1->addTransition(new StringTransition("c", s0h));
+ s0->addTransition(new StringTransition("d", s2));
+
+ root->setInitialState(s0);
+ s0->setInitialState(s00);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.start();
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s0));
+ QVERIFY(machine.configuration().contains(s00));
+
+ machine.postEvent(new StringEvent("a"));
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s0));
+ QVERIFY(machine.configuration().contains(s01));
+
+ machine.postEvent(new StringEvent("b"));
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+
+ machine.postEvent(new StringEvent("c"));
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 2);
+ QVERIFY(machine.configuration().contains(s0));
+ QVERIFY(machine.configuration().contains(s01));
+
+ machine.postEvent(new StringEvent("d"));
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s2));
+
+ QTRY_COMPARE(finishedSpy.count(), 1);
+}
+
+class TestStateAction : public QStateAction
+{
+public:
+ TestStateAction() : m_didExecute(false)
+ {}
+ bool didExecute() const {
+ return m_didExecute;
+ }
+protected:
+ void execute() {
+ m_didExecute = true;
+ }
+private:
+ bool m_didExecute;
+};
+
+void tst_QStateMachine::stateActions()
+{
+ {
+ QStateSetPropertyAction act;
+ QCOMPARE(act.targetObject(), (QObject*)0);
+ QCOMPARE(act.propertyName().length(), 0);
+ QCOMPARE(act.value(), QVariant());
+
+ act.setTargetObject(this);
+ QCOMPARE(act.targetObject(), (QObject*)this);
+ QByteArray name("foo");
+ act.setPropertyName(name);
+ QCOMPARE(act.propertyName(), name);
+ QVariant value(123);
+ act.setValue(value);
+ QCOMPARE(act.value(), value);
+ }
+ {
+ QByteArray name("foo");
+ QVariant value(123);
+ QStateSetPropertyAction act(this, name, value);
+ QCOMPARE(act.targetObject(), (QObject*)this);
+ QCOMPARE(act.propertyName(), name);
+ QCOMPARE(act.value(), value);
+ }
+
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+
+ QVERIFY(s1->entryActions().isEmpty());
+ QVERIFY(s1->exitActions().isEmpty());
+
+ QTest::ignoreMessage(QtWarningMsg, "QActionState::addEntryAction: cannot add null action");
+ s1->addEntryAction(0);
+ QTest::ignoreMessage(QtWarningMsg, "QActionState::addExitAction: cannot add null action");
+ s1->addExitAction(0);
+ QTest::ignoreMessage(QtWarningMsg, "QActionState::removeEntryAction: cannot remove null action");
+ s1->removeEntryAction(0);
+ QTest::ignoreMessage(QtWarningMsg, "QActionState::removeExitAction: cannot remove null action");
+ s1->removeExitAction(0);
+
+ QStateSetPropertyAction *spa = new QStateSetPropertyAction(s1, "objectName", "foo");
+ s1->addEntryAction(spa);
+ QCOMPARE(s1->entryActions().size(), 1);
+ QCOMPARE(s1->entryActions().at(0), (QStateAction*)spa);
+ QCOMPARE(spa->parent(), (QObject*)s1);
+ QVERIFY(s1->exitActions().isEmpty());
+
+ s1->addEntryAction(spa); // add again
+ QCOMPARE(s1->entryActions().size(), 1);
+
+ QFinalState *s2 = new QFinalState(machine.rootState());
+ s1->addTransition(s2);
+
+ machine.setInitialState(s1);
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(s1->objectName(), QString::fromLatin1("foo"));
+
+ s1->removeEntryAction(spa);
+ QCOMPARE(spa->parent(), (QObject*)0);
+ QVERIFY(s1->entryActions().isEmpty());
+
+ s1->removeEntryAction(spa); // remove again
+
+ s1->setObjectName(QString::fromLatin1("bar"));
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(s1->objectName(), QString::fromLatin1("bar"));
+
+ s1->addEntryAction(spa);
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE(s1->objectName(), QString::fromLatin1("foo"));
+
+ s1->removeEntryAction(spa);
+ QVERIFY(s1->entryActions().isEmpty());
+ QStateInvokeMethodAction *ima = new QStateInvokeMethodAction(spa, "deleteLater");
+ QPointer<QStateAction> ptr(spa);
+ QVERIFY(ptr != 0);
+ s1->addEntryAction(ima);
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCoreApplication::processEvents();
+ QVERIFY(ptr == 0);
+
+ s1->removeEntryAction(ima);
+
+ s1->setPropertyOnEntry(s1, "objectName", "bar");
+ QCOMPARE(s1->entryActions().size(), 1);
+ s1->setPropertyOnEntry(s1, "objectName", "bar");
+ QCOMPARE(s1->entryActions().size(), 1);
+
+ s1->invokeMethodOnEntry(ima, "deleteLater");
+ QCOMPARE(s1->entryActions().size(), 2);
+
+ ptr = ima;
+ QVERIFY(ptr != 0);
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCoreApplication::processEvents();
+ QVERIFY(ptr == 0);
+
+ while (!s1->entryActions().isEmpty()) {
+ QStateAction *act = s1->entryActions().first();
+ s1->removeEntryAction(act);
+ delete act;
+ }
+
+ TestStateAction *act1 = new TestStateAction();
+ s1->addEntryAction(act1);
+ TestStateAction *act2 = new TestStateAction();
+ s1->addExitAction(act2);
+ QVERIFY(!act1->didExecute());
+ QVERIFY(!act2->didExecute());
+
+ finishedSpy.clear();
+ machine.start();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+
+ QVERIFY(act1->didExecute());
+ QVERIFY(act2->didExecute());
+
+ QCOMPARE(s1->entryActions().size(), 1);
+ QCOMPARE(s2->entryActions().size(), 0);
+ s2->addEntryAction(act1); // should remove it from s1
+ QCOMPARE(s1->entryActions().size(), 0);
+ QCOMPARE(s2->entryActions().size(), 1);
+ QCOMPARE(act1->parent(), (QObject*)s2);
+
+ QCOMPARE(s2->exitActions().size(), 0);
+ s2->addExitAction(act1); // should remove entry action
+ QCOMPARE(s2->exitActions().size(), 1);
+ QCOMPARE(s2->entryActions().size(), 0);
+ QCOMPARE(act1->parent(), (QObject*)s2);
+}
+
+void tst_QStateMachine::transitionActions()
+{
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+
+ QFinalState *s2 = new QFinalState(machine.rootState());
+ QTransition *trans = new EventTransition(QEvent::User, s2);
+ s1->addTransition(trans);
+ QVERIFY(trans->actions().isEmpty());
+ QTest::ignoreMessage(QtWarningMsg, "QTransition::addAction: cannot add null action");
+ trans->addAction(0);
+ QVERIFY(trans->actions().isEmpty());
+
+ TestStateAction *act = new TestStateAction();
+ trans->addAction(act);
+ QCOMPARE(trans->actions().size(), 1);
+ QCOMPARE(trans->actions().at(0), (QStateAction*)act);
+ QCOMPARE(act->parent(), (QObject*)trans);
+ QVERIFY(!act->didExecute());
+
+ trans->removeAction(act);
+ QVERIFY(trans->actions().isEmpty());
+ QCOMPARE(act->parent(), (QObject*)0);
+
+ trans->addAction(act);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QVERIFY(act->didExecute());
+
+ trans->setPropertyOnTransition(s1, "objectName", "foo");
+ trans->invokeMethodOnTransition(act, "deleteLater");
+
+ QPointer<QStateAction> ptr(act);
+ QVERIFY(ptr != 0);
+ finishedSpy.clear();
+ machine.start();
+ QCoreApplication::processEvents();
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+ QCoreApplication::processEvents();
+ QVERIFY(ptr == 0);
+ QCOMPARE(s1->objectName(), QString::fromLatin1("foo"));
+}
+
+void tst_QStateMachine::defaultGlobalRestorePolicy()
+{
+ QStateMachine machine;
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+ propertyHolder->setProperty("b", 2);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+
+ QState *s2 = new QState(machine.rootState());
+ s2->setPropertyOnEntry(propertyHolder, "b", 4);
+
+ QState *s3 = new QState(machine.rootState());
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+}
+
+void tst_QStateMachine::restorePolicyNotInherited()
+{
+ QStateMachine machine;
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+ propertyHolder->setProperty("b", 2);
+
+ QState *parentState = new QState(machine.rootState());
+ parentState->setObjectName("parentState");
+ parentState->setRestorePolicy(QState::RestoreProperties);
+
+ QState *s1 = new QState(parentState);
+ s1->setObjectName("s1");
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+ parentState->setInitialState(s1);
+
+ QState *s2 = new QState(parentState);
+ s2->setObjectName("s2");
+ s2->setPropertyOnEntry(propertyHolder, "b", 4);
+
+ QState *s3 = new QState(parentState);
+ s3->setObjectName("s3");
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(parentState);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+}
+
+void tst_QStateMachine::globalRestorePolicySetToDoNotRestore()
+{
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QState::DoNotRestoreProperties);
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+ propertyHolder->setProperty("b", 2);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+
+ QState *s2 = new QState(machine.rootState());
+ s2->setPropertyOnEntry(propertyHolder, "b", 4);
+
+ QState *s3 = new QState(machine.rootState());
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+}
+
+void tst_QStateMachine::setRestorePolicyToDoNotRestore()
+{
+ QObject *object = new QObject();
+ object->setProperty("a", 1);
+ object->setProperty("b", 2);
+
+ QStateMachine machine;
+
+ QState *S1 = new QState();
+ S1->setObjectName("S1");
+ S1->setPropertyOnEntry(object, "a", 3);
+ S1->setRestorePolicy(QState::DoNotRestoreProperties);
+ machine.addState(S1);
+
+ QState *S2 = new QState();
+ S2->setObjectName("S2");
+ S2->setPropertyOnEntry(object, "b", 5);
+ S2->setRestorePolicy(QState::DoNotRestoreProperties);
+ machine.addState(S2);
+
+ QState *S3 = new QState();
+ S3->setObjectName("S3");
+ S3->setRestorePolicy(QState::DoNotRestoreProperties);
+ machine.addState(S3);
+
+ QFinalState *S4 = new QFinalState();
+ machine.addState(S4);
+
+ S1->addTransition(new EventTransition(QEvent::User, S2));
+ S2->addTransition(new EventTransition(QEvent::User, S3));
+ S3->addTransition(S4);
+
+ machine.setInitialState(S1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 3);
+ QCOMPARE(object->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 3);
+ QCOMPARE(object->property("b").toInt(), 5);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(object->property("a").toInt(), 3);
+ QCOMPARE(object->property("b").toInt(), 5);
+}
+
+void tst_QStateMachine::setGlobalRestorePolicyToGlobalRestore()
+{
+ s_countWarnings = false;
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QState::GlobalRestorePolicy);
+
+ QCOMPARE(machine.globalRestorePolicy(), QState::DoNotRestoreProperties);
+ QCOMPARE(s_msgType, QtWarningMsg);
+
+ s_msgType = QtDebugMsg;
+ machine.setGlobalRestorePolicy(QState::RestoreProperties);
+ machine.setGlobalRestorePolicy(QState::GlobalRestorePolicy);
+
+ QCOMPARE(machine.globalRestorePolicy(), QState::RestoreProperties);
+ QCOMPARE(s_msgType, QtWarningMsg);
+}
+
+void tst_QStateMachine::restorePolicyOnChildState()
+{
+ QStateMachine machine;
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+ propertyHolder->setProperty("b", 2);
+
+ QState *parentState = new QState(machine.rootState());
+ parentState->setObjectName("parentState");
+
+ QState *s1 = new QState(parentState);
+ s1->setRestorePolicy(QState::RestoreProperties);
+ s1->setObjectName("s1");
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+ parentState->setInitialState(s1);
+
+ QState *s2 = new QState(parentState);
+ s2->setRestorePolicy(QState::RestoreProperties);
+ s2->setObjectName("s2");
+ s2->setPropertyOnEntry(propertyHolder, "b", 4);
+
+ QState *s3 = new QState(parentState);
+ s3->setRestorePolicy(QState::RestoreProperties);
+ s3->setObjectName("s3");
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(parentState);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 1);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 1);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+}
+
+void tst_QStateMachine::globalRestorePolicySetToRestore()
+{
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QState::RestoreProperties);
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+ propertyHolder->setProperty("b", 2);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+
+ QState *s2 = new QState(machine.rootState());
+ s2->setPropertyOnEntry(propertyHolder, "b", 4);
+
+ QState *s3 = new QState(machine.rootState());
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 1);
+ QCOMPARE(propertyHolder->property("b").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(propertyHolder->property("a").toInt(), 1);
+ QCOMPARE(propertyHolder->property("b").toInt(), 2);
+}
+
+void tst_QStateMachine::mixedRestoreProperties()
+{
+ QStateMachine machine;
+
+ QObject *propertyHolder = new QObject();
+ propertyHolder->setProperty("a", 1);
+
+ QState *s1 = new QState(machine.rootState());
+ s1->setRestorePolicy(QState::RestoreProperties);
+ s1->setPropertyOnEntry(propertyHolder, "a", 3);
+
+ QState *s2 = new QState(machine.rootState());
+ s2->setPropertyOnEntry(propertyHolder, "a", 4);
+
+ QState *s3 = new QState(machine.rootState());
+
+ QState *s4 = new QState(machine.rootState());
+ s4->setPropertyOnEntry(propertyHolder, "a", 5);
+
+ QState *s5 = new QState(machine.rootState());
+ s5->setRestorePolicy(QState::RestoreProperties);
+ s5->setPropertyOnEntry(propertyHolder, "a", 6);
+
+ s1->addTransition(new EventTransition(QEvent::User, s2));
+ s2->addTransition(new EventTransition(QEvent::User, s3));
+ s3->addTransition(new EventTransition(QEvent::User, s4));
+ s4->addTransition(new EventTransition(QEvent::User, s5));
+ s5->addTransition(new EventTransition(QEvent::User, s3));
+
+ machine.setInitialState(s1);
+ machine.start();
+ QCoreApplication::processEvents();
+
+ // Enter s1, save current
+ QCOMPARE(propertyHolder->property("a").toInt(), 3);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ // Enter s2, restorePolicy == DoNotRestore, so restore all properties
+ QCOMPARE(propertyHolder->property("a").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ // Enter s3
+ QCOMPARE(propertyHolder->property("a").toInt(), 4);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ // Enter s4
+ QCOMPARE(propertyHolder->property("a").toInt(), 5);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ // Enter s5, save current
+ QCOMPARE(propertyHolder->property("a").toInt(), 6);
+
+ machine.postEvent(new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+
+ // Enter s3, restore
+ QCOMPARE(propertyHolder->property("a").toInt(), 5);
+}
+
+void tst_QStateMachine::addAnimatedTransition()
+{
+ {
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ SignalEmitter emitter;
+ QState *as = s1->addAnimatedTransition(&emitter, SIGNAL(signalWithNoArg()), s2);
+ QVERIFY(as != 0);
+ QCOMPARE(as->parentState(), s2->parentState());
+ }
+ {
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ QState *s21 = new QState(s2);
+ SignalEmitter emitter;
+ QState *as = s1->addAnimatedTransition(&emitter, SIGNAL(signalWithNoArg()), s21);
+ QVERIFY(as != 0);
+ QCOMPARE(as->parentState(), s2);
+ }
+ {
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ SignalEmitter emitter;
+ QTest::ignoreMessage(QtWarningMsg, "QState::addAnimatedTransition: cannot add transition to target that doesn't have a parent state");
+ QState *as = s1->addAnimatedTransition(&emitter, SIGNAL(signalWithNoArg()), s2);
+ QCOMPARE(as, (QState*)0);
+ }
+}
+
+void tst_QStateMachine::transitionWithParent()
+{
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ EventTransition *trans = new EventTransition(QEvent::User, s2, s1);
+ QCOMPARE(trans->sourceState(), s1);
+ QCOMPARE(trans->targetState(), (QAbstractState*)s2);
+ QCOMPARE(trans->targetStates().size(), 1);
+ QCOMPARE(trans->targetStates().at(0), (QAbstractState*)s2);
+}
+
+QTEST_MAIN(tst_QStateMachine)
+#include "tst_qstatemachine.moc"
diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro
index 8e2c243..4c39373 100644
--- a/tests/benchmarks/benchmarks.pro
+++ b/tests/benchmarks/benchmarks.pro
@@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS = containers-associative \
containers-sequential \
+ qanimation \
qbytearray \
qpainter \
qtestlib-simple events \
diff --git a/tests/benchmarks/qanimation/dummyanimation.cpp b/tests/benchmarks/qanimation/dummyanimation.cpp
new file mode 100644
index 0000000..6fb1d0a
--- /dev/null
+++ b/tests/benchmarks/qanimation/dummyanimation.cpp
@@ -0,0 +1,20 @@
+#include "dummyanimation.h"
+#include "dummyobject.h"
+
+
+DummyAnimation::DummyAnimation(DummyObject *d) : m_dummy(d)
+{
+}
+
+void DummyAnimation::updateCurrentValue(const QVariant &value)
+{
+ if (state() == Stopped)
+ return;
+ if (m_dummy)
+ m_dummy->setRect(value.toRect());
+}
+
+void DummyAnimation::updateState(State state)
+{
+ Q_UNUSED(state);
+}
diff --git a/tests/benchmarks/qanimation/dummyanimation.h b/tests/benchmarks/qanimation/dummyanimation.h
new file mode 100644
index 0000000..fe6592b
--- /dev/null
+++ b/tests/benchmarks/qanimation/dummyanimation.h
@@ -0,0 +1,19 @@
+#include <QtGui>
+
+#ifndef _DUMMYANIMATION_H__
+
+class DummyObject;
+
+class DummyAnimation : public QVariantAnimation
+{
+public:
+ DummyAnimation(DummyObject *d);
+
+ void updateCurrentValue(const QVariant &value);
+ void updateState(State state);
+
+private:
+ DummyObject *m_dummy;
+};
+
+#endif \ No newline at end of file
diff --git a/tests/benchmarks/qanimation/dummyobject.cpp b/tests/benchmarks/qanimation/dummyobject.cpp
new file mode 100644
index 0000000..bd76388
--- /dev/null
+++ b/tests/benchmarks/qanimation/dummyobject.cpp
@@ -0,0 +1,25 @@
+#include "dummyobject.h"
+
+DummyObject::DummyObject()
+{
+}
+
+QRect DummyObject::rect() const
+{
+ return m_rect;
+}
+
+void DummyObject::setRect(const QRect &r)
+{
+ m_rect = r;
+}
+
+float DummyObject::opacity() const
+{
+ return m_opacity;
+}
+
+void DummyObject::setOpacity(float o)
+{
+ m_opacity = o;
+}
diff --git a/tests/benchmarks/qanimation/dummyobject.h b/tests/benchmarks/qanimation/dummyobject.h
new file mode 100644
index 0000000..c989662
--- /dev/null
+++ b/tests/benchmarks/qanimation/dummyobject.h
@@ -0,0 +1,23 @@
+#include <QtGui>
+
+#ifndef _DUMMYOBJECT_H__
+
+class DummyObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QRect rect READ rect WRITE setRect)
+ Q_PROPERTY(float opacity READ opacity WRITE setOpacity)
+public:
+ DummyObject();
+ QRect rect() const;
+ void setRect(const QRect &r);
+ float opacity() const;
+ void setOpacity(float);
+
+private:
+ QRect m_rect;
+ float m_opacity;
+};
+
+
+#endif \ No newline at end of file
diff --git a/tests/benchmarks/qanimation/main.cpp b/tests/benchmarks/qanimation/main.cpp
new file mode 100644
index 0000000..7bbcffb
--- /dev/null
+++ b/tests/benchmarks/qanimation/main.cpp
@@ -0,0 +1,173 @@
+#include <QtGui>
+#include <qtest.h>
+
+#include "dummyobject.h"
+#include "dummyanimation.h"
+#include "rectanimation.h"
+
+#define ITERATION_COUNT 10e3
+
+class tst_qanimation : public QObject
+{
+ Q_OBJECT
+private slots:
+ void itemAnimation();
+ void itemAnimation_data() { data();}
+ void itemPropertyAnimation();
+ void itemPropertyAnimation_data() { data();}
+ void dummyAnimation();
+ void dummyAnimation_data() { data();}
+ void dummyPropertyAnimation();
+ void dummyPropertyAnimation_data() { data();}
+ void rectAnimation();
+ void rectAnimation_data() { data();}
+
+ void floatAnimation_data() { data(); }
+ void floatAnimation();
+
+private:
+ void data();
+};
+
+
+void tst_qanimation::data()
+{
+ QTest::addColumn<bool>("paused");
+ QTest::newRow("NotRunning") << false;
+ QTest::newRow("Paused") << true;
+}
+
+void tst_qanimation::itemAnimation()
+{
+ QFETCH(bool, paused);
+ QGraphicsWidget item;
+
+ //first the item animation
+ {
+ QItemAnimation anim(&item, QItemAnimation::Position);
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(QPointF(0,0));
+ anim.setEndValue(QPointF(ITERATION_COUNT,ITERATION_COUNT));
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < anim.duration(); ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+}
+
+void tst_qanimation::itemPropertyAnimation()
+{
+ QFETCH(bool, paused);
+ QGraphicsWidget item;
+
+ //then the property animation
+ {
+ QPropertyAnimation anim(&item, "pos");
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(QPointF(0,0));
+ anim.setEndValue(QPointF(ITERATION_COUNT,ITERATION_COUNT));
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < ITERATION_COUNT; ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+
+}
+
+void tst_qanimation::dummyAnimation()
+{
+ QFETCH(bool, paused);
+ DummyObject dummy;
+
+ //first the dummy animation
+ {
+ DummyAnimation anim(&dummy);
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(QRect(0, 0, 0, 0));
+ anim.setEndValue(QRect(0, 0, ITERATION_COUNT,ITERATION_COUNT));
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < anim.duration(); ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+}
+
+void tst_qanimation::dummyPropertyAnimation()
+{
+ QFETCH(bool, paused);
+ DummyObject dummy;
+
+ //then the property animation
+ {
+ QPropertyAnimation anim(&dummy, "rect");
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(QRect(0, 0, 0, 0));
+ anim.setEndValue(QRect(0, 0, ITERATION_COUNT,ITERATION_COUNT));
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < ITERATION_COUNT; ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+}
+
+void tst_qanimation::rectAnimation()
+{
+ //this is the simplest animation you can do
+ QFETCH(bool, paused);
+ DummyObject dummy;
+
+ //then the property animation
+ {
+ RectAnimation anim(&dummy);
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(QRect(0, 0, 0, 0));
+ anim.setEndValue(QRect(0, 0, ITERATION_COUNT,ITERATION_COUNT));
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < ITERATION_COUNT; ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+}
+
+void tst_qanimation::floatAnimation()
+{
+ //this is the simplest animation you can do
+ QFETCH(bool, paused);
+ DummyObject dummy;
+
+ //then the property animation
+ {
+ QPropertyAnimation anim(&dummy, "opacity");
+ anim.setDuration(ITERATION_COUNT);
+ anim.setStartValue(0.f);
+ anim.setEndValue(1.f);
+ if (paused)
+ anim.pause();
+ QBENCHMARK {
+ for(int i = 0; i < ITERATION_COUNT; ++i) {
+ anim.setCurrentTime(i);
+ }
+ }
+ }
+}
+
+
+
+QTEST_MAIN(tst_qanimation)
+
+#include "main.moc"
diff --git a/tests/benchmarks/qanimation/qanimation.pro b/tests/benchmarks/qanimation/qanimation.pro
new file mode 100644
index 0000000..55cd75e
--- /dev/null
+++ b/tests/benchmarks/qanimation/qanimation.pro
@@ -0,0 +1,18 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = tst_qanimation
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG += release
+#CONFIG += debug
+
+
+SOURCES += main.cpp \
+ dummyobject.cpp \
+ dummyanimation.cpp \
+ rectanimation.cpp
+
+HEADERS += dummyobject.h \
+ dummyanimation.h \
+ rectanimation.h
diff --git a/tests/benchmarks/qanimation/rectanimation.cpp b/tests/benchmarks/qanimation/rectanimation.cpp
new file mode 100644
index 0000000..66c7a33
--- /dev/null
+++ b/tests/benchmarks/qanimation/rectanimation.cpp
@@ -0,0 +1,58 @@
+#include "rectanimation.h"
+#include "dummyobject.h"
+
+static inline int interpolateInteger(int from, int to, qreal progress)
+{
+ return from + (to - from) * progress;
+}
+
+
+RectAnimation::RectAnimation(DummyObject *obj) : object(obj), dura(250)
+{
+}
+
+void RectAnimation::setEndValue(const QRect &rect)
+{
+ end = rect;
+}
+
+void RectAnimation::setStartValue(const QRect &rect)
+{
+ start = rect;
+}
+
+void RectAnimation::setDuration(int d)
+{
+ dura = d;
+}
+
+int RectAnimation::duration() const
+{
+ return dura;
+}
+
+
+void RectAnimation::updateCurrentTime(int msecs)
+{
+ qreal progress = easing.valueForProgress( qreal(msecs) / qreal(dura) );
+ QRect now;
+ now.setCoords(interpolateInteger(start.left(), end.left(), progress),
+ interpolateInteger(start.top(), end.top(), progress),
+ interpolateInteger(start.right(), end.right(), progress),
+ interpolateInteger(start.bottom(), end.bottom(), progress));
+
+ bool changed = (now != current);
+ if (changed)
+ current = now;
+
+ if (state() == Stopped)
+ return;
+
+ if (object)
+ object->setRect(current);
+}
+
+void RectAnimation::updateState(QAbstractAnimation::State state)
+{
+ Q_UNUSED(state);
+}
diff --git a/tests/benchmarks/qanimation/rectanimation.h b/tests/benchmarks/qanimation/rectanimation.h
new file mode 100644
index 0000000..c9770c4
--- /dev/null
+++ b/tests/benchmarks/qanimation/rectanimation.h
@@ -0,0 +1,30 @@
+#include <QtGui>
+
+#ifndef _RECTANIMATION_H__
+
+class DummyObject;
+
+//this class is even simpler than the dummy
+//and uses no QVariant at all
+class RectAnimation : public QAbstractAnimation
+{
+public:
+ RectAnimation(DummyObject *obj);
+
+ void setEndValue(const QRect &rect);
+ void setStartValue(const QRect &rect);
+
+ void setDuration(int d);
+ int duration() const;
+
+ virtual void updateCurrentTime(int msecs);
+ virtual void updateState(QAbstractAnimation::State state);
+
+private:
+ DummyObject *object;
+ QEasingCurve easing;
+ QRect start, end, current;
+ int dura;
+};
+
+#endif \ No newline at end of file
diff --git a/tests/benchmarks/qvariant/qvariant.pro b/tests/benchmarks/qvariant/qvariant.pro
index 68b4a97..63b5442 100644
--- a/tests/benchmarks/qvariant/qvariant.pro
+++ b/tests/benchmarks/qvariant/qvariant.pro
@@ -3,7 +3,6 @@ TEMPLATE = app
TARGET = tst_qvariant
DEPENDPATH += .
INCLUDEPATH += .
-QT -= gui
CONFIG += release
#CONFIG += debug
diff --git a/tests/benchmarks/qvariant/tst_qvariant.cpp b/tests/benchmarks/qvariant/tst_qvariant.cpp
index 4a7ad02..0eb1ae2 100644
--- a/tests/benchmarks/qvariant/tst_qvariant.cpp
+++ b/tests/benchmarks/qvariant/tst_qvariant.cpp
@@ -38,7 +38,9 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
#include <QtCore>
+#include <QtGui/QPixmap>
#include <qtest.h>
#define ITERATION_COUNT 1e5
@@ -47,64 +49,73 @@ class tst_qvariant : public QObject
{
Q_OBJECT
private slots:
+ void testBound();
+
void doubleVariantCreation();
void floatVariantCreation();
void rectVariantCreation();
void stringVariantCreation();
+ void pixmapVariantCreation();
+
void doubleVariantSetValue();
void floatVariantSetValue();
void rectVariantSetValue();
void stringVariantSetValue();
+
void doubleVariantAssignment();
void floatVariantAssignment();
void rectVariantAssignment();
void stringVariantAssignment();
};
-
-void tst_qvariant::doubleVariantCreation()
+void tst_qvariant::testBound()
{
- double d = 0;
+ qreal d = qreal(.5);
QBENCHMARK {
for(int i = 0; i < ITERATION_COUNT; ++i) {
- QVariant v(d);
+ d = qBound<qreal>(0, d, 1);
}
}
}
-void tst_qvariant::floatVariantCreation()
+template <typename T>
+static void variantCreation(T val)
{
- float f = 0;
QBENCHMARK {
for(int i = 0; i < ITERATION_COUNT; ++i) {
- QVariant v(f);
+ QVariant v(val);
}
}
}
+void tst_qvariant::doubleVariantCreation()
+{
+ variantCreation<double>(0.0);
+}
+
+void tst_qvariant::floatVariantCreation()
+{
+ variantCreation<float>(0.0f);
+}
+
void tst_qvariant::rectVariantCreation()
{
- QRect r(1,2,3,4);
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- QVariant v(r);
- }
- }
+ variantCreation<QRect>(QRect(1, 2, 3, 4));
}
void tst_qvariant::stringVariantCreation()
{
- QString s;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- QVariant v(s);
- }
- }
+ variantCreation<QString>(QString());
}
-void tst_qvariant::doubleVariantSetValue()
+void tst_qvariant::pixmapVariantCreation()
+{
+ variantCreation<QPixmap>(QPixmap());
+}
+
+template <typename T>
+static void variantSetValue(T d)
{
- double d = 0;
QVariant v;
QBENCHMARK {
for(int i = 0; i < ITERATION_COUNT; ++i) {
@@ -113,42 +124,29 @@ void tst_qvariant::doubleVariantSetValue()
}
}
+void tst_qvariant::doubleVariantSetValue()
+{
+ variantSetValue<double>(0.0);
+}
+
void tst_qvariant::floatVariantSetValue()
{
- float f = 0;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- qVariantSetValue(v, f);
- }
- }
+ variantSetValue<float>(0.0f);
}
void tst_qvariant::rectVariantSetValue()
{
- QRect r;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- qVariantSetValue(v, r);
- }
- }
+ variantSetValue<QRect>(QRect());
}
void tst_qvariant::stringVariantSetValue()
{
- QString s;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- qVariantSetValue(v, s);
- }
- }
+ variantSetValue<QString>(QString());
}
-void tst_qvariant::doubleVariantAssignment()
+template <typename T>
+static void variantAssignment(T d)
{
- double d = 0;
QVariant v;
QBENCHMARK {
for(int i = 0; i < ITERATION_COUNT; ++i) {
@@ -157,37 +155,24 @@ void tst_qvariant::doubleVariantAssignment()
}
}
+void tst_qvariant::doubleVariantAssignment()
+{
+ variantAssignment<double>(0.0);
+}
+
void tst_qvariant::floatVariantAssignment()
{
- float f = 0;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- v = f;
- }
- }
+ variantAssignment<float>(0.0f);
}
void tst_qvariant::rectVariantAssignment()
{
- QRect r;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- v = r;
- }
- }
+ variantAssignment<QRect>(QRect());
}
void tst_qvariant::stringVariantAssignment()
{
- QString s;
- QVariant v;
- QBENCHMARK {
- for(int i = 0; i < ITERATION_COUNT; ++i) {
- v = s;
- }
- }
+ variantAssignment<QString>(QString());
}
QTEST_MAIN(tst_qvariant)