tests/auto/qstatemachine/tst_qstatemachine.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtTest/QtTest>
       
    43 #include <QtCore/QCoreApplication>
       
    44 #include <QtGui/QPushButton>
       
    45 #include <QtGui/QGraphicsScene>
       
    46 #include <QtGui/QGraphicsSceneEvent>
       
    47 #include <QtGui/QGraphicsTextItem>
       
    48 
       
    49 #include "qstatemachine.h"
       
    50 #include "qstate.h"
       
    51 #include "qhistorystate.h"
       
    52 #include "qkeyeventtransition.h"
       
    53 #include "qmouseeventtransition.h"
       
    54 #include "private/qstate_p.h"
       
    55 #include "private/qstatemachine_p.h"
       
    56 
       
    57 // Will try to wait for the condition while allowing event processing
       
    58 #define QTRY_COMPARE(__expr, __expected) \
       
    59     do { \
       
    60         const int __step = 50; \
       
    61         const int __timeout = 5000; \
       
    62         if ((__expr) != (__expected)) { \
       
    63             QTest::qWait(0); \
       
    64         } \
       
    65         for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
       
    66             QTest::qWait(__step); \
       
    67         } \
       
    68         QCOMPARE(__expr, __expected); \
       
    69     } while(0)
       
    70 
       
    71 //TESTED_CLASS=
       
    72 //TESTED_FILES=
       
    73 
       
    74 static int globalTick;
       
    75 
       
    76 // Run exec for a maximum of TIMEOUT msecs
       
    77 #define QCOREAPPLICATION_EXEC(TIMEOUT) \
       
    78 { \
       
    79     QTimer timer; \
       
    80     timer.setSingleShot(true); \
       
    81     timer.setInterval(TIMEOUT); \
       
    82     timer.start(); \
       
    83     connect(&timer, SIGNAL(timeout()), QCoreApplication::instance(), SLOT(quit())); \
       
    84     QCoreApplication::exec(); \
       
    85 }
       
    86 
       
    87 class SignalEmitter : public QObject
       
    88 {
       
    89 Q_OBJECT
       
    90     public:
       
    91     SignalEmitter(QObject *parent = 0)
       
    92         : QObject(parent) {}
       
    93     void emitSignalWithNoArg()
       
    94         { emit signalWithNoArg(); }
       
    95     void emitSignalWithIntArg(int arg)
       
    96         { emit signalWithIntArg(arg); }
       
    97     void emitSignalWithStringArg(const QString &arg)
       
    98         { emit signalWithStringArg(arg); }
       
    99     void emitSignalWithDefaultArg()
       
   100         { emit signalWithDefaultArg(); }
       
   101 Q_SIGNALS:
       
   102     void signalWithNoArg();
       
   103     void signalWithIntArg(int);
       
   104     void signalWithStringArg(const QString &);
       
   105     void signalWithDefaultArg(int i = 42);
       
   106 };
       
   107 
       
   108 class tst_QStateMachine : public QObject
       
   109 {
       
   110     Q_OBJECT
       
   111 public:
       
   112     tst_QStateMachine();
       
   113     virtual ~tst_QStateMachine();
       
   114 
       
   115 private slots:
       
   116     void init();
       
   117     void cleanup();
       
   118 
       
   119     void rootState();
       
   120     void addAndRemoveState();
       
   121     void stateEntryAndExit();
       
   122     void assignProperty();
       
   123     void assignPropertyWithAnimation();
       
   124     void postEvent();
       
   125     void cancelDelayedEvent();
       
   126     void postDelayedEventAndStop();
       
   127     void stateFinished();
       
   128     void parallelStates();
       
   129     void parallelRootState();
       
   130     void allSourceToTargetConfigurations();
       
   131     void signalTransitions();
       
   132     void eventTransitions();
       
   133     void graphicsSceneEventTransitions();
       
   134     void historyStates();
       
   135     void startAndStop();
       
   136     void targetStateWithNoParent();
       
   137     void targetStateDeleted();
       
   138     void transitionToRootState();
       
   139     void transitionFromRootState();
       
   140     void transitionEntersParent();
       
   141 
       
   142     void defaultErrorState();
       
   143     void customGlobalErrorState();
       
   144     void customLocalErrorStateInBrokenState();
       
   145     void customLocalErrorStateInOtherState();
       
   146     void customLocalErrorStateInParentOfBrokenState();
       
   147     void customLocalErrorStateOverridesParent();
       
   148     void errorStateHasChildren();
       
   149     void errorStateHasErrors();
       
   150     void errorStateIsRootState();
       
   151     void errorStateEntersParentFirst();
       
   152     void customErrorStateIsNull();
       
   153     void clearError();
       
   154     void historyStateHasNowhereToGo();
       
   155     void historyStateAsInitialState();
       
   156     void brokenStateIsNeverEntered();
       
   157     void customErrorStateNotInGraph();
       
   158     void transitionToStateNotInGraph();
       
   159     void restoreProperties();
       
   160 
       
   161     void defaultGlobalRestorePolicy();
       
   162     void globalRestorePolicySetToRestore();
       
   163     void globalRestorePolicySetToDoNotRestore();
       
   164 
       
   165     void noInitialStateForInitialState();
       
   166 
       
   167     //void restorePolicyNotInherited();
       
   168     //void mixedRestoreProperties();
       
   169     //void setRestorePolicyToDoNotRestore();
       
   170     //void setGlobalRestorePolicyToGlobalRestore();
       
   171     //void restorePolicyOnChildState();
       
   172 
       
   173     void transitionWithParent();
       
   174     void transitionsFromParallelStateWithNoChildren();
       
   175     void parallelStateTransition();
       
   176     void parallelStateAssignmentsDone();
       
   177     void nestedRestoreProperties();
       
   178     void nestedRestoreProperties2();
       
   179 
       
   180     void simpleAnimation();
       
   181     void twoAnimations();
       
   182     void twoAnimatedTransitions();
       
   183     void playAnimationTwice();
       
   184     void nestedTargetStateForAnimation();
       
   185     void polishedSignalTransitionsReuseAnimationGroup();
       
   186     void animatedGlobalRestoreProperty();
       
   187     void specificTargetValueOfAnimation();
       
   188 
       
   189     void addDefaultAnimation();
       
   190     void addDefaultAnimationWithUnusedAnimation();
       
   191     void removeDefaultAnimation();
       
   192     void overrideDefaultAnimationWithSpecific();
       
   193 
       
   194 //    void addDefaultAnimationForSource();
       
   195 //    void addDefaultAnimationForTarget();
       
   196 //    void removeDefaultAnimationForSource();
       
   197 //    void removeDefaultAnimationForTarget();
       
   198 //    void overrideDefaultAnimationWithSource();
       
   199 //    void overrideDefaultAnimationWithTarget();
       
   200 //    void overrideDefaultSourceAnimationWithSpecific();
       
   201 //    void overrideDefaultTargetAnimationWithSpecific();
       
   202 //    void overrideDefaultTargetAnimationWithSource();
       
   203 
       
   204     void nestedStateMachines();
       
   205     void goToState();
       
   206 
       
   207     void task260403_clonedSignals();
       
   208 };
       
   209 
       
   210 tst_QStateMachine::tst_QStateMachine()
       
   211 {
       
   212 }
       
   213 
       
   214 tst_QStateMachine::~tst_QStateMachine()
       
   215 {
       
   216 }
       
   217 
       
   218 class TestState : public QState
       
   219 {
       
   220 public:
       
   221     enum Event {
       
   222         Entry,
       
   223         Exit
       
   224     };
       
   225     TestState(QState *parent)
       
   226         : QState(parent) {}
       
   227     QList<QPair<int, Event> > events;
       
   228 protected:
       
   229     virtual void onEntry(QEvent *) {
       
   230         events.append(qMakePair(globalTick++, Entry));
       
   231     }
       
   232     virtual void onExit(QEvent *) {
       
   233         events.append(qMakePair(globalTick++, Exit));
       
   234     }
       
   235 };
       
   236 
       
   237 class TestTransition : public QAbstractTransition
       
   238 {
       
   239 public:
       
   240     TestTransition(QAbstractState *target)
       
   241         : QAbstractTransition()
       
   242     { setTargetState(target); }
       
   243     QList<int> triggers;
       
   244 protected:
       
   245     virtual bool eventTest(QEvent *) {
       
   246         return true;
       
   247     }
       
   248     virtual void onTransition(QEvent *) {
       
   249         triggers.append(globalTick++);
       
   250     }
       
   251 };
       
   252 
       
   253 void tst_QStateMachine::init()
       
   254 {
       
   255 }
       
   256 
       
   257 void tst_QStateMachine::cleanup()
       
   258 {
       
   259 }
       
   260 
       
   261 class EventTransition : public QAbstractTransition
       
   262 {
       
   263 public:
       
   264     EventTransition(QEvent::Type type, QAbstractState *target, QState *parent = 0)
       
   265         : QAbstractTransition(parent), m_type(type)
       
   266     { setTargetState(target); }
       
   267 protected:
       
   268     virtual bool eventTest(QEvent *e) {
       
   269         return (e->type() == m_type);
       
   270     }
       
   271     virtual void onTransition(QEvent *) {}
       
   272 private:
       
   273     QEvent::Type m_type;
       
   274 };
       
   275 
       
   276 void tst_QStateMachine::transitionToRootState()
       
   277 {
       
   278     QStateMachine machine;
       
   279     machine.setObjectName("machine");
       
   280 
       
   281     QState *initialState = new QState();
       
   282     initialState->setObjectName("initial");
       
   283     machine.addState(initialState);
       
   284     machine.setInitialState(initialState);
       
   285 
       
   286     QAbstractTransition *trans = initialState->addTransition(new EventTransition(QEvent::User, &machine));
       
   287     QVERIFY(trans != 0);
       
   288     QCOMPARE(trans->sourceState(), initialState);
       
   289     QCOMPARE(trans->targetState(), static_cast<QAbstractState *>(&machine));
       
   290 
       
   291     machine.start();
       
   292     QCoreApplication::processEvents();
       
   293 
       
   294     QCOMPARE(machine.configuration().count(), 1);
       
   295     QVERIFY(machine.configuration().contains(initialState));
       
   296 
       
   297     machine.postEvent(new QEvent(QEvent::User));
       
   298     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initial'");
       
   299     QCoreApplication::processEvents();
       
   300     QVERIFY(machine.configuration().isEmpty());
       
   301     QVERIFY(!machine.isRunning());
       
   302 }
       
   303 
       
   304 void tst_QStateMachine::transitionFromRootState()
       
   305 {
       
   306     QStateMachine machine;
       
   307     QState *root = &machine;
       
   308     QState *s1 = new QState(root);
       
   309     EventTransition *trans = new EventTransition(QEvent::User, s1);
       
   310     QCOMPARE(root->addTransition(trans), static_cast<QAbstractTransition *>(trans));
       
   311     QCOMPARE(trans->sourceState(), root);
       
   312     QCOMPARE(trans->targetState(), static_cast<QAbstractState *>(s1));
       
   313 }
       
   314 
       
   315 void tst_QStateMachine::transitionEntersParent()
       
   316 {
       
   317     QStateMachine machine;
       
   318 
       
   319     QObject *entryController = new QObject(&machine);
       
   320     entryController->setObjectName("entryController");
       
   321     entryController->setProperty("greatGrandParentEntered", false);
       
   322     entryController->setProperty("grandParentEntered", false);
       
   323     entryController->setProperty("parentEntered", false);
       
   324     entryController->setProperty("stateEntered", false);
       
   325 
       
   326     QState *greatGrandParent = new QState();
       
   327     greatGrandParent->setObjectName("grandParent");
       
   328     greatGrandParent->assignProperty(entryController, "greatGrandParentEntered", true);
       
   329     machine.addState(greatGrandParent);
       
   330     machine.setInitialState(greatGrandParent);
       
   331 
       
   332     QState *grandParent = new QState(greatGrandParent);
       
   333     grandParent->setObjectName("grandParent");
       
   334     grandParent->assignProperty(entryController, "grandParentEntered", true);
       
   335 
       
   336     QState *parent = new QState(grandParent);
       
   337     parent->setObjectName("parent");
       
   338     parent->assignProperty(entryController, "parentEntered", true);
       
   339 
       
   340     QState *state = new QState(parent);
       
   341     state->setObjectName("state");
       
   342     state->assignProperty(entryController, "stateEntered", true);
       
   343 
       
   344     QState *initialStateOfGreatGrandParent = new QState(greatGrandParent);
       
   345     initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent");
       
   346     greatGrandParent->setInitialState(initialStateOfGreatGrandParent);
       
   347 
       
   348     initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, state));
       
   349 
       
   350     machine.start();
       
   351     QCoreApplication::processEvents();
       
   352 
       
   353     QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true);
       
   354     QCOMPARE(entryController->property("grandParentEntered").toBool(), false);
       
   355     QCOMPARE(entryController->property("parentEntered").toBool(), false);
       
   356     QCOMPARE(entryController->property("stateEntered").toBool(), false);
       
   357     QCOMPARE(machine.configuration().count(), 2);
       
   358     QVERIFY(machine.configuration().contains(greatGrandParent));
       
   359     QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent));
       
   360 
       
   361     entryController->setProperty("greatGrandParentEntered", false);
       
   362     entryController->setProperty("grandParentEntered", false);
       
   363     entryController->setProperty("parentEntered", false);
       
   364     entryController->setProperty("stateEntered", false);
       
   365 
       
   366     machine.postEvent(new QEvent(QEvent::User));
       
   367     QCoreApplication::processEvents();
       
   368 
       
   369     QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false);
       
   370     QCOMPARE(entryController->property("grandParentEntered").toBool(), true);
       
   371     QCOMPARE(entryController->property("parentEntered").toBool(), true);
       
   372     QCOMPARE(entryController->property("stateEntered").toBool(), true);
       
   373     QCOMPARE(machine.configuration().count(), 4);
       
   374     QVERIFY(machine.configuration().contains(greatGrandParent));
       
   375     QVERIFY(machine.configuration().contains(grandParent));
       
   376     QVERIFY(machine.configuration().contains(parent));
       
   377     QVERIFY(machine.configuration().contains(state));
       
   378 }
       
   379 
       
   380 void tst_QStateMachine::defaultErrorState()
       
   381 {
       
   382     QStateMachine machine;
       
   383     QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0));
       
   384 
       
   385     QState *brokenState = new QState();
       
   386     brokenState->setObjectName("MyInitialState");
       
   387 
       
   388     machine.addState(brokenState);
       
   389     machine.setInitialState(brokenState);
       
   390 
       
   391     QState *childState = new QState(brokenState);
       
   392     childState->setObjectName("childState");
       
   393 
       
   394     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'MyInitialState'");
       
   395 
       
   396     // initialState has no initial state
       
   397     machine.start();
       
   398     QCoreApplication::processEvents();
       
   399 
       
   400     QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
       
   401     QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'MyInitialState'"));
       
   402     QCOMPARE(machine.isRunning(), false);
       
   403 }
       
   404 
       
   405 class CustomErrorState: public QState
       
   406 {
       
   407 public:
       
   408     CustomErrorState(QStateMachine *machine, QState *parent = 0)
       
   409         : QState(parent), error(QStateMachine::NoError), m_machine(machine)
       
   410     {
       
   411     }
       
   412 
       
   413     void onEntry(QEvent *)
       
   414     {
       
   415         error = m_machine->error();
       
   416         errorString = m_machine->errorString();
       
   417     }
       
   418 
       
   419     QStateMachine::Error error;
       
   420     QString errorString;
       
   421 
       
   422 private:
       
   423     QStateMachine *m_machine;
       
   424 };
       
   425 
       
   426 void tst_QStateMachine::customGlobalErrorState()
       
   427 {
       
   428     QStateMachine machine;
       
   429 
       
   430     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   431     customErrorState->setObjectName("customErrorState");
       
   432     machine.addState(customErrorState);
       
   433     machine.setErrorState(customErrorState);
       
   434 
       
   435     QState *initialState = new QState();
       
   436     initialState->setObjectName("initialState");
       
   437     machine.addState(initialState);
       
   438     machine.setInitialState(initialState);
       
   439 
       
   440     QState *brokenState = new QState();
       
   441     brokenState->setObjectName("brokenState");
       
   442     machine.addState(brokenState);
       
   443     QState *childState = new QState(brokenState);
       
   444     childState->setObjectName("childState");
       
   445 
       
   446     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   447     machine.start();
       
   448     QCoreApplication::processEvents();
       
   449 
       
   450     QCOMPARE(machine.errorState(), static_cast<QAbstractState*>(customErrorState));
       
   451     QCOMPARE(machine.configuration().count(), 1);
       
   452     QVERIFY(machine.configuration().contains(initialState));
       
   453 
       
   454     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   455     QCOMPARE(machine.configuration().count(), 1);
       
   456     QVERIFY(machine.configuration().contains(initialState));
       
   457 
       
   458     QCoreApplication::processEvents();
       
   459 
       
   460     QCOMPARE(machine.isRunning(), true);
       
   461     QCOMPARE(machine.configuration().count(), 1);
       
   462     QVERIFY(machine.configuration().contains(customErrorState));
       
   463     QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError);
       
   464     QCOMPARE(customErrorState->errorString, QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
       
   465     QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
       
   466     QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
       
   467 }
       
   468 
       
   469 void tst_QStateMachine::customLocalErrorStateInBrokenState()
       
   470 {
       
   471     QStateMachine machine;
       
   472     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   473     machine.addState(customErrorState);
       
   474 
       
   475     QState *initialState = new QState();
       
   476     initialState->setObjectName("initialState");
       
   477     machine.addState(initialState);
       
   478     machine.setInitialState(initialState);
       
   479 
       
   480     QState *brokenState = new QState();
       
   481     brokenState->setObjectName("brokenState");
       
   482     machine.addState(brokenState);
       
   483     brokenState->setErrorState(customErrorState);
       
   484 
       
   485     QState *childState = new QState(brokenState);
       
   486     childState->setObjectName("childState");
       
   487 
       
   488     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   489 
       
   490     machine.start();
       
   491     QCoreApplication::processEvents();
       
   492 
       
   493     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   494     QCoreApplication::processEvents();
       
   495 
       
   496     QCOMPARE(machine.isRunning(), true);
       
   497     QCOMPARE(machine.configuration().count(), 1);
       
   498     QVERIFY(machine.configuration().contains(customErrorState));
       
   499     QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError);
       
   500 }
       
   501 
       
   502 void tst_QStateMachine::customLocalErrorStateInOtherState()
       
   503 {
       
   504     QStateMachine machine;
       
   505     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   506     machine.addState(customErrorState);
       
   507 
       
   508     QState *initialState = new QState();
       
   509     initialState->setObjectName("initialState");
       
   510     QTest::ignoreMessage(QtWarningMsg, "QState::setErrorState: error state cannot belong to a different state machine");
       
   511     initialState->setErrorState(customErrorState);
       
   512     machine.addState(initialState);
       
   513     machine.setInitialState(initialState);
       
   514 
       
   515     QState *brokenState = new QState();
       
   516     brokenState->setObjectName("brokenState");
       
   517 
       
   518     machine.addState(brokenState);
       
   519 
       
   520     QState *childState = new QState(brokenState);
       
   521     childState->setObjectName("childState");
       
   522 
       
   523     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   524 
       
   525     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'brokenState'");
       
   526     machine.start();
       
   527     QCoreApplication::processEvents();
       
   528 
       
   529     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   530     QCoreApplication::processEvents();
       
   531 
       
   532     QCOMPARE(machine.isRunning(), false);
       
   533 }
       
   534 
       
   535 void tst_QStateMachine::customLocalErrorStateInParentOfBrokenState()
       
   536 {
       
   537     QStateMachine machine;
       
   538     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   539     machine.addState(customErrorState);
       
   540 
       
   541     QState *initialState = new QState();
       
   542     initialState->setObjectName("initialState");
       
   543     machine.addState(initialState);
       
   544     machine.setInitialState(initialState);
       
   545 
       
   546     QState *parentOfBrokenState = new QState();
       
   547     machine.addState(parentOfBrokenState);
       
   548     parentOfBrokenState->setObjectName("parentOfBrokenState");
       
   549     parentOfBrokenState->setErrorState(customErrorState);
       
   550 
       
   551     QState *brokenState = new QState(parentOfBrokenState);
       
   552     brokenState->setObjectName("brokenState");
       
   553     parentOfBrokenState->setInitialState(brokenState);
       
   554 
       
   555     QState *childState = new QState(brokenState);
       
   556     childState->setObjectName("childState");
       
   557 
       
   558     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   559 
       
   560     machine.start();
       
   561     QCoreApplication::processEvents();
       
   562 
       
   563     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   564     QCoreApplication::processEvents();
       
   565 
       
   566     QCOMPARE(machine.isRunning(), true);
       
   567     QCOMPARE(machine.configuration().count(), 1);
       
   568     QVERIFY(machine.configuration().contains(customErrorState));
       
   569 }
       
   570 
       
   571 void tst_QStateMachine::customLocalErrorStateOverridesParent()
       
   572 {
       
   573     QStateMachine machine;
       
   574     CustomErrorState *customErrorStateForParent = new CustomErrorState(&machine);
       
   575     machine.addState(customErrorStateForParent);
       
   576 
       
   577     CustomErrorState *customErrorStateForBrokenState = new CustomErrorState(&machine);
       
   578     machine.addState(customErrorStateForBrokenState);
       
   579 
       
   580     QState *initialState = new QState();
       
   581     initialState->setObjectName("initialState");
       
   582     machine.addState(initialState);
       
   583     machine.setInitialState(initialState);
       
   584 
       
   585     QState *parentOfBrokenState = new QState();
       
   586     machine.addState(parentOfBrokenState);
       
   587     parentOfBrokenState->setObjectName("parentOfBrokenState");
       
   588     parentOfBrokenState->setErrorState(customErrorStateForParent);
       
   589 
       
   590     QState *brokenState = new QState(parentOfBrokenState);
       
   591     brokenState->setObjectName("brokenState");
       
   592     brokenState->setErrorState(customErrorStateForBrokenState);
       
   593     parentOfBrokenState->setInitialState(brokenState);
       
   594 
       
   595     QState *childState = new QState(brokenState);
       
   596     childState->setObjectName("childState");
       
   597 
       
   598     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   599 
       
   600     machine.start();
       
   601     QCoreApplication::processEvents();
       
   602 
       
   603     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   604     QCoreApplication::processEvents();
       
   605 
       
   606     QCOMPARE(machine.configuration().count(), 1);
       
   607     QVERIFY(machine.configuration().contains(customErrorStateForBrokenState));
       
   608     QCOMPARE(customErrorStateForBrokenState->error, QStateMachine::NoInitialStateError);
       
   609     QCOMPARE(customErrorStateForParent->error, QStateMachine::NoError);
       
   610 }
       
   611 
       
   612 void tst_QStateMachine::errorStateHasChildren()
       
   613 {
       
   614     QStateMachine machine;
       
   615     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   616     customErrorState->setObjectName("customErrorState");
       
   617     machine.addState(customErrorState);
       
   618 
       
   619     machine.setErrorState(customErrorState);
       
   620 
       
   621     QState *childOfErrorState = new QState(customErrorState);
       
   622     childOfErrorState->setObjectName("childOfErrorState");
       
   623     customErrorState->setInitialState(childOfErrorState);
       
   624 
       
   625     QState *initialState = new QState();
       
   626     initialState->setObjectName("initialState");
       
   627     machine.addState(initialState);
       
   628     machine.setInitialState(initialState);
       
   629 
       
   630     QState *brokenState = new QState();
       
   631     brokenState->setObjectName("brokenState");
       
   632     machine.addState(brokenState);
       
   633 
       
   634     QState *childState = new QState(brokenState);
       
   635     childState->setObjectName("childState");
       
   636 
       
   637     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   638 
       
   639     machine.start();
       
   640     QCoreApplication::processEvents();
       
   641 
       
   642     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   643     QCoreApplication::processEvents();
       
   644 
       
   645     QCOMPARE(machine.isRunning(), true);
       
   646     QCOMPARE(machine.configuration().count(), 2);
       
   647     QVERIFY(machine.configuration().contains(customErrorState));
       
   648     QVERIFY(machine.configuration().contains(childOfErrorState));
       
   649 }
       
   650 
       
   651 
       
   652 void tst_QStateMachine::errorStateHasErrors()
       
   653 {
       
   654     QStateMachine machine;
       
   655     CustomErrorState *customErrorState = new CustomErrorState(&machine);
       
   656     customErrorState->setObjectName("customErrorState");
       
   657     machine.addState(customErrorState);
       
   658 
       
   659     machine.setErrorState(customErrorState);
       
   660 
       
   661     QState *childOfErrorState = new QState(customErrorState);
       
   662     childOfErrorState->setObjectName("childOfErrorState");
       
   663 
       
   664     QState *initialState = new QState();
       
   665     initialState->setObjectName("initialState");
       
   666     machine.addState(initialState);
       
   667     machine.setInitialState(initialState);
       
   668 
       
   669     QState *brokenState = new QState();
       
   670     brokenState->setObjectName("brokenState");
       
   671     machine.addState(brokenState);
       
   672 
       
   673     QState *childState = new QState(brokenState);
       
   674     childState->setObjectName("childState");
       
   675 
       
   676     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   677 
       
   678     machine.start();
       
   679     QCoreApplication::processEvents();
       
   680 
       
   681     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   682     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'customErrorState'");
       
   683     QCoreApplication::processEvents();
       
   684 
       
   685     QCOMPARE(machine.isRunning(), false);
       
   686     QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
       
   687     QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'customErrorState'"));
       
   688 }
       
   689 
       
   690 void tst_QStateMachine::errorStateIsRootState()
       
   691 {
       
   692     QStateMachine machine;
       
   693     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::setErrorState: root state cannot be error state");
       
   694     machine.setErrorState(&machine);
       
   695 
       
   696     QState *initialState = new QState();
       
   697     initialState->setObjectName("initialState");
       
   698     machine.addState(initialState);
       
   699     machine.setInitialState(initialState);
       
   700 
       
   701     QState *brokenState = new QState();
       
   702     brokenState->setObjectName("brokenState");
       
   703     machine.addState(brokenState);
       
   704 
       
   705     QState *childState = new QState(brokenState);
       
   706     childState->setObjectName("childState");
       
   707 
       
   708     initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState));
       
   709 
       
   710     machine.start();
       
   711     QCoreApplication::processEvents();
       
   712 
       
   713     machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)));
       
   714     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'brokenState'");
       
   715     QCoreApplication::processEvents();
       
   716 
       
   717     QCOMPARE(machine.isRunning(), false);
       
   718 }
       
   719 
       
   720 void tst_QStateMachine::errorStateEntersParentFirst()
       
   721 {
       
   722     QStateMachine machine;
       
   723 
       
   724     QObject *entryController = new QObject(&machine);
       
   725     entryController->setObjectName("entryController");
       
   726     entryController->setProperty("greatGrandParentEntered", false);
       
   727     entryController->setProperty("grandParentEntered", false);
       
   728     entryController->setProperty("parentEntered", false);
       
   729     entryController->setProperty("errorStateEntered", false);
       
   730 
       
   731     QState *greatGrandParent = new QState();
       
   732     greatGrandParent->setObjectName("greatGrandParent");
       
   733     greatGrandParent->assignProperty(entryController, "greatGrandParentEntered", true);
       
   734     machine.addState(greatGrandParent);
       
   735     machine.setInitialState(greatGrandParent);
       
   736 
       
   737     QState *grandParent = new QState(greatGrandParent);
       
   738     grandParent->setObjectName("grandParent");
       
   739     grandParent->assignProperty(entryController, "grandParentEntered", true);
       
   740 
       
   741     QState *parent = new QState(grandParent);
       
   742     parent->setObjectName("parent");
       
   743     parent->assignProperty(entryController, "parentEntered", true);
       
   744 
       
   745     QState *errorState = new QState(parent);
       
   746     errorState->setObjectName("errorState");
       
   747     errorState->assignProperty(entryController, "errorStateEntered", true);
       
   748     machine.setErrorState(errorState);
       
   749 
       
   750     QState *initialStateOfGreatGrandParent = new QState(greatGrandParent);
       
   751     initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent");
       
   752     greatGrandParent->setInitialState(initialStateOfGreatGrandParent);
       
   753 
       
   754     QState *brokenState = new QState(greatGrandParent);
       
   755     brokenState->setObjectName("brokenState");
       
   756 
       
   757     QState *childState = new QState(brokenState);
       
   758     childState->setObjectName("childState");
       
   759 
       
   760     initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, brokenState));
       
   761 
       
   762     machine.start();
       
   763     QCoreApplication::processEvents();
       
   764 
       
   765     QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true);
       
   766     QCOMPARE(entryController->property("grandParentEntered").toBool(), false);
       
   767     QCOMPARE(entryController->property("parentEntered").toBool(), false);
       
   768     QCOMPARE(entryController->property("errorStateEntered").toBool(), false);
       
   769     QCOMPARE(machine.configuration().count(), 2);
       
   770     QVERIFY(machine.configuration().contains(greatGrandParent));
       
   771     QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent));
       
   772 
       
   773     entryController->setProperty("greatGrandParentEntered", false);
       
   774     entryController->setProperty("grandParentEntered", false);
       
   775     entryController->setProperty("parentEntered", false);
       
   776     entryController->setProperty("errorStateEntered", false);
       
   777 
       
   778     machine.postEvent(new QEvent(QEvent::User));
       
   779     QCoreApplication::processEvents();
       
   780 
       
   781     QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false);
       
   782     QCOMPARE(entryController->property("grandParentEntered").toBool(), true);
       
   783     QCOMPARE(entryController->property("parentEntered").toBool(), true);
       
   784     QCOMPARE(entryController->property("errorStateEntered").toBool(), true);
       
   785     QCOMPARE(machine.configuration().count(), 4);
       
   786     QVERIFY(machine.configuration().contains(greatGrandParent));
       
   787     QVERIFY(machine.configuration().contains(grandParent));
       
   788     QVERIFY(machine.configuration().contains(parent));
       
   789     QVERIFY(machine.configuration().contains(errorState));
       
   790 }
       
   791 
       
   792 void tst_QStateMachine::customErrorStateIsNull()
       
   793 {
       
   794     QStateMachine machine;
       
   795     machine.setErrorState(0);
       
   796 
       
   797     QState *initialState = new QState();
       
   798     machine.addState(initialState);
       
   799     machine.setInitialState(initialState);
       
   800 
       
   801     QState *brokenState = new QState();
       
   802     machine.addState(brokenState);
       
   803 
       
   804     new QState(brokenState);
       
   805     initialState->addTransition(new EventTransition(QEvent::User, brokenState));
       
   806 
       
   807     machine.start();
       
   808     QCoreApplication::processEvents();
       
   809 
       
   810     machine.postEvent(new QEvent(QEvent::User));
       
   811     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state ''");
       
   812     QCoreApplication::processEvents();
       
   813 
       
   814     QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0));
       
   815     QCOMPARE(machine.isRunning(), false);
       
   816 }
       
   817 
       
   818 void tst_QStateMachine::clearError()
       
   819 {
       
   820     QStateMachine machine;
       
   821     machine.setErrorState(new QState(&machine)); // avoid warnings
       
   822 
       
   823     QState *brokenState = new QState(&machine);
       
   824     brokenState->setObjectName("brokenState");
       
   825     machine.setInitialState(brokenState);
       
   826     new QState(brokenState);
       
   827 
       
   828     machine.start();
       
   829     QCoreApplication::processEvents();
       
   830 
       
   831     QCOMPARE(machine.isRunning(), true);
       
   832     QCOMPARE(machine.error(), QStateMachine::NoInitialStateError);
       
   833     QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'"));
       
   834 
       
   835     machine.clearError();
       
   836 
       
   837     QCOMPARE(machine.error(), QStateMachine::NoError);
       
   838     QVERIFY(machine.errorString().isEmpty());
       
   839 }
       
   840 
       
   841 void tst_QStateMachine::historyStateAsInitialState()
       
   842 {
       
   843     QStateMachine machine;
       
   844 
       
   845     QHistoryState *hs = new QHistoryState(&machine);
       
   846     machine.setInitialState(hs);
       
   847 
       
   848     QState *s1 = new QState(&machine);
       
   849     hs->setDefaultState(s1);
       
   850 
       
   851     QState *s2 = new QState(&machine);
       
   852 
       
   853     QHistoryState *s2h = new QHistoryState(s2);
       
   854     s2->setInitialState(s2h);
       
   855 
       
   856     QState *s21 = new QState(s2);
       
   857     s2h->setDefaultState(s21);
       
   858 
       
   859     s1->addTransition(new EventTransition(QEvent::User, s2));
       
   860 
       
   861     machine.start();
       
   862     QCoreApplication::processEvents();
       
   863 
       
   864     QCOMPARE(machine.configuration().size(), 1);
       
   865     QVERIFY(machine.configuration().contains(s1));
       
   866 
       
   867     machine.postEvent(new QEvent(QEvent::User));
       
   868     QCoreApplication::processEvents();
       
   869 
       
   870     QCOMPARE(machine.configuration().size(), 2);
       
   871     QVERIFY(machine.configuration().contains(s2));
       
   872     QVERIFY(machine.configuration().contains(s21));
       
   873 }
       
   874 
       
   875 void tst_QStateMachine::historyStateHasNowhereToGo()
       
   876 {
       
   877     QStateMachine machine;
       
   878 
       
   879     QState *initialState = new QState(&machine);
       
   880     machine.setInitialState(initialState);
       
   881     machine.setErrorState(new QState(&machine)); // avoid warnings
       
   882 
       
   883     QState *brokenState = new QState(&machine);
       
   884     brokenState->setObjectName("brokenState");
       
   885     brokenState->setInitialState(new QState(brokenState));
       
   886 
       
   887     QHistoryState *historyState = new QHistoryState(brokenState);
       
   888     historyState->setObjectName("historyState");
       
   889     initialState->addTransition(new EventTransition(QEvent::User, historyState));
       
   890 
       
   891     machine.start();
       
   892     QCoreApplication::processEvents();
       
   893 
       
   894     machine.postEvent(new QEvent(QEvent::User));
       
   895     QCoreApplication::processEvents();
       
   896 
       
   897     QCOMPARE(machine.isRunning(), true);
       
   898     QCOMPARE(machine.configuration().count(), 1);
       
   899     QVERIFY(machine.configuration().contains(machine.errorState()));
       
   900     QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryStateError);
       
   901     QCOMPARE(machine.errorString(), QString::fromLatin1("Missing default state in history state 'historyState'"));
       
   902 }
       
   903 
       
   904 void tst_QStateMachine::brokenStateIsNeverEntered()
       
   905 {
       
   906     QStateMachine machine;
       
   907 
       
   908     QObject *entryController = new QObject(&machine);
       
   909     entryController->setProperty("brokenStateEntered", false);
       
   910     entryController->setProperty("childStateEntered", false);
       
   911     entryController->setProperty("errorStateEntered", false);
       
   912 
       
   913     QState *initialState = new QState(&machine);
       
   914     machine.setInitialState(initialState);
       
   915 
       
   916     QState *errorState = new QState(&machine);
       
   917     errorState->assignProperty(entryController, "errorStateEntered", true);
       
   918     machine.setErrorState(errorState);
       
   919 
       
   920     QState *brokenState = new QState(&machine);
       
   921     brokenState->assignProperty(entryController, "brokenStateEntered", true);
       
   922     brokenState->setObjectName("brokenState");
       
   923 
       
   924     QState *childState = new QState(brokenState);
       
   925     childState->assignProperty(entryController, "childStateEntered", true);
       
   926 
       
   927     initialState->addTransition(new EventTransition(QEvent::User, brokenState));
       
   928 
       
   929     machine.start();
       
   930     QCoreApplication::processEvents();
       
   931 
       
   932     machine.postEvent(new QEvent(QEvent::User));
       
   933     QCoreApplication::processEvents();
       
   934 
       
   935     QCOMPARE(entryController->property("errorStateEntered").toBool(), true);
       
   936     QCOMPARE(entryController->property("brokenStateEntered").toBool(), false);
       
   937     QCOMPARE(entryController->property("childStateEntered").toBool(), false);
       
   938 }
       
   939 
       
   940 void tst_QStateMachine::transitionToStateNotInGraph()
       
   941 {
       
   942     QStateMachine machine;
       
   943 
       
   944     QState *initialState = new QState(&machine);
       
   945     initialState->setObjectName("initialState");
       
   946     machine.setInitialState(initialState);
       
   947 
       
   948     QState independentState;
       
   949     independentState.setObjectName("independentState");
       
   950     initialState->addTransition(&independentState);
       
   951 
       
   952     machine.start();
       
   953     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initialState'");
       
   954     QCoreApplication::processEvents();
       
   955 
       
   956     QCOMPARE(machine.isRunning(), false);
       
   957 }
       
   958 
       
   959 void tst_QStateMachine::customErrorStateNotInGraph()
       
   960 {
       
   961     QStateMachine machine;
       
   962 
       
   963     QState errorState;
       
   964     errorState.setObjectName("errorState");
       
   965     QTest::ignoreMessage(QtWarningMsg, "QState::setErrorState: error state cannot belong to a different state machine");
       
   966     machine.setErrorState(&errorState);
       
   967     QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0));
       
   968 
       
   969     QState *initialBrokenState = new QState(&machine);
       
   970     initialBrokenState->setObjectName("initialBrokenState");
       
   971     machine.setInitialState(initialBrokenState);
       
   972     new QState(initialBrokenState);
       
   973 
       
   974     machine.start();
       
   975     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'initialBrokenState'");
       
   976     QCoreApplication::processEvents();
       
   977 
       
   978     QCOMPARE(machine.isRunning(), false);
       
   979 }
       
   980 
       
   981 void tst_QStateMachine::restoreProperties()
       
   982 {
       
   983     QStateMachine machine;
       
   984     QCOMPARE(machine.globalRestorePolicy(), QStateMachine::DoNotRestoreProperties);
       
   985     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
   986 
       
   987     QObject *object = new QObject(&machine);
       
   988     object->setProperty("a", 1);
       
   989     object->setProperty("b", 2);
       
   990 
       
   991     QState *S1 = new QState();
       
   992     S1->setObjectName("S1");
       
   993     S1->assignProperty(object, "a", 3);
       
   994     machine.addState(S1);
       
   995 
       
   996     QState *S2 = new QState();
       
   997     S2->setObjectName("S2");
       
   998     S2->assignProperty(object, "b", 5);
       
   999     machine.addState(S2);
       
  1000 
       
  1001     QState *S3 = new QState();
       
  1002     S3->setObjectName("S3");
       
  1003     machine.addState(S3);
       
  1004 
       
  1005     QFinalState *S4 = new QFinalState();
       
  1006     machine.addState(S4);
       
  1007 
       
  1008     S1->addTransition(new EventTransition(QEvent::User, S2));
       
  1009     S2->addTransition(new EventTransition(QEvent::User, S3));
       
  1010     S3->addTransition(S4);
       
  1011 
       
  1012     machine.setInitialState(S1);
       
  1013     machine.start();
       
  1014     QCoreApplication::processEvents();
       
  1015 
       
  1016     QCOMPARE(object->property("a").toInt(), 3);
       
  1017     QCOMPARE(object->property("b").toInt(), 2);
       
  1018 
       
  1019     machine.postEvent(new QEvent(QEvent::User));
       
  1020     QCoreApplication::processEvents();
       
  1021 
       
  1022     QCOMPARE(object->property("a").toInt(), 1);
       
  1023     QCOMPARE(object->property("b").toInt(), 5);
       
  1024 
       
  1025     machine.postEvent(new QEvent(QEvent::User));
       
  1026     QCoreApplication::processEvents();
       
  1027 
       
  1028     QCOMPARE(object->property("a").toInt(), 1);
       
  1029     QCOMPARE(object->property("b").toInt(), 2);
       
  1030 }
       
  1031 
       
  1032 void tst_QStateMachine::rootState()
       
  1033 {
       
  1034     QStateMachine machine;
       
  1035     QCOMPARE(qobject_cast<QState*>(machine.parentState()), (QState*)0);
       
  1036     QCOMPARE(machine.machine(), (QStateMachine*)0);
       
  1037 
       
  1038     QState *s1 = new QState(&machine);
       
  1039     QCOMPARE(s1->parentState(), static_cast<QState*>(&machine));
       
  1040 
       
  1041     QState *s2 = new QState();
       
  1042     s2->setParent(&machine);
       
  1043     QCOMPARE(s2->parentState(), static_cast<QState*>(&machine));
       
  1044 }
       
  1045 
       
  1046 void tst_QStateMachine::addAndRemoveState()
       
  1047 {
       
  1048 #ifdef QT_BUILD_INTERNAL
       
  1049     QStateMachine machine;
       
  1050     QStatePrivate *root_d = QStatePrivate::get(&machine);
       
  1051     QCOMPARE(root_d->childStates().size(), 0);
       
  1052 
       
  1053     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: cannot add null state");
       
  1054     machine.addState(0);
       
  1055 
       
  1056     QState *s1 = new QState();
       
  1057     QCOMPARE(s1->parentState(), (QState*)0);
       
  1058     QCOMPARE(s1->machine(), (QStateMachine*)0);
       
  1059     machine.addState(s1);
       
  1060     QCOMPARE(s1->machine(), static_cast<QStateMachine*>(&machine));
       
  1061     QCOMPARE(s1->parentState(), static_cast<QState*>(&machine));
       
  1062     QCOMPARE(root_d->childStates().size(), 1);
       
  1063     QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s1);
       
  1064 
       
  1065     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine");
       
  1066     machine.addState(s1);
       
  1067 
       
  1068     QState *s2 = new QState();
       
  1069     QCOMPARE(s2->parentState(), (QState*)0);
       
  1070     machine.addState(s2);
       
  1071     QCOMPARE(s2->parentState(), static_cast<QState*>(&machine));
       
  1072     QCOMPARE(root_d->childStates().size(), 2);
       
  1073     QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s1);
       
  1074     QCOMPARE(root_d->childStates().at(1), (QAbstractState*)s2);
       
  1075 
       
  1076     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine");
       
  1077     machine.addState(s2);
       
  1078 
       
  1079     machine.removeState(s1);
       
  1080     QCOMPARE(s1->parentState(), (QState*)0);
       
  1081     QCOMPARE(root_d->childStates().size(), 1);
       
  1082     QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s2);
       
  1083 
       
  1084     machine.removeState(s2);
       
  1085     QCOMPARE(s2->parentState(), (QState*)0);
       
  1086     QCOMPARE(root_d->childStates().size(), 0);
       
  1087 
       
  1088     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::removeState: cannot remove null state");
       
  1089     machine.removeState(0);
       
  1090 
       
  1091     {
       
  1092         QStateMachine machine2;
       
  1093         {
       
  1094             QString warning;
       
  1095             warning.sprintf("QStateMachine::removeState: state %p's machine (%p) is different from this machine (%p)",
       
  1096                             &machine2, (void*)0, &machine);
       
  1097             QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
       
  1098             machine.removeState(&machine2);
       
  1099         }
       
  1100         // ### check this behavior
       
  1101         machine.addState(&machine2);
       
  1102         QCOMPARE(machine2.parent(), (QObject*)&machine);
       
  1103     }
       
  1104 
       
  1105     delete s1;
       
  1106     delete s2;
       
  1107     // ### how to deal with this?
       
  1108     // machine.removeState(machine.errorState());
       
  1109 #endif
       
  1110 }
       
  1111 
       
  1112 void tst_QStateMachine::stateEntryAndExit()
       
  1113 {
       
  1114     // Two top-level states
       
  1115     {
       
  1116         QStateMachine machine;
       
  1117 
       
  1118         TestState *s1 = new TestState(&machine);
       
  1119         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state");
       
  1120         s1->addTransition((QAbstractState*)0);
       
  1121         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add null transition");
       
  1122         s1->addTransition((QAbstractTransition*)0);
       
  1123         QTest::ignoreMessage(QtWarningMsg, "QState::removeTransition: cannot remove null transition");
       
  1124         s1->removeTransition((QAbstractTransition*)0);
       
  1125 
       
  1126         TestState *s2 = new TestState(&machine);
       
  1127         QFinalState *s3 = new QFinalState(&machine);
       
  1128 
       
  1129         TestTransition *t = new TestTransition(s2);
       
  1130         QCOMPARE(t->machine(), (QStateMachine*)0);
       
  1131         QCOMPARE(t->sourceState(), (QState*)0);
       
  1132         QCOMPARE(t->targetState(), (QAbstractState*)s2);
       
  1133         QCOMPARE(t->targetStates().size(), 1);
       
  1134         QCOMPARE(t->targetStates().at(0), (QAbstractState*)s2);
       
  1135         t->setTargetState(0);
       
  1136         QCOMPARE(t->targetState(), (QAbstractState*)0);
       
  1137         QVERIFY(t->targetStates().isEmpty());
       
  1138         t->setTargetState(s2);
       
  1139         QCOMPARE(t->targetState(), (QAbstractState*)s2);
       
  1140         QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::setTargetStates: target state(s) cannot be null");
       
  1141         t->setTargetStates(QList<QAbstractState*>() << 0);
       
  1142         QCOMPARE(t->targetState(), (QAbstractState*)s2);
       
  1143         t->setTargetStates(QList<QAbstractState*>() << s2);
       
  1144         QCOMPARE(t->targetState(), (QAbstractState*)s2);
       
  1145         QCOMPARE(t->targetStates().size(), 1);
       
  1146         QCOMPARE(t->targetStates().at(0), (QAbstractState*)s2);
       
  1147         QCOMPARE(s1->addTransition(t), (QAbstractTransition*)t);
       
  1148         QCOMPARE(t->sourceState(), (QState*)s1);
       
  1149         QCOMPARE(t->machine(), &machine);
       
  1150 
       
  1151         {
       
  1152             QAbstractTransition *trans = s2->addTransition(s3);
       
  1153             QVERIFY(trans != 0);
       
  1154             QCOMPARE(trans->sourceState(), (QState*)s2);
       
  1155             QCOMPARE(trans->targetState(), (QAbstractState*)s3);
       
  1156             {
       
  1157                 QString warning;
       
  1158                 warning.sprintf("QState::removeTransition: transition %p's source state (%p) is different from this state (%p)", trans, s2, s1);
       
  1159                 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
       
  1160                 s1->removeTransition(trans);
       
  1161             }
       
  1162             s2->removeTransition(trans);
       
  1163             QCOMPARE(trans->sourceState(), (QState*)0);
       
  1164             QCOMPARE(trans->targetState(), (QAbstractState*)s3);
       
  1165             QCOMPARE(s2->addTransition(trans), trans);
       
  1166             QCOMPARE(trans->sourceState(), (QState*)s2);
       
  1167         }
       
  1168 
       
  1169         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  1170         QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
       
  1171         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1172         machine.setInitialState(s1);
       
  1173         QCOMPARE(machine.initialState(), (QAbstractState*)s1);
       
  1174         {
       
  1175             QString warning;
       
  1176             warning.sprintf("QState::setInitialState: state %p is not a child of this state (%p)", &machine, &machine);
       
  1177             QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
       
  1178             machine.setInitialState(&machine);
       
  1179             QCOMPARE(machine.initialState(), (QAbstractState*)s1);
       
  1180         }
       
  1181         QVERIFY(machine.configuration().isEmpty());
       
  1182         globalTick = 0;
       
  1183         QVERIFY(!machine.isRunning());
       
  1184         QSignalSpy s1EnteredSpy(s1, SIGNAL(entered()));
       
  1185         QSignalSpy s1ExitedSpy(s1, SIGNAL(exited()));
       
  1186         QSignalSpy tTriggeredSpy(t, SIGNAL(triggered()));
       
  1187         QSignalSpy s2EnteredSpy(s2, SIGNAL(entered()));
       
  1188         QSignalSpy s2ExitedSpy(s2, SIGNAL(exited()));
       
  1189         machine.start();
       
  1190 
       
  1191         QTRY_COMPARE(startedSpy.count(), 1);
       
  1192         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1193         QTRY_COMPARE(stoppedSpy.count(), 0);
       
  1194         QCOMPARE(machine.configuration().count(), 1);
       
  1195         QVERIFY(machine.configuration().contains(s3));
       
  1196 
       
  1197         // s1 is entered
       
  1198         QCOMPARE(s1->events.count(), 2);
       
  1199         QCOMPARE(s1->events.at(0).first, 0);
       
  1200         QCOMPARE(s1->events.at(0).second, TestState::Entry);
       
  1201         // s1 is exited
       
  1202         QCOMPARE(s1->events.at(1).first, 1);
       
  1203         QCOMPARE(s1->events.at(1).second, TestState::Exit);
       
  1204         // t is triggered
       
  1205         QCOMPARE(t->triggers.count(), 1);
       
  1206         QCOMPARE(t->triggers.at(0), 2);
       
  1207         // s2 is entered
       
  1208         QCOMPARE(s2->events.count(), 2);
       
  1209         QCOMPARE(s2->events.at(0).first, 3);
       
  1210         QCOMPARE(s2->events.at(0).second, TestState::Entry);
       
  1211         // s2 is exited
       
  1212         QCOMPARE(s2->events.at(1).first, 4);
       
  1213         QCOMPARE(s2->events.at(1).second, TestState::Exit);
       
  1214 
       
  1215         QCOMPARE(s1EnteredSpy.count(), 1);
       
  1216         QCOMPARE(s1ExitedSpy.count(), 1);
       
  1217         QCOMPARE(tTriggeredSpy.count(), 1);
       
  1218         QCOMPARE(s2EnteredSpy.count(), 1);
       
  1219         QCOMPARE(s2ExitedSpy.count(), 1);
       
  1220     }
       
  1221     // Two top-level states, one has two child states
       
  1222     {
       
  1223         QStateMachine machine;
       
  1224 
       
  1225         TestState *s1 = new TestState(&machine);
       
  1226         TestState *s11 = new TestState(s1);
       
  1227         TestState *s12 = new TestState(s1);
       
  1228         TestState *s2 = new TestState(&machine);
       
  1229         QFinalState *s3 = new QFinalState(&machine);
       
  1230         s1->setInitialState(s11);
       
  1231         TestTransition *t1 = new TestTransition(s12);
       
  1232         s11->addTransition(t1);
       
  1233         TestTransition *t2 = new TestTransition(s2);
       
  1234         s12->addTransition(t2);
       
  1235         s2->addTransition(s3);
       
  1236 
       
  1237         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  1238         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1239         machine.setInitialState(s1);
       
  1240         globalTick = 0;
       
  1241         machine.start();
       
  1242 
       
  1243         QTRY_COMPARE(startedSpy.count(), 1);
       
  1244         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1245         QCOMPARE(machine.configuration().count(), 1);
       
  1246         QVERIFY(machine.configuration().contains(s3));
       
  1247 
       
  1248         // s1 is entered
       
  1249         QCOMPARE(s1->events.count(), 2);
       
  1250         QCOMPARE(s1->events.at(0).first, 0);
       
  1251         QCOMPARE(s1->events.at(0).second, TestState::Entry);
       
  1252         // s11 is entered
       
  1253         QCOMPARE(s11->events.count(), 2);
       
  1254         QCOMPARE(s11->events.at(0).first, 1);
       
  1255         QCOMPARE(s11->events.at(0).second, TestState::Entry);
       
  1256         // s11 is exited
       
  1257         QCOMPARE(s11->events.at(1).first, 2);
       
  1258         QCOMPARE(s11->events.at(1).second, TestState::Exit);
       
  1259         // t1 is triggered
       
  1260         QCOMPARE(t1->triggers.count(), 1);
       
  1261         QCOMPARE(t1->triggers.at(0), 3);
       
  1262         // s12 is entered
       
  1263         QCOMPARE(s12->events.count(), 2);
       
  1264         QCOMPARE(s12->events.at(0).first, 4);
       
  1265         QCOMPARE(s12->events.at(0).second, TestState::Entry);
       
  1266         // s12 is exited
       
  1267         QCOMPARE(s12->events.at(1).first, 5);
       
  1268         QCOMPARE(s12->events.at(1).second, TestState::Exit);
       
  1269         // s1 is exited
       
  1270         QCOMPARE(s1->events.at(1).first, 6);
       
  1271         QCOMPARE(s1->events.at(1).second, TestState::Exit);
       
  1272         // t2 is triggered
       
  1273         QCOMPARE(t2->triggers.count(), 1);
       
  1274         QCOMPARE(t2->triggers.at(0), 7);
       
  1275         // s2 is entered
       
  1276         QCOMPARE(s2->events.count(), 2);
       
  1277         QCOMPARE(s2->events.at(0).first, 8);
       
  1278         QCOMPARE(s2->events.at(0).second, TestState::Entry);
       
  1279         // s2 is exited
       
  1280         QCOMPARE(s2->events.at(1).first, 9);
       
  1281         QCOMPARE(s2->events.at(1).second, TestState::Exit);
       
  1282     }
       
  1283 }
       
  1284 
       
  1285 void tst_QStateMachine::assignProperty()
       
  1286 {
       
  1287     QStateMachine machine;
       
  1288     QState *s1 = new QState(&machine);
       
  1289 
       
  1290     QTest::ignoreMessage(QtWarningMsg, "QState::assignProperty: cannot assign property 'foo' of null object");
       
  1291     s1->assignProperty(0, "foo", QVariant());
       
  1292 
       
  1293     s1->assignProperty(s1, "objectName", "s1");
       
  1294     QFinalState *s2 = new QFinalState(&machine);
       
  1295     s1->addTransition(s2);
       
  1296     machine.setInitialState(s1);
       
  1297     machine.start();
       
  1298     QTRY_COMPARE(s1->objectName(), QString::fromLatin1("s1"));
       
  1299 
       
  1300     s1->assignProperty(s1, "objectName", "foo");
       
  1301     machine.start();
       
  1302     QTRY_COMPARE(s1->objectName(), QString::fromLatin1("foo"));
       
  1303 
       
  1304     s1->assignProperty(s1, "noSuchProperty", 123);
       
  1305     machine.start();
       
  1306     QTRY_COMPARE(s1->dynamicPropertyNames().size(), 1);
       
  1307     QCOMPARE(s1->dynamicPropertyNames().at(0), QByteArray("noSuchProperty"));
       
  1308     QCOMPARE(s1->objectName(), QString::fromLatin1("foo"));
       
  1309 
       
  1310     {
       
  1311         QSignalSpy polishedSpy(s1, SIGNAL(polished()));
       
  1312         machine.start();
       
  1313         QTRY_COMPARE(polishedSpy.count(), 1);
       
  1314     }
       
  1315 
       
  1316     // nested states
       
  1317     {
       
  1318         QState *s11 = new QState(s1);
       
  1319         QString str = QString::fromLatin1("set by nested state");
       
  1320         s11->assignProperty(s11, "objectName", str);
       
  1321         s1->setInitialState(s11);
       
  1322         machine.start();
       
  1323         QTRY_COMPARE(s11->objectName(), str);
       
  1324     }
       
  1325 }
       
  1326 
       
  1327 void tst_QStateMachine::assignPropertyWithAnimation()
       
  1328 {
       
  1329     // Single animation
       
  1330     {
       
  1331         QStateMachine machine;
       
  1332         QVERIFY(machine.animationsEnabled());
       
  1333         machine.setAnimationsEnabled(false);
       
  1334         QVERIFY(!machine.animationsEnabled());
       
  1335         machine.setAnimationsEnabled(true);
       
  1336         QVERIFY(machine.animationsEnabled());
       
  1337         QObject obj;
       
  1338         obj.setProperty("foo", 321);
       
  1339         obj.setProperty("bar", 654);
       
  1340         QState *s1 = new QState(&machine);
       
  1341         s1->assignProperty(&obj, "foo", 123);
       
  1342         QState *s2 = new QState(&machine);
       
  1343         s2->assignProperty(&obj, "foo", 456);
       
  1344         s2->assignProperty(&obj, "bar", 789);
       
  1345         QAbstractTransition *trans = s1->addTransition(s2);
       
  1346         QVERIFY(trans->animations().isEmpty());
       
  1347         QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::addAnimation: cannot add null animation");
       
  1348         trans->addAnimation(0);
       
  1349         QPropertyAnimation anim(&obj, "foo");
       
  1350         anim.setDuration(250);
       
  1351         trans->addAnimation(&anim);
       
  1352         QCOMPARE(trans->animations().size(), 1);
       
  1353         QCOMPARE(trans->animations().at(0), (QAbstractAnimation*)&anim);
       
  1354         QCOMPARE(anim.parent(), (QObject*)0);
       
  1355         QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::removeAnimation: cannot remove null animation");
       
  1356         trans->removeAnimation(0);
       
  1357         trans->removeAnimation(&anim);
       
  1358         QVERIFY(trans->animations().isEmpty());
       
  1359         trans->addAnimation(&anim);
       
  1360         QCOMPARE(trans->animations().size(), 1);
       
  1361         QCOMPARE(trans->animations().at(0), (QAbstractAnimation*)&anim);
       
  1362         QFinalState *s3 = new QFinalState(&machine);
       
  1363         s2->addTransition(s2, SIGNAL(polished()), s3);
       
  1364 
       
  1365         machine.setInitialState(s1);
       
  1366         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1367         machine.start();
       
  1368         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1369         QCOMPARE(obj.property("foo").toInt(), 456);
       
  1370         QCOMPARE(obj.property("bar").toInt(), 789);
       
  1371     }
       
  1372     // Two animations
       
  1373     {
       
  1374         QStateMachine machine;
       
  1375         QObject obj;
       
  1376         obj.setProperty("foo", 321);
       
  1377         obj.setProperty("bar", 654);
       
  1378         QState *s1 = new QState(&machine);
       
  1379         s1->assignProperty(&obj, "foo", 123);
       
  1380         QState *s2 = new QState(&machine);
       
  1381         s2->assignProperty(&obj, "foo", 456);
       
  1382         s2->assignProperty(&obj, "bar", 789);
       
  1383         QAbstractTransition *trans = s1->addTransition(s2);
       
  1384         QPropertyAnimation anim(&obj, "foo");
       
  1385         anim.setDuration(150);
       
  1386         trans->addAnimation(&anim);
       
  1387         QPropertyAnimation anim2(&obj, "bar");
       
  1388         anim2.setDuration(150);
       
  1389         trans->addAnimation(&anim2);
       
  1390         QFinalState *s3 = new QFinalState(&machine);
       
  1391         s2->addTransition(s2, SIGNAL(polished()), s3);
       
  1392 
       
  1393         machine.setInitialState(s1);
       
  1394         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1395         machine.start();
       
  1396         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1397         QCOMPARE(obj.property("foo").toInt(), 456);
       
  1398         QCOMPARE(obj.property("bar").toInt(), 789);
       
  1399     }
       
  1400     // Animation group
       
  1401     {
       
  1402         QStateMachine machine;
       
  1403         QObject obj;
       
  1404         obj.setProperty("foo", 321);
       
  1405         obj.setProperty("bar", 654);
       
  1406         QState *s1 = new QState(&machine);
       
  1407         s1->assignProperty(&obj, "foo", 123);
       
  1408         s1->assignProperty(&obj, "bar", 321);
       
  1409         QState *s2 = new QState(&machine);
       
  1410         s2->assignProperty(&obj, "foo", 456);
       
  1411         s2->assignProperty(&obj, "bar", 654);
       
  1412         s2->assignProperty(&obj, "baz", 789);
       
  1413         QAbstractTransition *trans = s1->addTransition(s2);
       
  1414         QSequentialAnimationGroup group;
       
  1415         group.addAnimation(new QPropertyAnimation(&obj, "foo"));
       
  1416         group.addAnimation(new QPropertyAnimation(&obj, "bar"));
       
  1417         trans->addAnimation(&group);
       
  1418         QFinalState *s3 = new QFinalState(&machine);
       
  1419         s2->addTransition(s2, SIGNAL(polished()), s3);
       
  1420 
       
  1421         machine.setInitialState(s1);
       
  1422         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1423         machine.start();
       
  1424         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1425         QCOMPARE(obj.property("foo").toInt(), 456);
       
  1426         QCOMPARE(obj.property("bar").toInt(), 654);
       
  1427         QCOMPARE(obj.property("baz").toInt(), 789);
       
  1428     }
       
  1429     // Nested states
       
  1430     {
       
  1431         QStateMachine machine;
       
  1432         QObject obj;
       
  1433         obj.setProperty("foo", 321);
       
  1434         obj.setProperty("bar", 654);
       
  1435         QState *s1 = new QState(&machine);
       
  1436         QCOMPARE(s1->childMode(), QState::ExclusiveStates);
       
  1437         s1->setChildMode(QState::ParallelStates);
       
  1438         QCOMPARE(s1->childMode(), QState::ParallelStates);
       
  1439         s1->setChildMode(QState::ExclusiveStates);
       
  1440         QCOMPARE(s1->childMode(), QState::ExclusiveStates);
       
  1441         QCOMPARE(s1->initialState(), (QAbstractState*)0);
       
  1442         s1->setObjectName("s1");
       
  1443         s1->assignProperty(&obj, "foo", 123);
       
  1444         s1->assignProperty(&obj, "bar", 456);
       
  1445         QState *s2 = new QState(&machine);
       
  1446         s2->setObjectName("s2");
       
  1447         s2->assignProperty(&obj, "foo", 321);
       
  1448         QState *s21 = new QState(s2);
       
  1449         s21->setObjectName("s21");
       
  1450         s21->assignProperty(&obj, "bar", 654);
       
  1451         QState *s22 = new QState(s2);
       
  1452         s22->setObjectName("s22");
       
  1453         s22->assignProperty(&obj, "bar", 789);
       
  1454         s2->setInitialState(s21);
       
  1455         QCOMPARE(s2->initialState(), (QAbstractState*)s21);
       
  1456 
       
  1457         QAbstractTransition *trans = s1->addTransition(s2);
       
  1458         QPropertyAnimation anim(&obj, "foo");
       
  1459         anim.setDuration(500);
       
  1460         trans->addAnimation(&anim);
       
  1461         QPropertyAnimation anim2(&obj, "bar");
       
  1462         anim2.setDuration(250);
       
  1463         trans->addAnimation(&anim2);
       
  1464 
       
  1465         s21->addTransition(s21, SIGNAL(polished()), s22);
       
  1466 
       
  1467         QFinalState *s3 = new QFinalState(&machine);
       
  1468         s22->addTransition(s2, SIGNAL(polished()), s3);
       
  1469 
       
  1470         machine.setInitialState(s1);
       
  1471         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1472         machine.start();
       
  1473         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1474         QCOMPARE(obj.property("foo").toInt(), 321);
       
  1475         QCOMPARE(obj.property("bar").toInt(), 789);
       
  1476     }
       
  1477     // Aborted animation
       
  1478     {
       
  1479         QStateMachine machine;
       
  1480         SignalEmitter emitter;
       
  1481         QObject obj;
       
  1482         obj.setProperty("foo", 321);
       
  1483         obj.setProperty("bar", 654);
       
  1484         QState *group = new QState(&machine);
       
  1485         QState *s1 = new QState(group);
       
  1486         group->setInitialState(s1);
       
  1487         s1->assignProperty(&obj, "foo", 123);
       
  1488         QState *s2 = new QState(group);
       
  1489         s2->assignProperty(&obj, "foo", 456);
       
  1490         s2->assignProperty(&obj, "bar", 789);
       
  1491         QAbstractTransition *trans = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s2);
       
  1492         QPropertyAnimation anim(&obj, "foo");
       
  1493         anim.setDuration(8000);
       
  1494         trans->addAnimation(&anim);
       
  1495         QPropertyAnimation anim2(&obj, "bar");
       
  1496         anim2.setDuration(8000);
       
  1497         trans->addAnimation(&anim2);
       
  1498         QState *s3 = new QState(group);
       
  1499         s3->assignProperty(&obj, "foo", 911);
       
  1500         s2->addTransition(&emitter, SIGNAL(signalWithNoArg()), s3);
       
  1501 
       
  1502         machine.setInitialState(group);
       
  1503         machine.start();
       
  1504         QTRY_COMPARE(machine.configuration().contains(s1), true);
       
  1505         QSignalSpy polishedSpy(s2, SIGNAL(polished()));
       
  1506         emitter.emitSignalWithNoArg();
       
  1507         QTRY_COMPARE(machine.configuration().contains(s2), true);
       
  1508         QVERIFY(polishedSpy.isEmpty());
       
  1509         emitter.emitSignalWithNoArg(); // will cause animations from s1-->s2 to abort
       
  1510         QTRY_COMPARE(machine.configuration().contains(s3), true);
       
  1511         QVERIFY(polishedSpy.isEmpty());
       
  1512         QCOMPARE(obj.property("foo").toInt(), 911);
       
  1513         QCOMPARE(obj.property("bar").toInt(), 789);
       
  1514     }
       
  1515 }
       
  1516 
       
  1517 struct StringEvent : public QEvent
       
  1518 {
       
  1519 public:
       
  1520     StringEvent(const QString &val)
       
  1521         : QEvent(QEvent::Type(QEvent::User+2)),
       
  1522           value(val) {}
       
  1523 
       
  1524     QString value;
       
  1525 };
       
  1526 
       
  1527 class StringTransition : public QAbstractTransition
       
  1528 {
       
  1529 public:
       
  1530     StringTransition(const QString &value, QAbstractState *target)
       
  1531         : QAbstractTransition(), m_value(value)
       
  1532     { setTargetState(target); }
       
  1533 
       
  1534 protected:
       
  1535     virtual bool eventTest(QEvent *e)
       
  1536     {
       
  1537         if (e->type() != QEvent::Type(QEvent::User+2))
       
  1538             return false;
       
  1539         StringEvent *se = static_cast<StringEvent*>(e);
       
  1540         return (m_value == se->value) && (!m_cond.isValid() || (m_cond.indexIn(m_value) != -1));
       
  1541     }
       
  1542     virtual void onTransition(QEvent *) {}
       
  1543 
       
  1544 private:
       
  1545     QString m_value;
       
  1546     QRegExp m_cond;
       
  1547 };
       
  1548 
       
  1549 class StringEventPoster : public QState
       
  1550 {
       
  1551 public:
       
  1552     StringEventPoster(const QString &value, QState *parent = 0)
       
  1553         : QState(parent), m_value(value), m_delay(-1) {}
       
  1554 
       
  1555     void setString(const QString &value)
       
  1556         { m_value = value; }
       
  1557     void setDelay(int delay)
       
  1558         { m_delay = delay; }
       
  1559 
       
  1560 protected:
       
  1561     virtual void onEntry(QEvent *)
       
  1562     {
       
  1563         if (m_delay == -1)
       
  1564             machine()->postEvent(new StringEvent(m_value));
       
  1565         else
       
  1566             machine()->postDelayedEvent(new StringEvent(m_value), m_delay);
       
  1567     }
       
  1568     virtual void onExit(QEvent *) {}
       
  1569 
       
  1570 private:
       
  1571     QString m_value;
       
  1572     int m_delay;
       
  1573 };
       
  1574 
       
  1575 void tst_QStateMachine::postEvent()
       
  1576 {
       
  1577     for (int x = 0; x < 2; ++x) {
       
  1578         QStateMachine machine;
       
  1579         {
       
  1580             QEvent e(QEvent::None);
       
  1581             QTest::ignoreMessage(QtWarningMsg, "QStateMachine::postEvent: cannot post event when the state machine is not running");
       
  1582             machine.postEvent(&e);
       
  1583         }
       
  1584         StringEventPoster *s1 = new StringEventPoster("a");
       
  1585         if (x == 1)
       
  1586             s1->setDelay(100);
       
  1587         QFinalState *s2 = new QFinalState;
       
  1588         s1->addTransition(new StringTransition("a", s2));
       
  1589         machine.addState(s1);
       
  1590         machine.addState(s2);
       
  1591         machine.setInitialState(s1);
       
  1592         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1593         machine.start();
       
  1594         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1595         QCOMPARE(machine.configuration().size(), 1);
       
  1596         QVERIFY(machine.configuration().contains(s2));
       
  1597 
       
  1598         s1->setString("b");
       
  1599         QFinalState *s3 = new QFinalState();
       
  1600         machine.addState(s3);
       
  1601         s1->addTransition(new StringTransition("b", s3));
       
  1602         finishedSpy.clear();
       
  1603         machine.start();
       
  1604         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1605         QCOMPARE(machine.configuration().size(), 1);
       
  1606         QVERIFY(machine.configuration().contains(s3));
       
  1607     }
       
  1608 }
       
  1609 
       
  1610 void tst_QStateMachine::cancelDelayedEvent()
       
  1611 {
       
  1612     QStateMachine machine;
       
  1613     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::cancelDelayedEvent: the machine is not running");
       
  1614     QVERIFY(!machine.cancelDelayedEvent(-1));
       
  1615 
       
  1616     QState *s1 = new QState(&machine);
       
  1617     QFinalState *s2 = new QFinalState(&machine);
       
  1618     s1->addTransition(new StringTransition("a", s2));
       
  1619     machine.setInitialState(s1);
       
  1620 
       
  1621     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  1622     machine.start();
       
  1623     QTRY_COMPARE(startedSpy.count(), 1);
       
  1624     QCOMPARE(machine.configuration().size(), 1);
       
  1625     QVERIFY(machine.configuration().contains(s1));
       
  1626 
       
  1627     int id1 = machine.postDelayedEvent(new StringEvent("c"), 50000);
       
  1628     QVERIFY(id1 != -1);
       
  1629     int id2 = machine.postDelayedEvent(new StringEvent("b"), 25000);
       
  1630     QVERIFY(id2 != -1);
       
  1631     QVERIFY(id2 != id1);
       
  1632     int id3 = machine.postDelayedEvent(new StringEvent("a"), 100);
       
  1633     QVERIFY(id3 != -1);
       
  1634     QVERIFY(id3 != id2);
       
  1635     QVERIFY(machine.cancelDelayedEvent(id1));
       
  1636     QVERIFY(!machine.cancelDelayedEvent(id1));
       
  1637     QVERIFY(machine.cancelDelayedEvent(id2));
       
  1638     QVERIFY(!machine.cancelDelayedEvent(id2));
       
  1639 
       
  1640     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1641     QTRY_COMPARE(finishedSpy.count(), 1);
       
  1642     QCOMPARE(machine.configuration().size(), 1);
       
  1643     QVERIFY(machine.configuration().contains(s2));
       
  1644 }
       
  1645 
       
  1646 void tst_QStateMachine::postDelayedEventAndStop()
       
  1647 {
       
  1648     QStateMachine machine;
       
  1649     QState *s1 = new QState(&machine);
       
  1650     QFinalState *s2 = new QFinalState(&machine);
       
  1651     s1->addTransition(new StringTransition("a", s2));
       
  1652     machine.setInitialState(s1);
       
  1653 
       
  1654     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  1655     machine.start();
       
  1656     QTRY_COMPARE(startedSpy.count(), 1);
       
  1657     QCOMPARE(machine.configuration().size(), 1);
       
  1658     QVERIFY(machine.configuration().contains(s1));
       
  1659 
       
  1660     int id1 = machine.postDelayedEvent(new StringEvent("a"), 0);
       
  1661     QVERIFY(id1 != -1);
       
  1662     QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
       
  1663     machine.stop();
       
  1664     QTRY_COMPARE(stoppedSpy.count(), 1);
       
  1665     QCOMPARE(machine.configuration().size(), 1);
       
  1666     QVERIFY(machine.configuration().contains(s1));
       
  1667 
       
  1668     machine.start();
       
  1669     QTRY_COMPARE(startedSpy.count(), 2);
       
  1670     QCOMPARE(machine.configuration().size(), 1);
       
  1671     QVERIFY(machine.configuration().contains(s1));
       
  1672 
       
  1673     int id2 = machine.postDelayedEvent(new StringEvent("a"), 1000);
       
  1674     QVERIFY(id2 != -1);
       
  1675     machine.stop();
       
  1676     QTRY_COMPARE(stoppedSpy.count(), 2);
       
  1677     machine.start();
       
  1678     QTRY_COMPARE(startedSpy.count(), 3);
       
  1679     QTestEventLoop::instance().enterLoop(2);
       
  1680     QCOMPARE(machine.configuration().size(), 1);
       
  1681     QVERIFY(machine.configuration().contains(s1));
       
  1682 }
       
  1683 
       
  1684 void tst_QStateMachine::stateFinished()
       
  1685 {
       
  1686     QStateMachine machine;
       
  1687     QState *s1 = new QState(&machine);
       
  1688     QState *s1_1 = new QState(s1);
       
  1689     QFinalState *s1_2 = new QFinalState(s1);
       
  1690     s1_1->addTransition(s1_2);
       
  1691     s1->setInitialState(s1_1);
       
  1692     QFinalState *s2 = new QFinalState(&machine);
       
  1693     s1->addTransition(s1, SIGNAL(finished()), s2);
       
  1694     machine.setInitialState(s1);
       
  1695     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1696     machine.start();
       
  1697     QTRY_COMPARE(finishedSpy.count(), 1);
       
  1698     QCOMPARE(machine.configuration().size(), 1);
       
  1699     QVERIFY(machine.configuration().contains(s2));
       
  1700 }
       
  1701 
       
  1702 void tst_QStateMachine::parallelStates()
       
  1703 {
       
  1704     QStateMachine machine;
       
  1705 
       
  1706     QState *s1 = new QState(QState::ParallelStates);
       
  1707     QCOMPARE(s1->childMode(), QState::ParallelStates);
       
  1708       QState *s1_1 = new QState(s1);
       
  1709         QState *s1_1_1 = new QState(s1_1);
       
  1710         QFinalState *s1_1_f = new QFinalState(s1_1);
       
  1711         s1_1_1->addTransition(s1_1_f);
       
  1712       s1_1->setInitialState(s1_1_1);
       
  1713       QState *s1_2 = new QState(s1);
       
  1714         QState *s1_2_1 = new QState(s1_2);
       
  1715         QFinalState *s1_2_f = new QFinalState(s1_2);
       
  1716         s1_2_1->addTransition(s1_2_f);
       
  1717       s1_2->setInitialState(s1_2_1);
       
  1718     {
       
  1719         QString warning;
       
  1720         warning.sprintf("QState::setInitialState: ignoring attempt to set initial state of parallel state group %p", s1);
       
  1721         QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
       
  1722         s1->setInitialState(0);
       
  1723     }
       
  1724     machine.addState(s1);
       
  1725 
       
  1726     QFinalState *s2 = new QFinalState();
       
  1727     machine.addState(s2);
       
  1728 
       
  1729     s1->addTransition(s1, SIGNAL(finished()), s2);
       
  1730 
       
  1731     machine.setInitialState(s1);
       
  1732     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1733     machine.start();
       
  1734     QTRY_COMPARE(finishedSpy.count(), 1);
       
  1735     QCOMPARE(machine.configuration().size(), 1);
       
  1736     QVERIFY(machine.configuration().contains(s2));
       
  1737 }
       
  1738 
       
  1739 void tst_QStateMachine::parallelRootState()
       
  1740 {
       
  1741     QStateMachine machine;
       
  1742     QState *root = &machine;
       
  1743     QCOMPARE(root->childMode(), QState::ExclusiveStates);
       
  1744     root->setChildMode(QState::ParallelStates);
       
  1745     QCOMPARE(root->childMode(), QState::ParallelStates);
       
  1746 
       
  1747     QState *s1 = new QState(root);
       
  1748     QFinalState *s1_f = new QFinalState(s1);
       
  1749     s1->setInitialState(s1_f);
       
  1750     QState *s2 = new QState(root);
       
  1751     QFinalState *s2_f = new QFinalState(s2);
       
  1752     s2->setInitialState(s2_f);
       
  1753 
       
  1754     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  1755     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start.");
       
  1756     machine.start();
       
  1757     QCoreApplication::processEvents();
       
  1758     QEXPECT_FAIL("", "parallel root state is not supported (task 256587)", Continue);
       
  1759     QCOMPARE(startedSpy.count(), 1);
       
  1760 }
       
  1761 
       
  1762 void tst_QStateMachine::allSourceToTargetConfigurations()
       
  1763 {
       
  1764     QStateMachine machine;
       
  1765     QState *s0 = new QState(&machine);
       
  1766     s0->setObjectName("s0");
       
  1767     QState *s1 = new QState(s0);
       
  1768     s1->setObjectName("s1");
       
  1769     QState *s11 = new QState(s1);
       
  1770     s11->setObjectName("s11");
       
  1771     QState *s2 = new QState(s0);
       
  1772     s2->setObjectName("s2");
       
  1773     QState *s21 = new QState(s2);
       
  1774     s21->setObjectName("s21");
       
  1775     QState *s211 = new QState(s21);
       
  1776     s211->setObjectName("s211");
       
  1777     QFinalState *f = new QFinalState(&machine);
       
  1778     f->setObjectName("f");
       
  1779 
       
  1780     s0->setInitialState(s1);
       
  1781     s1->setInitialState(s11);
       
  1782     s2->setInitialState(s21);
       
  1783     s21->setInitialState(s211);
       
  1784 
       
  1785     s11->addTransition(new StringTransition("g", s211));
       
  1786     s1->addTransition(new StringTransition("a", s1));
       
  1787     s1->addTransition(new StringTransition("b", s11));
       
  1788     s1->addTransition(new StringTransition("c", s2));
       
  1789     s1->addTransition(new StringTransition("d", s0));
       
  1790     s1->addTransition(new StringTransition("f", s211));
       
  1791     s211->addTransition(new StringTransition("d", s21));
       
  1792     s211->addTransition(new StringTransition("g", s0));
       
  1793     s211->addTransition(new StringTransition("h", f));
       
  1794     s21->addTransition(new StringTransition("b", s211));
       
  1795     s2->addTransition(new StringTransition("c", s1));
       
  1796     s2->addTransition(new StringTransition("f", s11));
       
  1797     s0->addTransition(new StringTransition("e", s211));
       
  1798 
       
  1799     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1800     machine.setInitialState(s0);
       
  1801     machine.start();
       
  1802     QCoreApplication::processEvents();
       
  1803 
       
  1804     machine.postEvent(new StringEvent("a"));
       
  1805     QCoreApplication::processEvents();
       
  1806     machine.postEvent(new StringEvent("b"));
       
  1807     QCoreApplication::processEvents();
       
  1808     machine.postEvent(new StringEvent("c"));
       
  1809     QCoreApplication::processEvents();
       
  1810     machine.postEvent(new StringEvent("d"));
       
  1811     QCoreApplication::processEvents();
       
  1812     machine.postEvent(new StringEvent("e"));
       
  1813     QCoreApplication::processEvents();
       
  1814     machine.postEvent(new StringEvent("f"));
       
  1815     QCoreApplication::processEvents();
       
  1816     machine.postEvent(new StringEvent("g"));
       
  1817     QCoreApplication::processEvents();
       
  1818     machine.postEvent(new StringEvent("h"));
       
  1819     QCoreApplication::processEvents();
       
  1820 
       
  1821     QTRY_COMPARE(finishedSpy.count(), 1);
       
  1822 }
       
  1823 
       
  1824 class TestSignalTransition : public QSignalTransition
       
  1825 {
       
  1826 public:
       
  1827     TestSignalTransition(QState *sourceState = 0)
       
  1828         : QSignalTransition(sourceState), m_sender(0)
       
  1829     {}
       
  1830     TestSignalTransition(QObject *sender, const char *signal,
       
  1831                          QAbstractState *target)
       
  1832         : QSignalTransition(sender, signal), m_sender(0)
       
  1833     { setTargetState(target); }
       
  1834     QObject *senderReceived() const {
       
  1835         return m_sender;
       
  1836     }
       
  1837     int signalIndexReceived() const {
       
  1838         return m_signalIndex;
       
  1839     }
       
  1840     QVariantList argumentsReceived() const {
       
  1841         return m_args;
       
  1842     }
       
  1843 protected:
       
  1844     bool eventTest(QEvent *e) {
       
  1845         if (!QSignalTransition::eventTest(e))
       
  1846             return false;
       
  1847         QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e);
       
  1848         m_sender = se->sender();
       
  1849         m_signalIndex = se->signalIndex();
       
  1850         m_args = se->arguments();
       
  1851         return true;
       
  1852     }
       
  1853 private:
       
  1854     QObject *m_sender;
       
  1855     int m_signalIndex;
       
  1856     QVariantList m_args;
       
  1857 };
       
  1858 
       
  1859 void tst_QStateMachine::signalTransitions()
       
  1860 {
       
  1861     {
       
  1862         QStateMachine machine;
       
  1863         QState *s0 = new QState(&machine);
       
  1864         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: sender cannot be null");
       
  1865         QCOMPARE(s0->addTransition(0, SIGNAL(noSuchSignal()), 0), (QSignalTransition*)0);
       
  1866 
       
  1867         SignalEmitter emitter;
       
  1868         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: signal cannot be null");
       
  1869         QCOMPARE(s0->addTransition(&emitter, 0, 0), (QSignalTransition*)0);
       
  1870 
       
  1871         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state");
       
  1872         QCOMPARE(s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), 0), (QSignalTransition*)0);
       
  1873 
       
  1874         QFinalState *s1 = new QFinalState(&machine);
       
  1875         QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: no such signal SignalEmitter::noSuchSignal()");
       
  1876         QCOMPARE(s0->addTransition(&emitter, SIGNAL(noSuchSignal()), s1), (QSignalTransition*)0);
       
  1877 
       
  1878         QSignalTransition *trans = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1);
       
  1879         QVERIFY(trans != 0);
       
  1880         QCOMPARE(trans->sourceState(), s0);
       
  1881         QCOMPARE(trans->targetState(), (QAbstractState*)s1);
       
  1882         QCOMPARE(trans->senderObject(), (QObject*)&emitter);
       
  1883         QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg())));
       
  1884 
       
  1885         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1886         machine.setInitialState(s0);
       
  1887         machine.start();
       
  1888         QCoreApplication::processEvents();
       
  1889 
       
  1890         emitter.emitSignalWithNoArg();
       
  1891 
       
  1892         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1893 
       
  1894         emitter.emitSignalWithNoArg();
       
  1895 
       
  1896         trans->setSignal(SIGNAL(signalWithIntArg(int)));
       
  1897         QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithIntArg(int))));
       
  1898         machine.start();
       
  1899         QCoreApplication::processEvents();
       
  1900         emitter.emitSignalWithIntArg(123);
       
  1901         QTRY_COMPARE(finishedSpy.count(), 2);
       
  1902 
       
  1903         machine.start();
       
  1904         QCoreApplication::processEvents();
       
  1905         trans->setSignal(SIGNAL(signalWithNoArg()));
       
  1906         QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg())));
       
  1907         emitter.emitSignalWithNoArg();
       
  1908         QTRY_COMPARE(finishedSpy.count(), 3);
       
  1909 
       
  1910         SignalEmitter emitter2;
       
  1911         machine.start();
       
  1912         QCoreApplication::processEvents();
       
  1913         trans->setSenderObject(&emitter2);
       
  1914         emitter2.emitSignalWithNoArg();
       
  1915         QTRY_COMPARE(finishedSpy.count(), 4);
       
  1916 
       
  1917         machine.start();
       
  1918         QCoreApplication::processEvents();
       
  1919         QTest::ignoreMessage(QtWarningMsg, "QSignalTransition: no such signal: SignalEmitter::noSuchSignal()");
       
  1920         trans->setSignal(SIGNAL(noSuchSignal()));
       
  1921         QCOMPARE(trans->signal(), QByteArray(SIGNAL(noSuchSignal())));
       
  1922     }
       
  1923     {
       
  1924         QStateMachine machine;
       
  1925         QState *s0 = new QState(&machine);
       
  1926         QFinalState *s1 = new QFinalState(&machine);
       
  1927         SignalEmitter emitter;
       
  1928         QSignalTransition *trans = s0->addTransition(&emitter, "signalWithNoArg()", s1);
       
  1929         QVERIFY(trans != 0);
       
  1930         QCOMPARE(trans->sourceState(), s0);
       
  1931         QCOMPARE(trans->targetState(), (QAbstractState*)s1);
       
  1932         QCOMPARE(trans->senderObject(), (QObject*)&emitter);
       
  1933         QCOMPARE(trans->signal(), QByteArray("signalWithNoArg()"));
       
  1934 
       
  1935         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1936         machine.setInitialState(s0);
       
  1937         machine.start();
       
  1938         QCoreApplication::processEvents();
       
  1939 
       
  1940         emitter.emitSignalWithNoArg();
       
  1941 
       
  1942         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1943 
       
  1944         trans->setSignal("signalWithIntArg(int)");
       
  1945         QCOMPARE(trans->signal(), QByteArray("signalWithIntArg(int)"));
       
  1946         machine.start();
       
  1947         QCoreApplication::processEvents();
       
  1948         emitter.emitSignalWithIntArg(123);
       
  1949         QTRY_COMPARE(finishedSpy.count(), 2);
       
  1950     }
       
  1951     {
       
  1952         QStateMachine machine;
       
  1953         QState *s0 = new QState(&machine);
       
  1954         QFinalState *s1 = new QFinalState(&machine);
       
  1955         SignalEmitter emitter;
       
  1956         TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithIntArg(int)), s1);
       
  1957         s0->addTransition(trans);
       
  1958 
       
  1959         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1960         machine.setInitialState(s0);
       
  1961         machine.start();
       
  1962         QCoreApplication::processEvents();
       
  1963 
       
  1964         emitter.emitSignalWithIntArg(123);
       
  1965 
       
  1966         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1967         QCOMPARE(trans->senderReceived(), (QObject*)&emitter);
       
  1968         QCOMPARE(trans->signalIndexReceived(), emitter.metaObject()->indexOfSignal("signalWithIntArg(int)"));
       
  1969         QCOMPARE(trans->argumentsReceived().size(), 1);
       
  1970         QCOMPARE(trans->argumentsReceived().at(0).toInt(), 123);
       
  1971     }
       
  1972     {
       
  1973         QStateMachine machine;
       
  1974         QState *s0 = new QState(&machine);
       
  1975         QFinalState *s1 = new QFinalState(&machine);
       
  1976         SignalEmitter emitter;
       
  1977         TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithStringArg(QString)), s1);
       
  1978         s0->addTransition(trans);
       
  1979 
       
  1980         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  1981         machine.setInitialState(s0);
       
  1982         machine.start();
       
  1983         QCoreApplication::processEvents();
       
  1984 
       
  1985         QString testString = QString::fromLatin1("hello");
       
  1986         emitter.emitSignalWithStringArg(testString);
       
  1987 
       
  1988         QTRY_COMPARE(finishedSpy.count(), 1);
       
  1989         QCOMPARE(trans->senderReceived(), (QObject*)&emitter);
       
  1990         QCOMPARE(trans->signalIndexReceived(), emitter.metaObject()->indexOfSignal("signalWithStringArg(QString)"));
       
  1991         QCOMPARE(trans->argumentsReceived().size(), 1);
       
  1992         QCOMPARE(trans->argumentsReceived().at(0).toString(), testString);
       
  1993     }
       
  1994     {
       
  1995         QStateMachine machine;
       
  1996         QState *s0 = new QState(&machine);
       
  1997         QFinalState *s1 = new QFinalState(&machine);
       
  1998 
       
  1999         TestSignalTransition *trans = new TestSignalTransition();
       
  2000         QCOMPARE(trans->senderObject(), (QObject*)0);
       
  2001         QCOMPARE(trans->signal(), QByteArray());
       
  2002 
       
  2003         SignalEmitter emitter;
       
  2004         trans->setSenderObject(&emitter);
       
  2005         QCOMPARE(trans->senderObject(), (QObject*)&emitter);
       
  2006         trans->setSignal(SIGNAL(signalWithNoArg()));
       
  2007         QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg())));
       
  2008         trans->setTargetState(s1);
       
  2009         s0->addTransition(trans);
       
  2010 
       
  2011         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2012         machine.setInitialState(s0);
       
  2013         machine.start();
       
  2014         QCoreApplication::processEvents();
       
  2015 
       
  2016         emitter.emitSignalWithNoArg();
       
  2017 
       
  2018         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2019     }
       
  2020     // Multiple transitions for same (object,signal)
       
  2021     {
       
  2022         QStateMachine machine;
       
  2023         SignalEmitter emitter;
       
  2024         QState *s0 = new QState(&machine);
       
  2025         QState *s1 = new QState(&machine);
       
  2026         QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1);
       
  2027         QSignalTransition *t1 = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s0);
       
  2028 
       
  2029         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2030         machine.setInitialState(s0);
       
  2031         machine.start();
       
  2032         QCoreApplication::processEvents();
       
  2033         QCOMPARE(machine.configuration().size(), 1);
       
  2034         QVERIFY(machine.configuration().contains(s0));
       
  2035 
       
  2036         emitter.emitSignalWithNoArg();
       
  2037         QCoreApplication::processEvents();
       
  2038         QCOMPARE(machine.configuration().size(), 1);
       
  2039         QVERIFY(machine.configuration().contains(s1));
       
  2040 
       
  2041         s0->removeTransition(t0);
       
  2042         emitter.emitSignalWithNoArg();
       
  2043         QCoreApplication::processEvents();
       
  2044         QCOMPARE(machine.configuration().size(), 1);
       
  2045         QVERIFY(machine.configuration().contains(s0));
       
  2046 
       
  2047         emitter.emitSignalWithNoArg();
       
  2048         QCoreApplication::processEvents();
       
  2049         QCOMPARE(machine.configuration().size(), 1);
       
  2050         QVERIFY(machine.configuration().contains(s0));
       
  2051 
       
  2052         s1->removeTransition(t1);
       
  2053         emitter.emitSignalWithNoArg();
       
  2054         QCoreApplication::processEvents();
       
  2055         QCOMPARE(machine.configuration().size(), 1);
       
  2056         QVERIFY(machine.configuration().contains(s0));
       
  2057 
       
  2058         s0->addTransition(t0);
       
  2059         s1->addTransition(t1);
       
  2060         emitter.emitSignalWithNoArg();
       
  2061         QCoreApplication::processEvents();
       
  2062         QCOMPARE(machine.configuration().size(), 1);
       
  2063         QVERIFY(machine.configuration().contains(s1));
       
  2064     }
       
  2065     // multiple signal transitions from same source
       
  2066     {
       
  2067         QStateMachine machine;
       
  2068         SignalEmitter emitter;
       
  2069         QState *s0 = new QState(&machine);
       
  2070         QFinalState *s1 = new QFinalState(&machine);
       
  2071         s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1);
       
  2072         QFinalState *s2 = new QFinalState(&machine);
       
  2073         s0->addTransition(&emitter, SIGNAL(signalWithIntArg(int)), s2);
       
  2074         QFinalState *s3 = new QFinalState(&machine);
       
  2075         s0->addTransition(&emitter, SIGNAL(signalWithStringArg(QString)), s3);
       
  2076 
       
  2077         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2078         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2079         machine.setInitialState(s0);
       
  2080 
       
  2081         machine.start();
       
  2082         QTRY_COMPARE(startedSpy.count(), 1);
       
  2083         emitter.emitSignalWithNoArg();
       
  2084         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2085         QCOMPARE(machine.configuration().size(), 1);
       
  2086         QVERIFY(machine.configuration().contains(s1));
       
  2087 
       
  2088         machine.start();
       
  2089         QTRY_COMPARE(startedSpy.count(), 2);
       
  2090         emitter.emitSignalWithIntArg(123);
       
  2091         QTRY_COMPARE(finishedSpy.count(), 2);
       
  2092         QCOMPARE(machine.configuration().size(), 1);
       
  2093         QVERIFY(machine.configuration().contains(s2));
       
  2094 
       
  2095         machine.start();
       
  2096         QTRY_COMPARE(startedSpy.count(), 3);
       
  2097         emitter.emitSignalWithStringArg("hello");
       
  2098         QTRY_COMPARE(finishedSpy.count(), 3);
       
  2099         QCOMPARE(machine.configuration().size(), 1);
       
  2100         QVERIFY(machine.configuration().contains(s3));
       
  2101     }
       
  2102     // signature normalization
       
  2103     {
       
  2104         QStateMachine machine;
       
  2105         SignalEmitter emitter;
       
  2106         QState *s0 = new QState(&machine);
       
  2107         QFinalState *s1 = new QFinalState(&machine);
       
  2108         QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL( signalWithNoArg( ) ), s1);
       
  2109         QVERIFY(t0 != 0);
       
  2110         QCOMPARE(t0->signal(), QByteArray(SIGNAL( signalWithNoArg( ) )));
       
  2111 
       
  2112         QSignalTransition *t1 = s0->addTransition(&emitter, SIGNAL( signalWithStringArg( const QString & ) ), s1);
       
  2113         QVERIFY(t1 != 0);
       
  2114         QCOMPARE(t1->signal(), QByteArray(SIGNAL( signalWithStringArg( const QString & ) )));
       
  2115 
       
  2116         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2117         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2118         machine.setInitialState(s0);
       
  2119         machine.start();
       
  2120         QTRY_COMPARE(startedSpy.count(), 1);
       
  2121         QCOMPARE(finishedSpy.count(), 0);
       
  2122 
       
  2123         emitter.emitSignalWithNoArg();
       
  2124 
       
  2125         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2126     }
       
  2127 }
       
  2128 
       
  2129 class TestEventTransition : public QEventTransition
       
  2130 {
       
  2131 public:
       
  2132     TestEventTransition(QState *sourceState = 0)
       
  2133         : QEventTransition(sourceState),
       
  2134           m_eventSource(0), m_eventType(QEvent::None)
       
  2135     {}
       
  2136     TestEventTransition(QObject *object, QEvent::Type type,
       
  2137                         QAbstractState *target)
       
  2138         : QEventTransition(object, type),
       
  2139           m_eventSource(0), m_eventType(QEvent::None)
       
  2140     { setTargetState(target); }
       
  2141     QObject *eventSourceReceived() const {
       
  2142         return m_eventSource;
       
  2143     }
       
  2144     QEvent::Type eventTypeReceived() const {
       
  2145         return m_eventType;
       
  2146     }
       
  2147 protected:
       
  2148     bool eventTest(QEvent *e) {
       
  2149         if (!QEventTransition::eventTest(e))
       
  2150             return false;
       
  2151         QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(e);
       
  2152         m_eventSource = we->object();
       
  2153         m_eventType = we->event()->type();
       
  2154         return true;
       
  2155     }
       
  2156 private:
       
  2157     QObject *m_eventSource;
       
  2158     QEvent::Type m_eventType;
       
  2159 };
       
  2160 
       
  2161 void tst_QStateMachine::eventTransitions()
       
  2162 {
       
  2163     QPushButton button;
       
  2164     {
       
  2165         QStateMachine machine;
       
  2166         QState *s0 = new QState(&machine);
       
  2167         QFinalState *s1 = new QFinalState(&machine);
       
  2168 
       
  2169         QMouseEventTransition *trans;
       
  2170         trans = new QMouseEventTransition(&button, QEvent::MouseButtonPress, Qt::LeftButton);
       
  2171         QCOMPARE(trans->targetState(), (QAbstractState*)0);
       
  2172         trans->setTargetState(s1);
       
  2173         QCOMPARE(trans->eventType(), QEvent::MouseButtonPress);
       
  2174         QCOMPARE(trans->button(), Qt::LeftButton);
       
  2175         QCOMPARE(trans->targetState(), (QAbstractState*)s1);
       
  2176         s0->addTransition(trans);
       
  2177 
       
  2178         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2179         machine.setInitialState(s0);
       
  2180         machine.start();
       
  2181         QCoreApplication::processEvents();
       
  2182 
       
  2183         QTest::mousePress(&button, Qt::LeftButton);
       
  2184         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2185 
       
  2186         QTest::mousePress(&button, Qt::LeftButton);
       
  2187 
       
  2188         trans->setEventType(QEvent::MouseButtonRelease);
       
  2189         QCOMPARE(trans->eventType(), QEvent::MouseButtonRelease);
       
  2190         machine.start();
       
  2191         QCoreApplication::processEvents();
       
  2192         QTest::mouseRelease(&button, Qt::LeftButton);
       
  2193         QTRY_COMPARE(finishedSpy.count(), 2);
       
  2194 
       
  2195         machine.start();
       
  2196         QCoreApplication::processEvents();
       
  2197         trans->setEventType(QEvent::MouseButtonPress);
       
  2198         QTest::mousePress(&button, Qt::LeftButton);
       
  2199         QTRY_COMPARE(finishedSpy.count(), 3);
       
  2200 
       
  2201         QPushButton button2;
       
  2202         machine.start();
       
  2203         QCoreApplication::processEvents();
       
  2204         trans->setEventSource(&button2);
       
  2205         QTest::mousePress(&button2, Qt::LeftButton);
       
  2206         QTRY_COMPARE(finishedSpy.count(), 4);
       
  2207     }
       
  2208     for (int x = 0; x < 2; ++x) {
       
  2209         QStateMachine machine;
       
  2210         QState *s0 = new QState(&machine);
       
  2211         QFinalState *s1 = new QFinalState(&machine);
       
  2212 
       
  2213         QEventTransition *trans;
       
  2214         if (x == 0) {
       
  2215             trans = new QEventTransition();
       
  2216             QCOMPARE(trans->eventSource(), (QObject*)0);
       
  2217             QCOMPARE(trans->eventType(), QEvent::None);
       
  2218             trans->setEventSource(&button);
       
  2219             trans->setEventType(QEvent::MouseButtonPress);
       
  2220             trans->setTargetState(s1);
       
  2221         } else if (x == 1) {
       
  2222             trans = new QEventTransition(&button, QEvent::MouseButtonPress);
       
  2223             trans->setTargetState(s1);
       
  2224         }
       
  2225         QCOMPARE(trans->eventSource(), (QObject*)&button);
       
  2226         QCOMPARE(trans->eventType(), QEvent::MouseButtonPress);
       
  2227         QCOMPARE(trans->targetState(), (QAbstractState*)s1);
       
  2228         s0->addTransition(trans);
       
  2229 
       
  2230         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2231         machine.setInitialState(s0);
       
  2232         machine.start();
       
  2233         QCoreApplication::processEvents();
       
  2234 
       
  2235         QTest::mousePress(&button, Qt::LeftButton);
       
  2236         QCoreApplication::processEvents();
       
  2237 
       
  2238         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2239     }
       
  2240     {
       
  2241         QStateMachine machine;
       
  2242         QState *s0 = new QState(&machine);
       
  2243         QFinalState *s1 = new QFinalState(&machine);
       
  2244 
       
  2245         QMouseEventTransition *trans = new QMouseEventTransition();
       
  2246         QCOMPARE(trans->eventSource(), (QObject*)0);
       
  2247         QCOMPARE(trans->eventType(), QEvent::None);
       
  2248         QCOMPARE(trans->button(), Qt::NoButton);
       
  2249         trans->setEventSource(&button);
       
  2250         trans->setEventType(QEvent::MouseButtonPress);
       
  2251         trans->setButton(Qt::LeftButton);
       
  2252         trans->setTargetState(s1);
       
  2253         s0->addTransition(trans);
       
  2254 
       
  2255         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2256         machine.setInitialState(s0);
       
  2257         machine.start();
       
  2258         QCoreApplication::processEvents();
       
  2259 
       
  2260         QTest::mousePress(&button, Qt::LeftButton);
       
  2261         QCoreApplication::processEvents();
       
  2262 
       
  2263         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2264     }
       
  2265 
       
  2266     {
       
  2267         QStateMachine machine;
       
  2268         QState *s0 = new QState(&machine);
       
  2269         QFinalState *s1 = new QFinalState(&machine);
       
  2270 
       
  2271         QKeyEventTransition *trans = new QKeyEventTransition(&button, QEvent::KeyPress, Qt::Key_A);
       
  2272         QCOMPARE(trans->eventType(), QEvent::KeyPress);
       
  2273         QCOMPARE(trans->key(), (int)Qt::Key_A);
       
  2274         trans->setTargetState(s1);
       
  2275         s0->addTransition(trans);
       
  2276 
       
  2277         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2278         machine.setInitialState(s0);
       
  2279         machine.start();
       
  2280         QCoreApplication::processEvents();
       
  2281 
       
  2282         QTest::keyPress(&button, Qt::Key_A);
       
  2283         QCoreApplication::processEvents();
       
  2284 
       
  2285         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2286     }
       
  2287     {
       
  2288         QStateMachine machine;
       
  2289         QState *s0 = new QState(&machine);
       
  2290         QFinalState *s1 = new QFinalState(&machine);
       
  2291 
       
  2292         QKeyEventTransition *trans = new QKeyEventTransition();
       
  2293         QCOMPARE(trans->eventSource(), (QObject*)0);
       
  2294         QCOMPARE(trans->eventType(), QEvent::None);
       
  2295         QCOMPARE(trans->key(), 0);
       
  2296         trans->setEventSource(&button);
       
  2297         trans->setEventType(QEvent::KeyPress);
       
  2298         trans->setKey(Qt::Key_A);
       
  2299         trans->setTargetState(s1);
       
  2300         s0->addTransition(trans);
       
  2301 
       
  2302         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2303         machine.setInitialState(s0);
       
  2304         machine.start();
       
  2305         QCoreApplication::processEvents();
       
  2306 
       
  2307         QTest::keyPress(&button, Qt::Key_A);
       
  2308         QCoreApplication::processEvents();
       
  2309 
       
  2310         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2311     }
       
  2312     // Multiple transitions for same (object,event)
       
  2313     {
       
  2314         QStateMachine machine;
       
  2315         QState *s0 = new QState(&machine);
       
  2316         QState *s1 = new QState(&machine);
       
  2317         QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress);
       
  2318         t0->setTargetState(s1);
       
  2319         s0->addTransition(t0);
       
  2320         QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonPress);
       
  2321         t1->setTargetState(s0);
       
  2322         s1->addTransition(t1);
       
  2323 
       
  2324         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2325         machine.setInitialState(s0);
       
  2326         machine.start();
       
  2327         QCoreApplication::processEvents();
       
  2328         QCOMPARE(machine.configuration().size(), 1);
       
  2329         QVERIFY(machine.configuration().contains(s0));
       
  2330 
       
  2331         QTest::mousePress(&button, Qt::LeftButton);
       
  2332         QCoreApplication::processEvents();
       
  2333         QCOMPARE(machine.configuration().size(), 1);
       
  2334         QVERIFY(machine.configuration().contains(s1));
       
  2335 
       
  2336         s0->removeTransition(t0);
       
  2337         QTest::mousePress(&button, Qt::LeftButton);
       
  2338         QCoreApplication::processEvents();
       
  2339         QCOMPARE(machine.configuration().size(), 1);
       
  2340         QVERIFY(machine.configuration().contains(s0));
       
  2341 
       
  2342         QTest::mousePress(&button, Qt::LeftButton);
       
  2343         QCoreApplication::processEvents();
       
  2344         QCOMPARE(machine.configuration().size(), 1);
       
  2345         QVERIFY(machine.configuration().contains(s0));
       
  2346 
       
  2347         s1->removeTransition(t1);
       
  2348         QTest::mousePress(&button, Qt::LeftButton);
       
  2349         QCoreApplication::processEvents();
       
  2350         QCOMPARE(machine.configuration().size(), 1);
       
  2351         QVERIFY(machine.configuration().contains(s0));
       
  2352 
       
  2353         s0->addTransition(t0);
       
  2354         s1->addTransition(t1);
       
  2355         QTest::mousePress(&button, Qt::LeftButton);
       
  2356         QCoreApplication::processEvents();
       
  2357         QCOMPARE(machine.configuration().size(), 1);
       
  2358         QVERIFY(machine.configuration().contains(s1));
       
  2359     }
       
  2360     // multiple event transitions from same source
       
  2361     {
       
  2362         QStateMachine machine;
       
  2363         QState *s0 = new QState(&machine);
       
  2364         QFinalState *s1 = new QFinalState(&machine);
       
  2365         QFinalState *s2 = new QFinalState(&machine);
       
  2366         QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress);
       
  2367         t0->setTargetState(s1);
       
  2368         s0->addTransition(t0);
       
  2369         QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonRelease);
       
  2370         t1->setTargetState(s2);
       
  2371         s0->addTransition(t1);
       
  2372 
       
  2373         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2374         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2375         machine.setInitialState(s0);
       
  2376 
       
  2377         machine.start();
       
  2378         QTRY_COMPARE(startedSpy.count(), 1);
       
  2379         QTest::mousePress(&button, Qt::LeftButton);
       
  2380         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2381         QCOMPARE(machine.configuration().size(), 1);
       
  2382         QVERIFY(machine.configuration().contains(s1));
       
  2383 
       
  2384         machine.start();
       
  2385         QTRY_COMPARE(startedSpy.count(), 2);
       
  2386         QTest::mouseRelease(&button, Qt::LeftButton);
       
  2387         QTRY_COMPARE(finishedSpy.count(), 2);
       
  2388         QCOMPARE(machine.configuration().size(), 1);
       
  2389         QVERIFY(machine.configuration().contains(s2));
       
  2390     }
       
  2391     // custom event
       
  2392     {
       
  2393         QStateMachine machine;
       
  2394         QState *s0 = new QState(&machine);
       
  2395         QFinalState *s1 = new QFinalState(&machine);
       
  2396 
       
  2397         QEventTransition *trans = new QEventTransition(&button, QEvent::Type(QEvent::User+1));
       
  2398         trans->setTargetState(s1);
       
  2399         s0->addTransition(trans);
       
  2400 
       
  2401         QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2402         machine.setInitialState(s0);
       
  2403         machine.start();
       
  2404         QTest::ignoreMessage(QtWarningMsg, "QObject event transitions are not supported for custom types");
       
  2405         QTRY_COMPARE(startedSpy.count(), 1);
       
  2406     }
       
  2407     // custom transition
       
  2408     {
       
  2409         QStateMachine machine;
       
  2410         QState *s0 = new QState(&machine);
       
  2411         QFinalState *s1 = new QFinalState(&machine);
       
  2412 
       
  2413         TestEventTransition *trans = new TestEventTransition(&button, QEvent::MouseButtonPress, s1);
       
  2414         s0->addTransition(trans);
       
  2415         QCOMPARE(trans->eventSourceReceived(), (QObject*)0);
       
  2416         QCOMPARE(trans->eventTypeReceived(), QEvent::None);
       
  2417 
       
  2418         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2419         machine.setInitialState(s0);
       
  2420         machine.start();
       
  2421         QCoreApplication::processEvents();
       
  2422 
       
  2423         QTest::mousePress(&button, Qt::LeftButton);
       
  2424         QCoreApplication::processEvents();
       
  2425 
       
  2426         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2427 
       
  2428         QCOMPARE(trans->eventSourceReceived(), (QObject*)&button);
       
  2429         QCOMPARE(trans->eventTypeReceived(), QEvent::MouseButtonPress);
       
  2430     }
       
  2431 }
       
  2432 
       
  2433 void tst_QStateMachine::graphicsSceneEventTransitions()
       
  2434 {
       
  2435     QGraphicsScene scene;
       
  2436     QGraphicsTextItem *textItem = scene.addText("foo");
       
  2437 
       
  2438     QStateMachine machine;
       
  2439     QState *s1 = new QState(&machine);
       
  2440     QFinalState *s2 = new QFinalState(&machine);
       
  2441     QEventTransition *t = new QEventTransition(textItem, QEvent::GraphicsSceneMouseMove);
       
  2442     t->setTargetState(s2);
       
  2443     s1->addTransition(t);
       
  2444     machine.setInitialState(s1);
       
  2445 
       
  2446     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2447     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2448     machine.start();
       
  2449     QTRY_COMPARE(startedSpy.count(), 1);
       
  2450     QVERIFY(finishedSpy.count() == 0);
       
  2451     QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
       
  2452     scene.sendEvent(textItem, &mouseEvent);
       
  2453     QTRY_COMPARE(finishedSpy.count(), 1);
       
  2454 }
       
  2455 
       
  2456 void tst_QStateMachine::historyStates()
       
  2457 {
       
  2458     for (int x = 0; x < 2; ++x) {
       
  2459         QStateMachine machine;
       
  2460         QState *root = &machine;
       
  2461           QState *s0 = new QState(root);
       
  2462             QState *s00 = new QState(s0);
       
  2463             QState *s01 = new QState(s0);
       
  2464             QHistoryState *s0h;
       
  2465             if (x == 0) {
       
  2466                 s0h = new QHistoryState(s0);
       
  2467                 QCOMPARE(s0h->historyType(), QHistoryState::ShallowHistory);
       
  2468                 s0h->setHistoryType(QHistoryState::DeepHistory);
       
  2469             } else {
       
  2470                 s0h = new QHistoryState(QHistoryState::DeepHistory, s0);
       
  2471             }
       
  2472             QCOMPARE(s0h->historyType(), QHistoryState::DeepHistory);
       
  2473             s0h->setHistoryType(QHistoryState::ShallowHistory);
       
  2474             QCOMPARE(s0h->historyType(), QHistoryState::ShallowHistory);
       
  2475             QCOMPARE(s0h->defaultState(), (QAbstractState*)0);
       
  2476             s0h->setDefaultState(s00);
       
  2477             QCOMPARE(s0h->defaultState(), (QAbstractState*)s00);
       
  2478             QString warning;
       
  2479             warning.sprintf("QHistoryState::setDefaultState: state %p does not belong to this history state's group (%p)", s0, s0);
       
  2480             QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
       
  2481             s0h->setDefaultState(s0);
       
  2482           QState *s1 = new QState(root);
       
  2483           QFinalState *s2 = new QFinalState(root);
       
  2484 
       
  2485         s00->addTransition(new StringTransition("a", s01));
       
  2486         s0->addTransition(new StringTransition("b", s1));
       
  2487         s1->addTransition(new StringTransition("c", s0h));
       
  2488         s0->addTransition(new StringTransition("d", s2));
       
  2489 
       
  2490         root->setInitialState(s0);
       
  2491         s0->setInitialState(s00);
       
  2492 
       
  2493         QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2494         machine.start();
       
  2495         QCoreApplication::processEvents();
       
  2496         QCOMPARE(machine.configuration().size(), 2);
       
  2497         QVERIFY(machine.configuration().contains(s0));
       
  2498         QVERIFY(machine.configuration().contains(s00));
       
  2499 
       
  2500         machine.postEvent(new StringEvent("a"));
       
  2501         QCoreApplication::processEvents();
       
  2502         QCOMPARE(machine.configuration().size(), 2);
       
  2503         QVERIFY(machine.configuration().contains(s0));
       
  2504         QVERIFY(machine.configuration().contains(s01));
       
  2505 
       
  2506         machine.postEvent(new StringEvent("b"));
       
  2507         QCoreApplication::processEvents();
       
  2508         QCOMPARE(machine.configuration().size(), 1);
       
  2509         QVERIFY(machine.configuration().contains(s1));
       
  2510 
       
  2511         machine.postEvent(new StringEvent("c"));
       
  2512         QCoreApplication::processEvents();
       
  2513         QCOMPARE(machine.configuration().size(), 2);
       
  2514         QVERIFY(machine.configuration().contains(s0));
       
  2515         QVERIFY(machine.configuration().contains(s01));
       
  2516 
       
  2517         machine.postEvent(new StringEvent("d"));
       
  2518         QCoreApplication::processEvents();
       
  2519         QCOMPARE(machine.configuration().size(), 1);
       
  2520         QVERIFY(machine.configuration().contains(s2));
       
  2521 
       
  2522         QTRY_COMPARE(finishedSpy.count(), 1);
       
  2523     }
       
  2524 }
       
  2525 
       
  2526 void tst_QStateMachine::startAndStop()
       
  2527 {
       
  2528     QStateMachine machine;
       
  2529     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2530     QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
       
  2531     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2532     QVERIFY(!machine.isRunning());
       
  2533     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start.");
       
  2534     machine.start();
       
  2535     QCOMPARE(startedSpy.count(), 0);
       
  2536     QCOMPARE(stoppedSpy.count(), 0);
       
  2537     QCOMPARE(finishedSpy.count(), 0);
       
  2538     QVERIFY(!machine.isRunning());
       
  2539     machine.stop();
       
  2540     QCOMPARE(startedSpy.count(), 0);
       
  2541     QCOMPARE(stoppedSpy.count(), 0);
       
  2542     QCOMPARE(finishedSpy.count(), 0);
       
  2543 
       
  2544     QState *s1 = new QState(&machine);
       
  2545     machine.setInitialState(s1);
       
  2546     machine.start();
       
  2547     QTRY_COMPARE(machine.isRunning(), true);
       
  2548     QTRY_COMPARE(startedSpy.count(), 1);
       
  2549     QCOMPARE(stoppedSpy.count(), 0);
       
  2550     QCOMPARE(finishedSpy.count(), 0);
       
  2551     QCOMPARE(machine.configuration().count(), 1);
       
  2552     QVERIFY(machine.configuration().contains(s1));
       
  2553 
       
  2554     QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start(): already running");
       
  2555     machine.start();
       
  2556 
       
  2557     machine.stop();
       
  2558     QTRY_COMPARE(machine.isRunning(), false);
       
  2559     QTRY_COMPARE(stoppedSpy.count(), 1);
       
  2560     QCOMPARE(startedSpy.count(), 1);
       
  2561     QCOMPARE(finishedSpy.count(), 0);
       
  2562 
       
  2563     QCOMPARE(machine.configuration().count(), 1);
       
  2564     QVERIFY(machine.configuration().contains(s1));
       
  2565 
       
  2566     machine.start();
       
  2567     machine.stop();
       
  2568     QTRY_COMPARE(startedSpy.count(), 2);
       
  2569     QCOMPARE(stoppedSpy.count(), 2);
       
  2570 }
       
  2571 
       
  2572 void tst_QStateMachine::targetStateWithNoParent()
       
  2573 {
       
  2574     QStateMachine machine;
       
  2575     QState *s1 = new QState(&machine);
       
  2576     s1->setObjectName("s1");
       
  2577     QState s2;
       
  2578     s1->addTransition(&s2);
       
  2579     machine.setInitialState(s1);
       
  2580     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  2581     QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
       
  2582     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  2583     machine.start();
       
  2584     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 's1'");
       
  2585     QTRY_COMPARE(startedSpy.count(), 1);
       
  2586     QCOMPARE(machine.isRunning(), false);
       
  2587     QCOMPARE(stoppedSpy.count(), 1);
       
  2588     QCOMPARE(finishedSpy.count(), 0);
       
  2589     QCOMPARE(machine.error(), QStateMachine::NoCommonAncestorForTransitionError);
       
  2590 }
       
  2591 
       
  2592 void tst_QStateMachine::targetStateDeleted()
       
  2593 {
       
  2594     QStateMachine machine;
       
  2595     QState *s1 = new QState(&machine);
       
  2596     s1->setObjectName("s1");
       
  2597     QState *s2 = new QState(&machine);
       
  2598     QAbstractTransition *trans = s1->addTransition(s2);
       
  2599     delete s2;
       
  2600     QCOMPARE(trans->targetState(), (QAbstractState*)0);
       
  2601     QVERIFY(trans->targetStates().isEmpty());
       
  2602 }
       
  2603 
       
  2604 void tst_QStateMachine::defaultGlobalRestorePolicy()
       
  2605 {
       
  2606     QStateMachine machine;
       
  2607 
       
  2608     QObject *propertyHolder = new QObject(&machine);
       
  2609     propertyHolder->setProperty("a", 1);
       
  2610     propertyHolder->setProperty("b", 2);
       
  2611 
       
  2612     QState *s1 = new QState(&machine);
       
  2613     s1->assignProperty(propertyHolder, "a", 3);
       
  2614 
       
  2615     QState *s2 = new QState(&machine);
       
  2616     s2->assignProperty(propertyHolder, "b", 4);
       
  2617 
       
  2618     QState *s3 = new QState(&machine);
       
  2619 
       
  2620     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2621     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2622 
       
  2623     machine.setInitialState(s1);
       
  2624     machine.start();
       
  2625     QCoreApplication::processEvents();
       
  2626 
       
  2627     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2628     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2629 
       
  2630     machine.postEvent(new QEvent(QEvent::User));
       
  2631     QCoreApplication::processEvents();
       
  2632 
       
  2633     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2634     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2635 
       
  2636     machine.postEvent(new QEvent(QEvent::User));
       
  2637     QCoreApplication::processEvents();
       
  2638 
       
  2639     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2640     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2641 }
       
  2642 
       
  2643 void tst_QStateMachine::noInitialStateForInitialState()
       
  2644 {
       
  2645     QStateMachine machine;
       
  2646 
       
  2647     QState *initialState = new QState(&machine);
       
  2648     initialState->setObjectName("initialState");
       
  2649     machine.setInitialState(initialState);
       
  2650 
       
  2651     QState *childState = new QState(initialState);
       
  2652     (void)childState;
       
  2653 
       
  2654     QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
       
  2655                                        "Missing initial state in compound state 'initialState'");
       
  2656     machine.start();
       
  2657     QCoreApplication::processEvents();
       
  2658 
       
  2659     QCOMPARE(machine.isRunning(), false);
       
  2660     QCOMPARE(int(machine.error()), int(QStateMachine::NoInitialStateError));
       
  2661 }
       
  2662 
       
  2663 /*
       
  2664 void tst_QStateMachine::restorePolicyNotInherited()
       
  2665 {
       
  2666     QStateMachine machine;
       
  2667 
       
  2668     QObject *propertyHolder = new QObject();
       
  2669     propertyHolder->setProperty("a", 1);
       
  2670     propertyHolder->setProperty("b", 2);
       
  2671 
       
  2672     QState *parentState = new QState(&machine);
       
  2673     parentState->setObjectName("parentState");
       
  2674     parentState->setRestorePolicy(QState::RestoreProperties);
       
  2675 
       
  2676     QState *s1 = new QState(parentState);
       
  2677     s1->setObjectName("s1");
       
  2678     s1->assignProperty(propertyHolder, "a", 3);
       
  2679     parentState->setInitialState(s1);
       
  2680 
       
  2681     QState *s2 = new QState(parentState);
       
  2682     s2->setObjectName("s2");
       
  2683     s2->assignProperty(propertyHolder, "b", 4);
       
  2684 
       
  2685     QState *s3 = new QState(parentState);
       
  2686     s3->setObjectName("s3");
       
  2687 
       
  2688     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2689     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2690 
       
  2691     machine.setInitialState(parentState);
       
  2692     machine.start();
       
  2693     QCoreApplication::processEvents();
       
  2694 
       
  2695     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2696     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2697 
       
  2698     machine.postEvent(new QEvent(QEvent::User));
       
  2699     QCoreApplication::processEvents();
       
  2700 
       
  2701     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2702     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2703 
       
  2704     machine.postEvent(new QEvent(QEvent::User));
       
  2705     QCoreApplication::processEvents();
       
  2706 
       
  2707     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2708     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2709 
       
  2710 }*/
       
  2711 
       
  2712 void tst_QStateMachine::globalRestorePolicySetToDoNotRestore()
       
  2713 {
       
  2714     QStateMachine machine;
       
  2715     machine.setGlobalRestorePolicy(QStateMachine::DoNotRestoreProperties);
       
  2716 
       
  2717     QObject *propertyHolder = new QObject(&machine);
       
  2718     propertyHolder->setProperty("a", 1);
       
  2719     propertyHolder->setProperty("b", 2);
       
  2720 
       
  2721     QState *s1 = new QState(&machine);
       
  2722     s1->assignProperty(propertyHolder, "a", 3);
       
  2723 
       
  2724     QState *s2 = new QState(&machine);
       
  2725     s2->assignProperty(propertyHolder, "b", 4);
       
  2726 
       
  2727     QState *s3 = new QState(&machine);
       
  2728 
       
  2729     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2730     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2731 
       
  2732     machine.setInitialState(s1);
       
  2733     machine.start();
       
  2734     QCoreApplication::processEvents();
       
  2735 
       
  2736     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2737     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2738 
       
  2739     machine.postEvent(new QEvent(QEvent::User));
       
  2740     QCoreApplication::processEvents();
       
  2741 
       
  2742     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2743     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2744 
       
  2745     machine.postEvent(new QEvent(QEvent::User));
       
  2746     QCoreApplication::processEvents();
       
  2747 
       
  2748     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2749     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2750 }
       
  2751 
       
  2752 /*
       
  2753 void tst_QStateMachine::setRestorePolicyToDoNotRestore()
       
  2754 {
       
  2755     QObject *object = new QObject();
       
  2756     object->setProperty("a", 1);
       
  2757     object->setProperty("b", 2);
       
  2758 
       
  2759     QStateMachine machine;
       
  2760 
       
  2761     QState *S1 = new QState();
       
  2762     S1->setObjectName("S1");
       
  2763     S1->assignProperty(object, "a", 3);
       
  2764     S1->setRestorePolicy(QState::DoNotRestoreProperties);
       
  2765     machine.addState(S1);
       
  2766 
       
  2767     QState *S2 = new QState();
       
  2768     S2->setObjectName("S2");
       
  2769     S2->assignProperty(object, "b", 5);
       
  2770     S2->setRestorePolicy(QState::DoNotRestoreProperties);
       
  2771     machine.addState(S2);
       
  2772 
       
  2773     QState *S3 = new QState();
       
  2774     S3->setObjectName("S3");
       
  2775     S3->setRestorePolicy(QState::DoNotRestoreProperties);
       
  2776     machine.addState(S3);
       
  2777 
       
  2778     QFinalState *S4 = new QFinalState();
       
  2779     machine.addState(S4);
       
  2780 
       
  2781     S1->addTransition(new EventTransition(QEvent::User, S2));
       
  2782     S2->addTransition(new EventTransition(QEvent::User, S3));
       
  2783     S3->addTransition(S4);
       
  2784 
       
  2785     machine.setInitialState(S1);
       
  2786     machine.start();
       
  2787     QCoreApplication::processEvents();
       
  2788 
       
  2789     QCOMPARE(object->property("a").toInt(), 3);
       
  2790     QCOMPARE(object->property("b").toInt(), 2);
       
  2791 
       
  2792     machine.postEvent(new QEvent(QEvent::User));
       
  2793     QCoreApplication::processEvents();
       
  2794 
       
  2795     QCOMPARE(object->property("a").toInt(), 3);
       
  2796     QCOMPARE(object->property("b").toInt(), 5);
       
  2797 
       
  2798     machine.postEvent(new QEvent(QEvent::User));
       
  2799     QCoreApplication::processEvents();
       
  2800 
       
  2801     QCOMPARE(object->property("a").toInt(), 3);
       
  2802     QCOMPARE(object->property("b").toInt(), 5);
       
  2803 }
       
  2804 
       
  2805 void tst_QStateMachine::setGlobalRestorePolicyToGlobalRestore()
       
  2806 {
       
  2807     s_countWarnings = false;
       
  2808     QStateMachine machine;
       
  2809     machine.setGlobalRestorePolicy(QStateMachine::GlobalRestorePolicy);
       
  2810 
       
  2811     QCOMPARE(machine.globalRestorePolicy(), QStateMachine::DoNotRestoreProperties);
       
  2812     QCOMPARE(s_msgType, QtWarningMsg);
       
  2813 
       
  2814     s_msgType = QtDebugMsg;
       
  2815     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
  2816     machine.setGlobalRestorePolicy(QStateMachine::GlobalRestorePolicy);
       
  2817 
       
  2818     QCOMPARE(machine.globalRestorePolicy(), QStateMachine::RestoreProperties);
       
  2819     QCOMPARE(s_msgType, QtWarningMsg);
       
  2820 }
       
  2821 
       
  2822 
       
  2823 void tst_QStateMachine::restorePolicyOnChildState()
       
  2824 {
       
  2825     QStateMachine machine;
       
  2826 
       
  2827     QObject *propertyHolder = new QObject();
       
  2828     propertyHolder->setProperty("a", 1);
       
  2829     propertyHolder->setProperty("b", 2);
       
  2830 
       
  2831     QState *parentState = new QState(&machine);
       
  2832     parentState->setObjectName("parentState");
       
  2833 
       
  2834     QState *s1 = new QState(parentState);
       
  2835     s1->setRestorePolicy(QState::RestoreProperties);
       
  2836     s1->setObjectName("s1");
       
  2837     s1->assignProperty(propertyHolder, "a", 3);
       
  2838     parentState->setInitialState(s1);
       
  2839 
       
  2840     QState *s2 = new QState(parentState);
       
  2841     s2->setRestorePolicy(QState::RestoreProperties);
       
  2842     s2->setObjectName("s2");
       
  2843     s2->assignProperty(propertyHolder, "b", 4);
       
  2844 
       
  2845     QState *s3 = new QState(parentState);
       
  2846     s3->setRestorePolicy(QState::RestoreProperties);
       
  2847     s3->setObjectName("s3");
       
  2848 
       
  2849     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2850     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2851 
       
  2852     machine.setInitialState(parentState);
       
  2853     machine.start();
       
  2854     QCoreApplication::processEvents();
       
  2855 
       
  2856     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2857     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2858 
       
  2859     machine.postEvent(new QEvent(QEvent::User));
       
  2860     QCoreApplication::processEvents();
       
  2861 
       
  2862     QCOMPARE(propertyHolder->property("a").toInt(), 1);
       
  2863     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2864 
       
  2865     machine.postEvent(new QEvent(QEvent::User));
       
  2866     QCoreApplication::processEvents();
       
  2867 
       
  2868     QCOMPARE(propertyHolder->property("a").toInt(), 1);
       
  2869     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2870 }
       
  2871 */
       
  2872 
       
  2873 void tst_QStateMachine::globalRestorePolicySetToRestore()
       
  2874 {
       
  2875     QStateMachine machine;
       
  2876     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
  2877 
       
  2878     QObject *propertyHolder = new QObject(&machine);
       
  2879     propertyHolder->setProperty("a", 1);
       
  2880     propertyHolder->setProperty("b", 2);
       
  2881 
       
  2882     QState *s1 = new QState(&machine);
       
  2883     s1->assignProperty(propertyHolder, "a", 3);
       
  2884 
       
  2885     QState *s2 = new QState(&machine);
       
  2886     s2->assignProperty(propertyHolder, "b", 4);
       
  2887 
       
  2888     QState *s3 = new QState(&machine);
       
  2889 
       
  2890     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2891     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2892 
       
  2893     machine.setInitialState(s1);
       
  2894     machine.start();
       
  2895     QCoreApplication::processEvents();
       
  2896 
       
  2897     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2898     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2899 
       
  2900     machine.postEvent(new QEvent(QEvent::User));
       
  2901     QCoreApplication::processEvents();
       
  2902 
       
  2903     QCOMPARE(propertyHolder->property("a").toInt(), 1);
       
  2904     QCOMPARE(propertyHolder->property("b").toInt(), 4);
       
  2905 
       
  2906     machine.postEvent(new QEvent(QEvent::User));
       
  2907     QCoreApplication::processEvents();
       
  2908 
       
  2909     QCOMPARE(propertyHolder->property("a").toInt(), 1);
       
  2910     QCOMPARE(propertyHolder->property("b").toInt(), 2);
       
  2911 }
       
  2912 
       
  2913 /*
       
  2914 void tst_QStateMachine::mixedRestoreProperties()
       
  2915 {
       
  2916     QStateMachine machine;
       
  2917 
       
  2918     QObject *propertyHolder = new QObject();
       
  2919     propertyHolder->setProperty("a", 1);
       
  2920 
       
  2921     QState *s1 = new QState(&machine);
       
  2922     s1->setRestorePolicy(QState::RestoreProperties);
       
  2923     s1->assignProperty(propertyHolder, "a", 3);
       
  2924 
       
  2925     QState *s2 = new QState(&machine);
       
  2926     s2->assignProperty(propertyHolder, "a", 4);
       
  2927 
       
  2928     QState *s3 = new QState(&machine);
       
  2929 
       
  2930     QState *s4 = new QState(&machine);
       
  2931     s4->assignProperty(propertyHolder, "a", 5);
       
  2932 
       
  2933     QState *s5 = new QState(&machine);
       
  2934     s5->setRestorePolicy(QState::RestoreProperties);
       
  2935     s5->assignProperty(propertyHolder, "a", 6);
       
  2936 
       
  2937     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  2938     s2->addTransition(new EventTransition(QEvent::User, s3));
       
  2939     s3->addTransition(new EventTransition(QEvent::User, s4));
       
  2940     s4->addTransition(new EventTransition(QEvent::User, s5));
       
  2941     s5->addTransition(new EventTransition(QEvent::User, s3));
       
  2942 
       
  2943     machine.setInitialState(s1);
       
  2944     machine.start();
       
  2945     QCoreApplication::processEvents();
       
  2946 
       
  2947     // Enter s1, save current
       
  2948     QCOMPARE(propertyHolder->property("a").toInt(), 3);
       
  2949 
       
  2950     machine.postEvent(new QEvent(QEvent::User));
       
  2951     QCoreApplication::processEvents();
       
  2952 
       
  2953     // Enter s2, restorePolicy == DoNotRestore, so restore all properties
       
  2954     QCOMPARE(propertyHolder->property("a").toInt(), 4);
       
  2955 
       
  2956     machine.postEvent(new QEvent(QEvent::User));
       
  2957     QCoreApplication::processEvents();
       
  2958 
       
  2959     // Enter s3
       
  2960     QCOMPARE(propertyHolder->property("a").toInt(), 4);
       
  2961 
       
  2962     machine.postEvent(new QEvent(QEvent::User));
       
  2963     QCoreApplication::processEvents();
       
  2964 
       
  2965     // Enter s4
       
  2966     QCOMPARE(propertyHolder->property("a").toInt(), 5);
       
  2967 
       
  2968     machine.postEvent(new QEvent(QEvent::User));
       
  2969     QCoreApplication::processEvents();
       
  2970 
       
  2971     // Enter s5, save current
       
  2972     QCOMPARE(propertyHolder->property("a").toInt(), 6);
       
  2973 
       
  2974     machine.postEvent(new QEvent(QEvent::User));
       
  2975     QCoreApplication::processEvents();
       
  2976 
       
  2977     // Enter s3, restore
       
  2978     QCOMPARE(propertyHolder->property("a").toInt(), 5);
       
  2979 }
       
  2980 */
       
  2981 
       
  2982 void tst_QStateMachine::transitionWithParent()
       
  2983 {
       
  2984     QStateMachine machine;
       
  2985     QState *s1 = new QState(&machine);
       
  2986     QState *s2 = new QState(&machine);
       
  2987     EventTransition *trans = new EventTransition(QEvent::User, s2, s1);
       
  2988     QCOMPARE(trans->sourceState(), s1);
       
  2989     QCOMPARE(trans->targetState(), (QAbstractState*)s2);
       
  2990     QCOMPARE(trans->targetStates().size(), 1);
       
  2991     QCOMPARE(trans->targetStates().at(0), (QAbstractState*)s2);
       
  2992 }
       
  2993 
       
  2994 void tst_QStateMachine::simpleAnimation()
       
  2995 {
       
  2996     QStateMachine machine;
       
  2997 
       
  2998     QObject *object = new QObject(&machine);
       
  2999     object->setProperty("fooBar", 1.0);
       
  3000 
       
  3001     QState *s1 = new QState(&machine);
       
  3002     QState *s2 = new QState(&machine);
       
  3003     s2->assignProperty(object, "fooBar", 2.0);
       
  3004 
       
  3005     EventTransition *et = new EventTransition(QEvent::User, s2);
       
  3006     QPropertyAnimation *animation = new QPropertyAnimation(object, "fooBar", s2);
       
  3007     et->addAnimation(animation);
       
  3008     s1->addTransition(et);
       
  3009 
       
  3010     QState *s3 = new QState(&machine);
       
  3011     s2->addTransition(animation, SIGNAL(finished()), s3);
       
  3012     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3013 
       
  3014     machine.setInitialState(s1);
       
  3015     machine.start();
       
  3016     QCoreApplication::processEvents();
       
  3017 
       
  3018     machine.postEvent(new QEvent(QEvent::User));
       
  3019     QCOREAPPLICATION_EXEC(5000);
       
  3020 
       
  3021     QVERIFY(machine.configuration().contains(s3));
       
  3022     QCOMPARE(object->property("fooBar").toDouble(), 2.0);
       
  3023 }
       
  3024 
       
  3025 class SlotCalledCounter: public QObject
       
  3026 {
       
  3027     Q_OBJECT
       
  3028 public:
       
  3029     SlotCalledCounter() : counter(0) {}
       
  3030 
       
  3031     int counter;
       
  3032 
       
  3033 public slots:
       
  3034     void slot() { counter++; }
       
  3035 };
       
  3036 
       
  3037 void tst_QStateMachine::twoAnimations()
       
  3038 {
       
  3039     QStateMachine machine;
       
  3040 
       
  3041     QObject *object = new QObject(&machine);
       
  3042     object->setProperty("foo", 1.0);
       
  3043     object->setProperty("bar", 3.0);
       
  3044 
       
  3045     QState *s1 = new QState(&machine);
       
  3046     QState *s2 = new QState(&machine);
       
  3047     s2->assignProperty(object, "foo", 2.0);
       
  3048     s2->assignProperty(object, "bar", 10.0);
       
  3049 
       
  3050     QPropertyAnimation *animationFoo = new QPropertyAnimation(object, "foo", s2);
       
  3051     QPropertyAnimation *animationBar = new QPropertyAnimation(object, "bar", s2);
       
  3052     animationBar->setDuration(900);
       
  3053 
       
  3054     SlotCalledCounter counter;
       
  3055     connect(animationFoo, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3056     connect(animationBar, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3057 
       
  3058     EventTransition *et = new EventTransition(QEvent::User, s2);
       
  3059     et->addAnimation(animationFoo);
       
  3060     et->addAnimation(animationBar);
       
  3061     s1->addTransition(et);
       
  3062 
       
  3063     QState *s3 = new QState(&machine);
       
  3064     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3065     s2->addTransition(s2, SIGNAL(polished()), s3);
       
  3066 
       
  3067     machine.setInitialState(s1);
       
  3068     machine.start();
       
  3069     QCoreApplication::processEvents();
       
  3070 
       
  3071     machine.postEvent(new QEvent(QEvent::User));
       
  3072     QCOREAPPLICATION_EXEC(5000);
       
  3073 
       
  3074     QVERIFY(machine.configuration().contains(s3));
       
  3075     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3076     QCOMPARE(object->property("bar").toDouble(), 10.0);
       
  3077 
       
  3078     QCOMPARE(counter.counter, 2);
       
  3079 }
       
  3080 
       
  3081 void tst_QStateMachine::twoAnimatedTransitions()
       
  3082 {
       
  3083     QStateMachine machine;
       
  3084 
       
  3085     QObject *object = new QObject(&machine);
       
  3086     object->setProperty("foo", 1.0);
       
  3087 
       
  3088     QState *s1 = new QState(&machine);
       
  3089 
       
  3090     QState *s2 = new QState(&machine);
       
  3091     s2->assignProperty(object, "foo", 5.0);
       
  3092     QPropertyAnimation *fooAnimation = new QPropertyAnimation(object, "foo", s2);
       
  3093     s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(fooAnimation);
       
  3094 
       
  3095     QState *s3 = new QState(&machine);
       
  3096     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3097     s2->addTransition(fooAnimation, SIGNAL(finished()), s3);
       
  3098 
       
  3099     QState *s4 = new QState(&machine);
       
  3100     s4->assignProperty(object, "foo", 2.0);
       
  3101     QPropertyAnimation *fooAnimation2 = new QPropertyAnimation(object, "foo", s4);
       
  3102     s3->addTransition(new EventTransition(QEvent::User, s4))->addAnimation(fooAnimation2);
       
  3103 
       
  3104     QState *s5 = new QState(&machine);
       
  3105     QObject::connect(s5, SIGNAL(entered()), QApplication::instance(), SLOT(quit()));
       
  3106     s4->addTransition(fooAnimation2, SIGNAL(finished()), s5);
       
  3107 
       
  3108     machine.setInitialState(s1);
       
  3109     machine.start();
       
  3110     QCoreApplication::processEvents();
       
  3111 
       
  3112     machine.postEvent(new QEvent(QEvent::User));
       
  3113     QCOREAPPLICATION_EXEC(5000);
       
  3114 
       
  3115     QVERIFY(machine.configuration().contains(s3));
       
  3116     QCOMPARE(object->property("foo").toDouble(), 5.0);
       
  3117 
       
  3118     machine.postEvent(new QEvent(QEvent::User));
       
  3119     QCOREAPPLICATION_EXEC(5000);
       
  3120 
       
  3121     QVERIFY(machine.configuration().contains(s5));
       
  3122     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3123 }
       
  3124 
       
  3125 void tst_QStateMachine::playAnimationTwice()
       
  3126 {
       
  3127     QStateMachine machine;
       
  3128 
       
  3129     QObject *object = new QObject(&machine);
       
  3130     object->setProperty("foo", 1.0);
       
  3131 
       
  3132     QState *s1 = new QState(&machine);
       
  3133 
       
  3134     QState *s2 = new QState(&machine);
       
  3135     s2->assignProperty(object, "foo", 5.0);
       
  3136     QPropertyAnimation *fooAnimation = new QPropertyAnimation(object, "foo", s2);
       
  3137     s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(fooAnimation);
       
  3138 
       
  3139     QState *s3 = new QState(&machine);
       
  3140     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3141     s2->addTransition(fooAnimation, SIGNAL(finished()), s3);
       
  3142 
       
  3143     QState *s4 = new QState(&machine);
       
  3144     s4->assignProperty(object, "foo", 2.0);
       
  3145     s3->addTransition(new EventTransition(QEvent::User, s4))->addAnimation(fooAnimation);
       
  3146 
       
  3147     QState *s5 = new QState(&machine);
       
  3148     QObject::connect(s5, SIGNAL(entered()), QApplication::instance(), SLOT(quit()));
       
  3149     s4->addTransition(fooAnimation, SIGNAL(finished()), s5);
       
  3150 
       
  3151     machine.setInitialState(s1);
       
  3152     machine.start();
       
  3153     QCoreApplication::processEvents();
       
  3154 
       
  3155     machine.postEvent(new QEvent(QEvent::User));
       
  3156     QCOREAPPLICATION_EXEC(5000);
       
  3157 
       
  3158     QVERIFY(machine.configuration().contains(s3));
       
  3159     QCOMPARE(object->property("foo").toDouble(), 5.0);
       
  3160 
       
  3161     machine.postEvent(new QEvent(QEvent::User));
       
  3162     QCOREAPPLICATION_EXEC(5000);
       
  3163 
       
  3164     QVERIFY(machine.configuration().contains(s5));
       
  3165     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3166 }
       
  3167 
       
  3168 void tst_QStateMachine::nestedTargetStateForAnimation()
       
  3169 {
       
  3170     QStateMachine machine;
       
  3171 
       
  3172     QObject *object = new QObject(&machine);
       
  3173     object->setProperty("foo", 1.0);
       
  3174     object->setProperty("bar", 3.0);
       
  3175 
       
  3176     SlotCalledCounter counter;
       
  3177 
       
  3178     QState *s1 = new QState(&machine);
       
  3179     QState *s2 = new QState(&machine);
       
  3180 
       
  3181     s2->assignProperty(object, "foo", 2.0);
       
  3182 
       
  3183     QState *s2Child = new QState(s2);
       
  3184     s2Child->assignProperty(object, "bar", 10.0);
       
  3185     s2->setInitialState(s2Child);
       
  3186 
       
  3187     QState *s2Child2 = new QState(s2);
       
  3188     s2Child2->assignProperty(object, "bar", 11.0);
       
  3189     QAbstractTransition *at = s2Child->addTransition(new EventTransition(QEvent::User, s2Child2));
       
  3190 
       
  3191     QPropertyAnimation *animation = new QPropertyAnimation(object, "bar", s2);
       
  3192     animation->setDuration(2000);
       
  3193     connect(animation, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3194     at->addAnimation(animation);
       
  3195 
       
  3196     at = s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3197 
       
  3198     animation = new QPropertyAnimation(object, "foo", s2);
       
  3199     connect(animation, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3200     at->addAnimation(animation);
       
  3201 
       
  3202     animation = new QPropertyAnimation(object, "bar", s2);
       
  3203     connect(animation, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3204     at->addAnimation(animation);
       
  3205 
       
  3206     QState *s3 = new QState(&machine);
       
  3207     s2->addTransition(s2Child, SIGNAL(polished()), s3);
       
  3208 
       
  3209     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3210 
       
  3211     machine.setInitialState(s1);
       
  3212     machine.start();
       
  3213     QCoreApplication::processEvents();
       
  3214     machine.postEvent(new QEvent(QEvent::User));
       
  3215 
       
  3216     QCOREAPPLICATION_EXEC(5000);
       
  3217 
       
  3218     QVERIFY(machine.configuration().contains(s3));
       
  3219     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3220     QCOMPARE(object->property("bar").toDouble(), 10.0);
       
  3221     QCOMPARE(counter.counter, 2);
       
  3222 }
       
  3223 
       
  3224 void tst_QStateMachine::polishedSignalTransitionsReuseAnimationGroup()
       
  3225 {
       
  3226     QStateMachine machine;
       
  3227     QObject *object = new QObject(&machine);
       
  3228     object->setProperty("foo", 0);
       
  3229 
       
  3230     QState *s1 = new QState(&machine);
       
  3231     s1->assignProperty(object, "foo", 123);
       
  3232     QState *s2 = new QState(&machine);
       
  3233     s2->assignProperty(object, "foo", 456);
       
  3234     QState *s3 = new QState(&machine);
       
  3235     s3->assignProperty(object, "foo", 789);
       
  3236     QFinalState *s4 = new QFinalState(&machine);
       
  3237 
       
  3238     QParallelAnimationGroup animationGroup;
       
  3239     animationGroup.addAnimation(new QPropertyAnimation(object, "foo"));
       
  3240     QSignalSpy animationFinishedSpy(&animationGroup, SIGNAL(finished()));
       
  3241     s1->addTransition(s1, SIGNAL(polished()), s2)->addAnimation(&animationGroup);
       
  3242     s2->addTransition(s2, SIGNAL(polished()), s3)->addAnimation(&animationGroup);
       
  3243     s3->addTransition(s3, SIGNAL(polished()), s4);
       
  3244 
       
  3245     machine.setInitialState(s1);
       
  3246     QSignalSpy machineFinishedSpy(&machine, SIGNAL(finished()));
       
  3247     machine.start();
       
  3248     QTRY_COMPARE(machineFinishedSpy.count(), 1);
       
  3249     QCOMPARE(machine.configuration().size(), 1);
       
  3250     QVERIFY(machine.configuration().contains(s4));
       
  3251     QCOMPARE(object->property("foo").toInt(), 789);
       
  3252 
       
  3253     QCOMPARE(animationFinishedSpy.count(), 2);
       
  3254 }
       
  3255 
       
  3256 void tst_QStateMachine::animatedGlobalRestoreProperty()
       
  3257 {
       
  3258     QStateMachine machine;
       
  3259     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
  3260 
       
  3261     QObject *object = new QObject(&machine);
       
  3262     object->setProperty("foo", 1.0);
       
  3263 
       
  3264     SlotCalledCounter counter;
       
  3265 
       
  3266     QState *s1 = new QState(&machine);
       
  3267     QState *s2 = new QState(&machine);
       
  3268     s2->assignProperty(object, "foo", 2.0);
       
  3269 
       
  3270     QState *s3 = new QState(&machine);
       
  3271 
       
  3272     QState *s4 = new QState(&machine);
       
  3273     QObject::connect(s4, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3274 
       
  3275     QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3276     QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", s2);
       
  3277     connect(pa, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3278     at->addAnimation(pa);
       
  3279 
       
  3280     at = s2->addTransition(pa, SIGNAL(finished()), s3);
       
  3281     pa = new QPropertyAnimation(object, "foo", s3);
       
  3282     connect(pa, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3283     at->addAnimation(pa);
       
  3284 
       
  3285     at = s3->addTransition(pa, SIGNAL(finished()), s4);
       
  3286     pa = new QPropertyAnimation(object, "foo", s4);
       
  3287     connect(pa, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3288     at->addAnimation(pa);
       
  3289 
       
  3290     machine.setInitialState(s1);
       
  3291     machine.start();
       
  3292     QCoreApplication::processEvents();
       
  3293 
       
  3294     machine.postEvent(new QEvent(QEvent::User));
       
  3295 
       
  3296     QCOREAPPLICATION_EXEC(5000);
       
  3297 
       
  3298     QVERIFY(machine.configuration().contains(s4));
       
  3299     QCOMPARE(object->property("foo").toDouble(), 1.0);
       
  3300     QCOMPARE(counter.counter, 2);
       
  3301 }
       
  3302 
       
  3303 void tst_QStateMachine::specificTargetValueOfAnimation()
       
  3304 {
       
  3305     QStateMachine machine;
       
  3306 
       
  3307     QObject *object = new QObject(&machine);
       
  3308     object->setProperty("foo", 1.0);
       
  3309 
       
  3310     QState *s1 = new QState(&machine);
       
  3311 
       
  3312     QState *s2 = new QState(&machine);
       
  3313     s2->assignProperty(object, "foo", 2.0);
       
  3314 
       
  3315     QPropertyAnimation *anim = new QPropertyAnimation(object, "foo");
       
  3316     anim->setEndValue(10.0);
       
  3317     s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(anim);
       
  3318 
       
  3319     QState *s3 = new QState(&machine);
       
  3320     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3321     s2->addTransition(anim, SIGNAL(finished()), s3);
       
  3322 
       
  3323     machine.setInitialState(s1);
       
  3324     machine.start();
       
  3325     QCoreApplication::processEvents();
       
  3326 
       
  3327     machine.postEvent(new QEvent(QEvent::User));
       
  3328     QCOREAPPLICATION_EXEC(5000);
       
  3329 
       
  3330     QVERIFY(machine.configuration().contains(s3));
       
  3331     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3332     QCOMPARE(anim->endValue().toDouble(), 10.0);
       
  3333 
       
  3334     delete anim;
       
  3335 }
       
  3336 
       
  3337 void tst_QStateMachine::addDefaultAnimation()
       
  3338 {
       
  3339     QStateMachine machine;
       
  3340 
       
  3341     QObject *object = new QObject();
       
  3342     object->setProperty("foo", 1.0);
       
  3343 
       
  3344     QState *s1 = new QState(&machine);
       
  3345 
       
  3346     QState *s2 = new QState(&machine);
       
  3347     s2->assignProperty(object, "foo", 2.0);
       
  3348 
       
  3349     QState *s3 = new QState(&machine);
       
  3350     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3351 
       
  3352     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3353 
       
  3354     QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine);
       
  3355     machine.addDefaultAnimation(pa);
       
  3356     s2->addTransition(pa, SIGNAL(finished()), s3);
       
  3357 
       
  3358     machine.setInitialState(s1);
       
  3359     machine.start();
       
  3360     QCoreApplication::processEvents();
       
  3361 
       
  3362     machine.postEvent(new QEvent(QEvent::User));
       
  3363     QCOREAPPLICATION_EXEC(5000);
       
  3364 
       
  3365     QVERIFY(machine.configuration().contains(s3));
       
  3366     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3367 
       
  3368     delete object;
       
  3369 }
       
  3370 
       
  3371 void tst_QStateMachine::addDefaultAnimationWithUnusedAnimation()
       
  3372 {
       
  3373     QStateMachine machine;
       
  3374 
       
  3375     QObject *object = new QObject(&machine);
       
  3376     object->setProperty("foo", 1.0);
       
  3377     object->setProperty("bar", 2.0);
       
  3378 
       
  3379     SlotCalledCounter counter;
       
  3380 
       
  3381     QState *s1 = new QState(&machine);
       
  3382 
       
  3383     QState *s2 = new QState(&machine);
       
  3384     s2->assignProperty(object, "foo", 2.0);
       
  3385 
       
  3386     QState *s3 = new QState(&machine);
       
  3387     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3388 
       
  3389     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3390 
       
  3391     QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine);
       
  3392     connect(pa, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3393     machine.addDefaultAnimation(pa);
       
  3394     s2->addTransition(pa, SIGNAL(finished()), s3);
       
  3395 
       
  3396     pa = new QPropertyAnimation(object, "bar", &machine);
       
  3397     connect(pa, SIGNAL(finished()), &counter, SLOT(slot()));
       
  3398     machine.addDefaultAnimation(pa);
       
  3399 
       
  3400     machine.setInitialState(s1);
       
  3401     machine.start();
       
  3402     QCoreApplication::processEvents();
       
  3403 
       
  3404     machine.postEvent(new QEvent(QEvent::User));
       
  3405     QCOREAPPLICATION_EXEC(5000);
       
  3406 
       
  3407     QVERIFY(machine.configuration().contains(s3));
       
  3408     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3409     QCOMPARE(counter.counter, 1);
       
  3410 }
       
  3411 
       
  3412 void tst_QStateMachine::removeDefaultAnimation()
       
  3413 {
       
  3414     QStateMachine machine;
       
  3415 
       
  3416     QObject propertyHolder;
       
  3417     propertyHolder.setProperty("foo", 0);
       
  3418 
       
  3419     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3420 
       
  3421     QPropertyAnimation *anim = new QPropertyAnimation(&propertyHolder, "foo");
       
  3422 
       
  3423     machine.addDefaultAnimation(anim);
       
  3424 
       
  3425     QCOMPARE(machine.defaultAnimations().size(), 1);
       
  3426     QVERIFY(machine.defaultAnimations().contains(anim));
       
  3427 
       
  3428     machine.removeDefaultAnimation(anim);
       
  3429 
       
  3430     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3431 
       
  3432     machine.addDefaultAnimation(anim);
       
  3433 
       
  3434     QPropertyAnimation *anim2 = new QPropertyAnimation(&propertyHolder, "foo");
       
  3435     machine.addDefaultAnimation(anim2);
       
  3436 
       
  3437     QCOMPARE(machine.defaultAnimations().size(), 2);
       
  3438     QVERIFY(machine.defaultAnimations().contains(anim));
       
  3439     QVERIFY(machine.defaultAnimations().contains(anim2));
       
  3440 
       
  3441     machine.removeDefaultAnimation(anim);
       
  3442 
       
  3443     QCOMPARE(machine.defaultAnimations().size(), 1);
       
  3444     QVERIFY(machine.defaultAnimations().contains(anim2));
       
  3445 
       
  3446     machine.removeDefaultAnimation(anim2);
       
  3447     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3448 
       
  3449     delete anim;
       
  3450     delete anim2;
       
  3451 }
       
  3452 
       
  3453 void tst_QStateMachine::overrideDefaultAnimationWithSpecific()
       
  3454 {
       
  3455     QStateMachine machine;
       
  3456 
       
  3457     QObject *object = new QObject(&machine);
       
  3458     object->setProperty("foo", 1.0);
       
  3459 
       
  3460     SlotCalledCounter counter;
       
  3461 
       
  3462     QState *s1 = new QState(&machine);
       
  3463     machine.setInitialState(s1);
       
  3464 
       
  3465     QState *s2 = new QState(&machine);
       
  3466     s2->assignProperty(object, "foo", 2.0);
       
  3467 
       
  3468     QState *s3 = new QState(&machine);
       
  3469     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3470 
       
  3471     QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3472 
       
  3473     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3474     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3475 
       
  3476     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3477     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3478     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3479 
       
  3480     machine.addDefaultAnimation(defaultAnimation);
       
  3481     at->addAnimation(moreSpecificAnimation);
       
  3482 
       
  3483     machine.start();
       
  3484     QCoreApplication::processEvents();
       
  3485 
       
  3486     machine.postEvent(new QEvent(QEvent::User));
       
  3487     QCOREAPPLICATION_EXEC(5000);
       
  3488 
       
  3489     QVERIFY(machine.configuration().contains(s3));
       
  3490     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3491 
       
  3492     delete defaultAnimation;
       
  3493     delete moreSpecificAnimation;
       
  3494 }
       
  3495 
       
  3496 /*
       
  3497 void tst_QStateMachine::addDefaultAnimationForSource()
       
  3498 {
       
  3499     QStateMachine machine;
       
  3500 
       
  3501     QObject *object = new QObject();
       
  3502     object->setProperty("foo", 1.0);
       
  3503 
       
  3504     QState *s1 = new QState(&machine);
       
  3505 
       
  3506     QState *s2 = new QState(&machine);
       
  3507     s2->assignProperty(object, "foo", 2.0);
       
  3508 
       
  3509     QState *s3 = new QState(&machine);
       
  3510     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3511 
       
  3512     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3513 
       
  3514     QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine);
       
  3515     machine.addDefaultAnimationForSourceState(s1, pa);
       
  3516     s2->addTransition(pa, SIGNAL(finished()), s3);
       
  3517 
       
  3518     machine.setInitialState(s1);
       
  3519     machine.start();
       
  3520     QCoreApplication::processEvents();
       
  3521 
       
  3522     machine.postEvent(new QEvent(QEvent::User));
       
  3523     QCOREAPPLICATION_EXEC(5000);
       
  3524 
       
  3525     QVERIFY(machine.configuration().contains(s3));
       
  3526     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3527 }
       
  3528 
       
  3529 void tst_QStateMachine::addDefaultAnimationForTarget()
       
  3530 {
       
  3531     QStateMachine machine;
       
  3532 
       
  3533     QObject *object = new QObject();
       
  3534     object->setProperty("foo", 1.0);
       
  3535 
       
  3536     QState *s1 = new QState(&machine);
       
  3537 
       
  3538     QState *s2 = new QState(&machine);
       
  3539     s2->assignProperty(object, "foo", 2.0);
       
  3540 
       
  3541     QState *s3 = new QState(&machine);
       
  3542     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3543 
       
  3544     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3545 
       
  3546     QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine);
       
  3547     machine.addDefaultAnimationForTargetState(s2, pa);
       
  3548     s2->addTransition(pa, SIGNAL(finished()), s3);
       
  3549 
       
  3550     machine.setInitialState(s1);
       
  3551     machine.start();
       
  3552     QCoreApplication::processEvents();
       
  3553 
       
  3554     machine.postEvent(new QEvent(QEvent::User));
       
  3555     QCOREAPPLICATION_EXEC(5000);
       
  3556 
       
  3557     QVERIFY(machine.configuration().contains(s3));
       
  3558     QCOMPARE(object->property("foo").toDouble(), 2.0);
       
  3559 }
       
  3560 
       
  3561 void tst_QStateMachine::removeDefaultAnimationForSource()
       
  3562 {
       
  3563     QStateMachine machine;
       
  3564 
       
  3565     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0);
       
  3566 
       
  3567     QPropertyAnimation *anim = new QPropertyAnimation(this, "foo");
       
  3568 
       
  3569     machine.addDefaultAnimationForSourceState(&machine, anim);
       
  3570 
       
  3571     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3572     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0);
       
  3573     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1);
       
  3574     QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim));
       
  3575 
       
  3576     machine.removeDefaultAnimationForTargetState(&machine, anim);
       
  3577 
       
  3578     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3579     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0);
       
  3580     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1);
       
  3581     QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim));
       
  3582 
       
  3583     machine.removeDefaultAnimationForSourceState(&machine, anim);
       
  3584 
       
  3585     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0);
       
  3586 
       
  3587     machine.addDefaultAnimationForSourceState(&machine, anim);
       
  3588 
       
  3589     QPropertyAnimation *anim2 = new QPropertyAnimation(this, "foo");
       
  3590     machine.addDefaultAnimationForSourceState(&machine, anim2);
       
  3591 
       
  3592     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 2);
       
  3593     QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim));
       
  3594     QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim2));
       
  3595 
       
  3596     machine.removeDefaultAnimationForSourceState(&machine, anim);
       
  3597 
       
  3598     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1);
       
  3599     QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim2));
       
  3600 
       
  3601     machine.removeDefaultAnimationForSourceState(&machine, anim2);
       
  3602     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0);
       
  3603 }
       
  3604 
       
  3605 void tst_QStateMachine::removeDefaultAnimationForTarget()
       
  3606 {
       
  3607     QStateMachine machine;
       
  3608 
       
  3609     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0);
       
  3610 
       
  3611     QPropertyAnimation *anim = new QPropertyAnimation(this, "foo");
       
  3612 
       
  3613     machine.addDefaultAnimationForTargetState(&machine, anim);
       
  3614 
       
  3615     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3616     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0);
       
  3617     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1);
       
  3618     QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim));
       
  3619 
       
  3620     machine.removeDefaultAnimationForSourceState(&machine, anim);
       
  3621 
       
  3622     QCOMPARE(machine.defaultAnimations().size(), 0);
       
  3623     QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0);
       
  3624     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1);
       
  3625     QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim));
       
  3626 
       
  3627     machine.removeDefaultAnimationForTargetState(&machine, anim);
       
  3628 
       
  3629     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0);
       
  3630 
       
  3631     machine.addDefaultAnimationForTargetState(&machine, anim);
       
  3632 
       
  3633     QPropertyAnimation *anim2 = new QPropertyAnimation(this, "foo");
       
  3634     machine.addDefaultAnimationForTargetState(&machine, anim2);
       
  3635 
       
  3636     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 2);
       
  3637     QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim));
       
  3638     QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim2));
       
  3639 
       
  3640     machine.removeDefaultAnimationForTargetState(&machine, anim);
       
  3641 
       
  3642     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1);
       
  3643     QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim2));
       
  3644 
       
  3645     machine.removeDefaultAnimationForTargetState(&machine, anim2);
       
  3646     QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0);
       
  3647 }
       
  3648 
       
  3649 void tst_QStateMachine::overrideDefaultAnimationWithSource()
       
  3650 {
       
  3651     QStateMachine machine;
       
  3652 
       
  3653     QObject *object = new QObject();
       
  3654     object->setProperty("foo", 1.0);
       
  3655 
       
  3656     SlotCalledCounter counter;
       
  3657 
       
  3658     QState *s1 = new QState(&machine);
       
  3659     machine.setInitialState(s1);
       
  3660 
       
  3661     QState *s2 = new QState(&machine);
       
  3662     s2->assignProperty(object, "foo", 2.0);
       
  3663 
       
  3664     QState *s3 = new QState(&machine);
       
  3665     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3666 
       
  3667     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3668 
       
  3669     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3670     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3671 
       
  3672     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3673     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3674     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3675 
       
  3676     machine.addDefaultAnimation(defaultAnimation);
       
  3677     machine.addDefaultAnimationForSourceState(s1, moreSpecificAnimation);
       
  3678 
       
  3679     machine.start();
       
  3680     QCoreApplication::processEvents();
       
  3681 
       
  3682     machine.postEvent(new QEvent(QEvent::User));
       
  3683     QCOREAPPLICATION_EXEC(5000);
       
  3684 
       
  3685     QVERIFY(machine.configuration().contains(s3));
       
  3686     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3687 }
       
  3688 
       
  3689 void tst_QStateMachine::overrideDefaultAnimationWithTarget()
       
  3690 {
       
  3691     QStateMachine machine;
       
  3692 
       
  3693     QObject *object = new QObject();
       
  3694     object->setProperty("foo", 1.0);
       
  3695 
       
  3696     SlotCalledCounter counter;
       
  3697 
       
  3698     QState *s1 = new QState(&machine);
       
  3699     machine.setInitialState(s1);
       
  3700 
       
  3701     QState *s2 = new QState(&machine);
       
  3702     s2->assignProperty(object, "foo", 2.0);
       
  3703 
       
  3704     QState *s3 = new QState(&machine);
       
  3705     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3706 
       
  3707     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3708 
       
  3709     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3710     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3711 
       
  3712     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3713     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3714     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3715 
       
  3716     machine.addDefaultAnimation(defaultAnimation);
       
  3717     machine.addDefaultAnimationForTargetState(s2, moreSpecificAnimation);
       
  3718 
       
  3719     machine.start();
       
  3720     QCoreApplication::processEvents();
       
  3721 
       
  3722     machine.postEvent(new QEvent(QEvent::User));
       
  3723     QCOREAPPLICATION_EXEC(5000);
       
  3724 
       
  3725     QVERIFY(machine.configuration().contains(s3));
       
  3726     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3727 
       
  3728 }
       
  3729 
       
  3730 void tst_QStateMachine::overrideDefaultSourceAnimationWithSpecific()
       
  3731 {
       
  3732     QStateMachine machine;
       
  3733 
       
  3734     QObject *object = new QObject();
       
  3735     object->setProperty("foo", 1.0);
       
  3736 
       
  3737     SlotCalledCounter counter;
       
  3738 
       
  3739     QState *s1 = new QState(&machine);
       
  3740     machine.setInitialState(s1);
       
  3741 
       
  3742     QState *s2 = new QState(&machine);
       
  3743     s2->assignProperty(object, "foo", 2.0);
       
  3744 
       
  3745     QState *s3 = new QState(&machine);
       
  3746     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3747 
       
  3748     QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3749 
       
  3750     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3751     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3752 
       
  3753     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3754     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3755     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3756 
       
  3757     machine.addDefaultAnimationForSourceState(s1, defaultAnimation);
       
  3758     at->addAnimation(moreSpecificAnimation);
       
  3759 
       
  3760     machine.start();
       
  3761     QCoreApplication::processEvents();
       
  3762 
       
  3763     machine.postEvent(new QEvent(QEvent::User));
       
  3764     QCOREAPPLICATION_EXEC(5000);
       
  3765 
       
  3766     QVERIFY(machine.configuration().contains(s3));
       
  3767     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3768 }
       
  3769 
       
  3770 void tst_QStateMachine::overrideDefaultTargetAnimationWithSpecific()
       
  3771 {
       
  3772     QStateMachine machine;
       
  3773 
       
  3774     QObject *object = new QObject();
       
  3775     object->setProperty("foo", 1.0);
       
  3776 
       
  3777     SlotCalledCounter counter;
       
  3778 
       
  3779     QState *s1 = new QState(&machine);
       
  3780     machine.setInitialState(s1);
       
  3781 
       
  3782     QState *s2 = new QState(&machine);
       
  3783     s2->assignProperty(object, "foo", 2.0);
       
  3784 
       
  3785     QState *s3 = new QState(&machine);
       
  3786     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3787 
       
  3788     QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3789 
       
  3790     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3791     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3792 
       
  3793     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3794     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3795     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3796 
       
  3797     machine.addDefaultAnimationForTargetState(s2, defaultAnimation);
       
  3798     at->addAnimation(moreSpecificAnimation);
       
  3799 
       
  3800     machine.start();
       
  3801     QCoreApplication::processEvents();
       
  3802 
       
  3803     machine.postEvent(new QEvent(QEvent::User));
       
  3804     QCOREAPPLICATION_EXEC(5000);
       
  3805 
       
  3806     QVERIFY(machine.configuration().contains(s3));
       
  3807     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3808 }
       
  3809 
       
  3810 void tst_QStateMachine::overrideDefaultTargetAnimationWithSource()
       
  3811 {
       
  3812     QStateMachine machine;
       
  3813 
       
  3814     QObject *object = new QObject();
       
  3815     object->setProperty("foo", 1.0);
       
  3816 
       
  3817     SlotCalledCounter counter;
       
  3818 
       
  3819     QState *s1 = new QState(&machine);
       
  3820     machine.setInitialState(s1);
       
  3821 
       
  3822     QState *s2 = new QState(&machine);
       
  3823     s2->assignProperty(object, "foo", 2.0);
       
  3824 
       
  3825     QState *s3 = new QState(&machine);
       
  3826     QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit()));
       
  3827 
       
  3828     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3829 
       
  3830     QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo");
       
  3831     connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3832 
       
  3833     QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo");
       
  3834     s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3);
       
  3835     connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot()));
       
  3836 
       
  3837     machine.addDefaultAnimationForTargetState(s2, defaultAnimation);
       
  3838     machine.addDefaultAnimationForSourceState(s1, moreSpecificAnimation);
       
  3839 
       
  3840     machine.start();
       
  3841     QCoreApplication::processEvents();
       
  3842 
       
  3843     machine.postEvent(new QEvent(QEvent::User));
       
  3844     QCOREAPPLICATION_EXEC(5000);
       
  3845 
       
  3846     QVERIFY(machine.configuration().contains(s3));
       
  3847     QCOMPARE(counter.counter, 2); // specific animation started and stopped
       
  3848 }
       
  3849 
       
  3850 */
       
  3851 
       
  3852 void tst_QStateMachine::parallelStateAssignmentsDone()
       
  3853 {
       
  3854     QStateMachine machine;
       
  3855 
       
  3856     QObject *propertyHolder = new QObject(&machine);
       
  3857     propertyHolder->setProperty("foo", 123);
       
  3858     propertyHolder->setProperty("bar", 456);
       
  3859     propertyHolder->setProperty("zoot", 789);
       
  3860 
       
  3861     QState *s1 = new QState(&machine);
       
  3862     machine.setInitialState(s1);
       
  3863 
       
  3864     QState *parallelState = new QState(QState::ParallelStates, &machine);
       
  3865     parallelState->assignProperty(propertyHolder, "foo", 321);
       
  3866 
       
  3867     QState *s2 = new QState(parallelState);
       
  3868     s2->assignProperty(propertyHolder, "bar", 654);
       
  3869 
       
  3870     QState *s3 = new QState(parallelState);
       
  3871     s3->assignProperty(propertyHolder, "zoot", 987);
       
  3872 
       
  3873     s1->addTransition(new EventTransition(QEvent::User, parallelState));
       
  3874     machine.start();
       
  3875     QCoreApplication::processEvents();
       
  3876 
       
  3877     QCOMPARE(propertyHolder->property("foo").toInt(), 123);
       
  3878     QCOMPARE(propertyHolder->property("bar").toInt(), 456);
       
  3879     QCOMPARE(propertyHolder->property("zoot").toInt(), 789);
       
  3880 
       
  3881     machine.postEvent(new QEvent(QEvent::User));
       
  3882     QCoreApplication::processEvents();
       
  3883 
       
  3884     QCOMPARE(propertyHolder->property("foo").toInt(), 321);
       
  3885     QCOMPARE(propertyHolder->property("bar").toInt(), 654);
       
  3886     QCOMPARE(propertyHolder->property("zoot").toInt(), 987);
       
  3887 }
       
  3888 
       
  3889 void tst_QStateMachine::transitionsFromParallelStateWithNoChildren()
       
  3890 {
       
  3891     QStateMachine machine;
       
  3892 
       
  3893     QState *parallelState = new QState(QState::ParallelStates, &machine);
       
  3894     machine.setInitialState(parallelState);
       
  3895 
       
  3896     QState *s1 = new QState(&machine);
       
  3897     parallelState->addTransition(new EventTransition(QEvent::User, s1));
       
  3898 
       
  3899     machine.start();
       
  3900     QCoreApplication::processEvents();
       
  3901 
       
  3902     QCOMPARE(1, machine.configuration().size());
       
  3903     QVERIFY(machine.configuration().contains(parallelState));
       
  3904 
       
  3905     machine.postEvent(new QEvent(QEvent::User));
       
  3906 
       
  3907     QCoreApplication::processEvents();
       
  3908 
       
  3909     QCOMPARE(1, machine.configuration().size());
       
  3910     QVERIFY(machine.configuration().contains(s1));
       
  3911 }
       
  3912 
       
  3913 void tst_QStateMachine::parallelStateTransition()
       
  3914 {
       
  3915     QStateMachine machine;
       
  3916 
       
  3917     QState *parallelState = new QState(QState::ParallelStates, &machine);
       
  3918     machine.setInitialState(parallelState);
       
  3919 
       
  3920     QState *s1 = new QState(parallelState);
       
  3921     QState *s2 = new QState(parallelState);
       
  3922 
       
  3923     QState *s1InitialChild = new QState(s1);
       
  3924     s1->setInitialState(s1InitialChild);
       
  3925 
       
  3926     QState *s2InitialChild = new QState(s2);
       
  3927     s2->setInitialState(s2InitialChild);
       
  3928 
       
  3929     QState *s1OtherChild = new QState(s1);
       
  3930 
       
  3931     s1->addTransition(new EventTransition(QEvent::User, s1OtherChild));
       
  3932 
       
  3933     machine.start();
       
  3934     QCoreApplication::processEvents();
       
  3935 
       
  3936     QVERIFY(machine.configuration().contains(parallelState));
       
  3937     QVERIFY(machine.configuration().contains(s1));
       
  3938     QVERIFY(machine.configuration().contains(s2));
       
  3939     QVERIFY(machine.configuration().contains(s1InitialChild));
       
  3940     QVERIFY(machine.configuration().contains(s2InitialChild));
       
  3941     QCOMPARE(machine.configuration().size(), 5);
       
  3942 
       
  3943     machine.postEvent(new QEvent(QEvent::User));
       
  3944     QCoreApplication::processEvents();
       
  3945 
       
  3946     QVERIFY(machine.configuration().contains(parallelState));
       
  3947 
       
  3948     QVERIFY(machine.configuration().contains(s1));
       
  3949 
       
  3950     QVERIFY(machine.configuration().contains(s2));
       
  3951     QVERIFY(machine.configuration().contains(s1OtherChild));
       
  3952     QVERIFY(machine.configuration().contains(s2InitialChild));
       
  3953     QCOMPARE(machine.configuration().size(), 5);
       
  3954 
       
  3955 }
       
  3956 
       
  3957 void tst_QStateMachine::nestedRestoreProperties()
       
  3958 {
       
  3959     QStateMachine machine;
       
  3960     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
  3961 
       
  3962     QObject *propertyHolder = new QObject(&machine);
       
  3963     propertyHolder->setProperty("foo", 1);
       
  3964     propertyHolder->setProperty("bar", 2);
       
  3965 
       
  3966     QState *s1 = new QState(&machine);
       
  3967     machine.setInitialState(s1);
       
  3968 
       
  3969     QState *s2 = new QState(&machine);
       
  3970     s2->assignProperty(propertyHolder, "foo", 3);
       
  3971 
       
  3972     QState *s21 = new QState(s2);
       
  3973     s21->assignProperty(propertyHolder, "bar", 4);
       
  3974     s2->setInitialState(s21);
       
  3975 
       
  3976     QState *s22 = new QState(s2);
       
  3977     s22->assignProperty(propertyHolder, "bar", 5);
       
  3978 
       
  3979     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  3980     s21->addTransition(new EventTransition(QEvent::User, s22));
       
  3981 
       
  3982     machine.start();
       
  3983     QCoreApplication::processEvents();
       
  3984 
       
  3985     QCOMPARE(machine.configuration().size(), 1);
       
  3986     QVERIFY(machine.configuration().contains(s1));
       
  3987     QCOMPARE(propertyHolder->property("foo").toInt(), 1);
       
  3988     QCOMPARE(propertyHolder->property("bar").toInt(), 2);
       
  3989 
       
  3990     machine.postEvent(new QEvent(QEvent::User));
       
  3991     QCoreApplication::processEvents();
       
  3992 
       
  3993     QCOMPARE(machine.configuration().size(), 2);
       
  3994     QVERIFY(machine.configuration().contains(s2));
       
  3995     QVERIFY(machine.configuration().contains(s21));
       
  3996     QCOMPARE(propertyHolder->property("foo").toInt(), 3);
       
  3997     QCOMPARE(propertyHolder->property("bar").toInt(), 4);
       
  3998 
       
  3999     machine.postEvent(new QEvent(QEvent::User));
       
  4000     QCoreApplication::processEvents();
       
  4001 
       
  4002     QCOMPARE(machine.configuration().size(), 2);
       
  4003     QVERIFY(machine.configuration().contains(s2));
       
  4004     QVERIFY(machine.configuration().contains(s22));
       
  4005     QCOMPARE(propertyHolder->property("foo").toInt(), 3);
       
  4006     QCOMPARE(propertyHolder->property("bar").toInt(), 5);
       
  4007 }
       
  4008 
       
  4009 void tst_QStateMachine::nestedRestoreProperties2()
       
  4010 {
       
  4011     QStateMachine machine;
       
  4012     machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
       
  4013 
       
  4014     QObject *propertyHolder = new QObject(&machine);
       
  4015     propertyHolder->setProperty("foo", 1);
       
  4016     propertyHolder->setProperty("bar", 2);
       
  4017 
       
  4018     QState *s1 = new QState(&machine);
       
  4019     machine.setInitialState(s1);
       
  4020 
       
  4021     QState *s2 = new QState(&machine);
       
  4022     s2->assignProperty(propertyHolder, "foo", 3);
       
  4023 
       
  4024     QState *s21 = new QState(s2);
       
  4025     s21->assignProperty(propertyHolder, "bar", 4);
       
  4026     s2->setInitialState(s21);
       
  4027 
       
  4028     QState *s22 = new QState(s2);
       
  4029     s22->assignProperty(propertyHolder, "foo", 6);
       
  4030     s22->assignProperty(propertyHolder, "bar", 5);
       
  4031 
       
  4032     s1->addTransition(new EventTransition(QEvent::User, s2));
       
  4033     s21->addTransition(new EventTransition(QEvent::User, s22));
       
  4034     s22->addTransition(new EventTransition(QEvent::User, s21));
       
  4035 
       
  4036     machine.start();
       
  4037     QCoreApplication::processEvents();
       
  4038 
       
  4039     QCOMPARE(machine.configuration().size(), 1);
       
  4040     QVERIFY(machine.configuration().contains(s1));
       
  4041     QCOMPARE(propertyHolder->property("foo").toInt(), 1);
       
  4042     QCOMPARE(propertyHolder->property("bar").toInt(), 2);
       
  4043 
       
  4044     machine.postEvent(new QEvent(QEvent::User));
       
  4045     QCoreApplication::processEvents();
       
  4046 
       
  4047     QCOMPARE(machine.configuration().size(), 2);
       
  4048     QVERIFY(machine.configuration().contains(s2));
       
  4049     QVERIFY(machine.configuration().contains(s21));
       
  4050     QCOMPARE(propertyHolder->property("foo").toInt(), 3);
       
  4051     QCOMPARE(propertyHolder->property("bar").toInt(), 4);
       
  4052 
       
  4053     machine.postEvent(new QEvent(QEvent::User));
       
  4054     QCoreApplication::processEvents();
       
  4055 
       
  4056     QCOMPARE(machine.configuration().size(), 2);
       
  4057     QVERIFY(machine.configuration().contains(s2));
       
  4058     QVERIFY(machine.configuration().contains(s22));
       
  4059     QCOMPARE(propertyHolder->property("foo").toInt(), 6);
       
  4060     QCOMPARE(propertyHolder->property("bar").toInt(), 5);
       
  4061 
       
  4062     machine.postEvent(new QEvent(QEvent::User));
       
  4063     QCoreApplication::processEvents();
       
  4064 
       
  4065     QCOMPARE(machine.configuration().size(), 2);
       
  4066     QVERIFY(machine.configuration().contains(s2));
       
  4067     QVERIFY(machine.configuration().contains(s21));
       
  4068     QCOMPARE(propertyHolder->property("foo").toInt(), 3);
       
  4069     QCOMPARE(propertyHolder->property("bar").toInt(), 4);
       
  4070 
       
  4071 }
       
  4072 
       
  4073 void tst_QStateMachine::nestedStateMachines()
       
  4074 {
       
  4075     QStateMachine machine;
       
  4076     QState *group = new QState(&machine);
       
  4077     group->setChildMode(QState::ParallelStates);
       
  4078     QStateMachine *subMachines[3];
       
  4079     for (int i = 0; i < 3; ++i) {
       
  4080         QState *subGroup = new QState(group);
       
  4081         QStateMachine *subMachine = new QStateMachine(subGroup);
       
  4082         {
       
  4083             QState *initial = new QState(subMachine);
       
  4084             QFinalState *done = new QFinalState(subMachine);
       
  4085             initial->addTransition(new EventTransition(QEvent::User, done));
       
  4086             subMachine->setInitialState(initial);
       
  4087         }
       
  4088         QFinalState *subMachineDone = new QFinalState(subGroup);
       
  4089         subMachine->addTransition(subMachine, SIGNAL(finished()), subMachineDone);
       
  4090         subGroup->setInitialState(subMachine);
       
  4091         subMachines[i] = subMachine;
       
  4092     }
       
  4093     QFinalState *final = new QFinalState(&machine);
       
  4094     group->addTransition(group, SIGNAL(finished()), final);
       
  4095     machine.setInitialState(group);
       
  4096 
       
  4097     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  4098     QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
       
  4099     machine.start();
       
  4100     QTRY_COMPARE(startedSpy.count(), 1);
       
  4101     QTRY_COMPARE(machine.configuration().count(), 1+2*3);
       
  4102     QVERIFY(machine.configuration().contains(group));
       
  4103     for (int i = 0; i < 3; ++i)
       
  4104         QVERIFY(machine.configuration().contains(subMachines[i]));
       
  4105 
       
  4106     QCoreApplication::processEvents(); // starts the submachines
       
  4107 
       
  4108     for (int i = 0; i < 3; ++i)
       
  4109         subMachines[i]->postEvent(new QEvent(QEvent::User));
       
  4110 
       
  4111     QTRY_COMPARE(finishedSpy.count(), 1);
       
  4112 }
       
  4113 
       
  4114 void tst_QStateMachine::goToState()
       
  4115 {
       
  4116     QStateMachine machine;
       
  4117     QState *s1 = new QState(&machine);
       
  4118     QState *s2 = new QState(&machine);
       
  4119     machine.setInitialState(s1);
       
  4120     QSignalSpy startedSpy(&machine, SIGNAL(started()));
       
  4121     machine.start();
       
  4122     QTRY_COMPARE(startedSpy.count(), 1);
       
  4123 
       
  4124     QStateMachinePrivate::get(&machine)->goToState(s2);
       
  4125     QCoreApplication::processEvents();
       
  4126     QCOMPARE(machine.configuration().size(), 1);
       
  4127     QVERIFY(machine.configuration().contains(s2));
       
  4128 
       
  4129     QStateMachinePrivate::get(&machine)->goToState(s2);
       
  4130     QCoreApplication::processEvents();
       
  4131     QCOMPARE(machine.configuration().size(), 1);
       
  4132     QVERIFY(machine.configuration().contains(s2));
       
  4133 
       
  4134     QStateMachinePrivate::get(&machine)->goToState(s1);
       
  4135     QStateMachinePrivate::get(&machine)->goToState(s2);
       
  4136     QStateMachinePrivate::get(&machine)->goToState(s1);
       
  4137     QCOMPARE(machine.configuration().size(), 1);
       
  4138     QVERIFY(machine.configuration().contains(s2));
       
  4139 
       
  4140     QCoreApplication::processEvents();
       
  4141     QCOMPARE(machine.configuration().size(), 1);
       
  4142     QVERIFY(machine.configuration().contains(s1));
       
  4143 
       
  4144     // go to state in group
       
  4145     QState *s2_1 = new QState(s2);
       
  4146     s2->setInitialState(s2_1);
       
  4147     QStateMachinePrivate::get(&machine)->goToState(s2_1);
       
  4148     QCoreApplication::processEvents();
       
  4149     QCOMPARE(machine.configuration().size(), 2);
       
  4150     QVERIFY(machine.configuration().contains(s2));
       
  4151     QVERIFY(machine.configuration().contains(s2_1));
       
  4152 }
       
  4153 
       
  4154 class CloneSignalTransition : public QSignalTransition
       
  4155 {
       
  4156 public:
       
  4157     CloneSignalTransition(QObject *sender, const char *signal, QAbstractState *target)
       
  4158         : QSignalTransition(sender, signal)
       
  4159     {
       
  4160         setTargetState(target);
       
  4161     }
       
  4162 
       
  4163     void onTransition(QEvent *e)
       
  4164     {
       
  4165         QSignalTransition::onTransition(e);
       
  4166         QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e);
       
  4167         eventSignalIndex = se->signalIndex();
       
  4168     }
       
  4169 
       
  4170     int eventSignalIndex;
       
  4171 };
       
  4172 
       
  4173 void tst_QStateMachine::task260403_clonedSignals()
       
  4174 {
       
  4175     SignalEmitter emitter;
       
  4176     QStateMachine machine;
       
  4177     QState *s1 = new QState(&machine);
       
  4178     QState *s2 = new QState(&machine);
       
  4179     CloneSignalTransition *t1 = new CloneSignalTransition(&emitter, SIGNAL(signalWithDefaultArg()), s2);
       
  4180     s1->addTransition(t1);
       
  4181 
       
  4182     machine.setInitialState(s1);
       
  4183     machine.start();
       
  4184     QTest::qWait(1);
       
  4185 
       
  4186     emitter.emitSignalWithDefaultArg();
       
  4187     QTest::qWait(1);
       
  4188     QCOMPARE(t1->eventSignalIndex, emitter.metaObject()->indexOfSignal("signalWithDefaultArg()"));
       
  4189 }
       
  4190 
       
  4191 QTEST_MAIN(tst_QStateMachine)
       
  4192 #include "tst_qstatemachine.moc"