From 22c7a1fd9b904ff6cffeca72b049da85aaf53f84 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Thu, 12 Jul 2012 19:40:04 +0200 Subject: [PATCH] statemachine: Fix dynamic transition registration edge cases Some of the transition constructors didn't call the maybeRegister() function, causing the transitions to be ignored if they were created when the state machine was running and the transition's source state was active. Added tests that cover all possible cases. Change-Id: If1b593b127bd719e3be4e5a2e6949a780c4e97c3 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qeventtransition.cpp | 2 + src/corelib/statemachine/qsignaltransition.cpp | 1 + .../qstatemachine/tst_qstatemachine.cpp | 86 ++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp index ed00d66..3c93281 100644 --- a/src/corelib/statemachine/qeventtransition.cpp +++ b/src/corelib/statemachine/qeventtransition.cpp @@ -150,6 +150,7 @@ QEventTransition::QEventTransition(QObject *object, QEvent::Type type, d->registered = false; d->object = object; d->eventType = type; + d->maybeRegister(); } /*! @@ -171,6 +172,7 @@ QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object, d->registered = false; d->object = object; d->eventType = type; + d->maybeRegister(); } /*! diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index bbd7bc4..26d2add 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -155,6 +155,7 @@ QSignalTransition::QSignalTransition(QObject *sender, const char *signal, Q_D(QSignalTransition); d->sender = sender; d->signal = signal; + d->maybeRegister(); } /*! diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index 88110b1..b14ab7d 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -206,6 +206,8 @@ private slots: void multiTargetTransitionInsideParallelStateGroup(); void signalTransitionNormalizeSignature(); + void createSignalTransitionWhenRunning(); + void createEventTransitionWhenRunning(); }; class TestState : public QState @@ -4741,5 +4743,89 @@ void tst_QStateMachine::signalTransitionNormalizeSignature() QCOMPARE(t0->transitionArgumentsReceived().size(), 0); } +void tst_QStateMachine::createSignalTransitionWhenRunning() +{ + QStateMachine machine; + QState *s1 = new QState(&machine); + machine.setInitialState(s1); + machine.start(); + QTRY_VERIFY(machine.configuration().contains(s1)); + + // Create by addTransition() + QState *s2 = new QState(&machine); + SignalEmitter emitter; + QAbstractTransition *t1 = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s2); + QCOMPARE(t1->sourceState(), s1); + emitter.emitSignalWithNoArg(); + QTRY_VERIFY(machine.configuration().contains(s2)); + + // Create by constructor that takes sender, signal, source (parent) state + QState *s3 = new QState(&machine); + QSignalTransition *t2 = new QSignalTransition(&emitter, SIGNAL(signalWithNoArg()), s2); + QCOMPARE(t2->sourceState(), s2); + t2->setTargetState(s3); + emitter.emitSignalWithNoArg(); + QTRY_VERIFY(machine.configuration().contains(s3)); + + // Create by constructor that takes source (parent) state + QState *s4 = new QState(&machine); + QSignalTransition *t3 = new QSignalTransition(s3); + QCOMPARE(t3->sourceState(), s3); + t3->setSenderObject(&emitter); + t3->setSignal(SIGNAL(signalWithNoArg())); + t3->setTargetState(s4); + emitter.emitSignalWithNoArg(); + QTRY_VERIFY(machine.configuration().contains(s4)); + + // Create by constructor without parent, then set the parent + QState *s5 = new QState(&machine); + QSignalTransition *t4 = new QSignalTransition(); + t4->setSenderObject(&emitter); + t4->setParent(s4); + QCOMPARE(t4->sourceState(), s4); + t4->setSignal(SIGNAL(signalWithNoArg())); + t4->setTargetState(s5); + emitter.emitSignalWithNoArg(); + QTRY_VERIFY(machine.configuration().contains(s5)); +} + +void tst_QStateMachine::createEventTransitionWhenRunning() +{ + QStateMachine machine; + QState *s1 = new QState(&machine); + machine.setInitialState(s1); + machine.start(); + QTRY_VERIFY(machine.configuration().contains(s1)); + + // Create by constructor that takes event source, type, source (parent) state + QState *s2 = new QState(&machine); + QObject object; + QEventTransition *t1 = new QEventTransition(&object, QEvent::Timer, s1); + QCOMPARE(t1->sourceState(), s1); + t1->setTargetState(s2); + + object.startTimer(10); // Will cause QEvent::Timer to fire every 10ms + QTRY_VERIFY(machine.configuration().contains(s2)); + + // Create by constructor that takes source (parent) state + QState *s3 = new QState(&machine); + QEventTransition *t2 = new QEventTransition(s2); + QCOMPARE(t2->sourceState(), s2); + t2->setEventSource(&object); + t2->setEventType(QEvent::Timer); + t2->setTargetState(s3); + QTRY_VERIFY(machine.configuration().contains(s3)); + + // Create by constructor without parent, then set the parent + QState *s4 = new QState(&machine); + QEventTransition *t3 = new QEventTransition(); + t3->setEventSource(&object); + t3->setParent(s3); + QCOMPARE(t3->sourceState(), s3); + t3->setEventType(QEvent::Timer); + t3->setTargetState(s4); + QTRY_VERIFY(machine.configuration().contains(s4)); +} + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" -- 2.7.4