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 <eskil.abrahamsen-blomfeldt@nokia.com>
This commit is contained in:
Kent Hansen 2012-07-12 19:40:04 +02:00 committed by Qt by Nokia
parent 58bea0b8e0
commit 22c7a1fd9b
3 changed files with 89 additions and 0 deletions

View File

@ -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();
}
/*!

View File

@ -155,6 +155,7 @@ QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
Q_D(QSignalTransition);
d->sender = sender;
d->signal = signal;
d->maybeRegister();
}
/*!

View File

@ -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"