summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@qt.io>2016-09-19 12:33:25 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2016-10-07 12:00:16 +0000
commitbc0d3869e409b40faa5e152a3e38e8ed97938efd (patch)
tree4ca4dda2f6e4e9e71122f54f6d3edd30d8f465ab /tests
parent70a4f65a9e182f1e06bb1483ff3b311f10ed119b (diff)
State machine interrogation interface
This interface can be used to get all states and transitions from an SCXML state machine. It will also signal which states are entered and exited for each microstep, and which transitions are taken by the microstep. Change-Id: I4bb936add6b3fd87a322093b8aee66521bb294a4 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/statemachineinfo/statemachine.scxml45
-rw-r--r--tests/auto/statemachineinfo/statemachineinfo.pro13
-rw-r--r--tests/auto/statemachineinfo/tst_statemachineinfo.cpp205
-rw-r--r--tests/auto/statemachineinfo/tst_statemachineinfo.qrc5
5 files changed, 270 insertions, 1 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 776a54a..60576d5 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -4,4 +4,5 @@ SUBDIRS = cmake\
dynamicmetaobject\
parser\
scion\
- statemachine
+ statemachine \
+ statemachineinfo
diff --git a/tests/auto/statemachineinfo/statemachine.scxml b/tests/auto/statemachineinfo/statemachine.scxml
new file mode 100644
index 0000000..94f06b1
--- /dev/null
+++ b/tests/auto/statemachineinfo/statemachine.scxml
@@ -0,0 +1,45 @@
+<?xml version="1.0" ?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtScxml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" name="InfoTest">
+ <transition/>
+ <state>
+ <transition target="next" event="step"/>
+ </state>
+ <parallel id="next">
+ <state id="a">
+ <transition target="theEnd" event="step"/>
+ </state>
+ <state id="b">
+ <transition target="theEnd" event="step" type="internal"/>
+ </state>
+ </parallel>
+ <final id="theEnd"/>
+</scxml>
diff --git a/tests/auto/statemachineinfo/statemachineinfo.pro b/tests/auto/statemachineinfo/statemachineinfo.pro
new file mode 100644
index 0000000..f8d5b5d
--- /dev/null
+++ b/tests/auto/statemachineinfo/statemachineinfo.pro
@@ -0,0 +1,13 @@
+QT = core gui qml testlib scxml-private
+CONFIG += testcase
+
+TARGET = tst_statemachineinfo
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+RESOURCES += tst_statemachineinfo.qrc
+
+SOURCES += \
+ tst_statemachineinfo.cpp
diff --git a/tests/auto/statemachineinfo/tst_statemachineinfo.cpp b/tests/auto/statemachineinfo/tst_statemachineinfo.cpp
new file mode 100644
index 0000000..1c33847
--- /dev/null
+++ b/tests/auto/statemachineinfo/tst_statemachineinfo.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtScxml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest>
+#include <QtScxml/qscxmlstatemachine.h>
+#include <QtScxml/private/qscxmlstatemachineinfo_p.h>
+
+Q_DECLARE_METATYPE(QScxmlError);
+
+class tst_StateMachineInfo: public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkInfo();
+};
+
+class Recorder: public QObject
+{
+ Q_OBJECT
+
+public:
+ void clear()
+ {
+ enterCount = 0;
+ entered.clear();
+ exitCount = 0;
+ exited.clear();
+ transitionTriggerCount = 0;
+ transitions.clear();
+ macroStepDone = false;
+ }
+
+public slots:
+ void statesEntered(const QVector<QScxmlStateMachineInfo::StateId> &states)
+ { entered = states; ++enterCount; }
+
+ void statesExited(const QVector<QScxmlStateMachineInfo::StateId> &states)
+ { exited = states; ++exitCount; }
+
+ void transitionsTriggered(const QVector<QScxmlStateMachineInfo::TransitionId> &transitions)
+ { this->transitions = transitions; ++transitionTriggerCount; }
+
+ void reachedStableState()
+ { macroStepDone = true; }
+
+ bool finishMacroStep() const
+ {
+ for (int i = 0; i < 100; ++i) {
+ if (!macroStepDone)
+ QCoreApplication::processEvents();
+ }
+
+ return macroStepDone;
+ }
+
+public:
+ int enterCount = 0;
+ QVector<QScxmlStateMachineInfo::StateId> entered;
+ int exitCount = 0;
+ QVector<QScxmlStateMachineInfo::StateId> exited;
+ int transitionTriggerCount = 0;
+ QVector<QScxmlStateMachineInfo::TransitionId> transitions;
+ bool macroStepDone = false;
+};
+
+void tst_StateMachineInfo::checkInfo()
+{
+ QScopedPointer<QScxmlStateMachine> stateMachine(
+ QScxmlStateMachine::fromFile(QString(":/tst_statemachineinfo/statemachine.scxml")));
+ QVERIFY(!stateMachine.isNull());
+ QVERIFY(stateMachine->parseErrors().isEmpty());
+ auto info = new QScxmlStateMachineInfo(stateMachine.data());
+
+ const QString machineName = QLatin1String("InfoTest");
+ QCOMPARE(info->stateName(QScxmlStateMachineInfo::StateMachineRootState), machineName);
+
+ auto states = info->allStates();
+ QCOMPARE(states.size(), 5);
+ QCOMPARE(info->stateName(states.at(0)), QLatin1String(""));
+ QCOMPARE(info->stateName(states.at(1)), QLatin1String("next"));
+ QCOMPARE(info->stateName(states.at(2)), QLatin1String("a"));
+ QCOMPARE(info->stateName(states.at(3)), QLatin1String("b"));
+ QCOMPARE(info->stateName(states.at(4)), QLatin1String("theEnd"));
+
+ QCOMPARE(info->stateType(states.at(0)), QScxmlStateMachineInfo::NormalState);
+ QCOMPARE(info->stateType(states.at(1)), QScxmlStateMachineInfo::ParallelState);
+ QCOMPARE(info->stateType(states.at(2)), QScxmlStateMachineInfo::NormalState);
+ QCOMPARE(info->stateType(states.at(3)), QScxmlStateMachineInfo::NormalState);
+ QCOMPARE(info->stateType(states.at(4)), QScxmlStateMachineInfo::FinalState);
+
+ auto transitions = info->allTransitions();
+ QCOMPARE(transitions.size(), 6);
+
+ // targetless transition on top level
+ QCOMPARE(info->transitionType(transitions.at(0)), QScxmlStateMachineInfo::ExternalTransition);
+ QCOMPARE(info->stateType(info->transitionSource(transitions.at(0))),
+ QScxmlStateMachineInfo::StateMachineRootState);
+ QCOMPARE(info->transitionTargets(transitions.at(0)).size(), 0);
+
+ // <anon>->next
+ QCOMPARE(info->transitionType(transitions.at(1)), QScxmlStateMachineInfo::ExternalTransition);
+ QCOMPARE(info->transitionSource(transitions.at(1)), states.at(0));
+ QCOMPARE(info->transitionTargets(transitions.at(1)).size(), 1);
+ QCOMPARE(info->transitionTargets(transitions.at(1)).at(0), states.at(1));
+
+ // a->theEnd
+ QCOMPARE(info->transitionType(transitions.at(2)), QScxmlStateMachineInfo::ExternalTransition);
+ QCOMPARE(info->transitionSource(transitions.at(2)), states.at(2));
+ QCOMPARE(info->transitionTargets(transitions.at(2)).size(), 1);
+ QCOMPARE(info->transitionTargets(transitions.at(2)).at(0), states.at(4));
+
+ // b->theEnd
+ QCOMPARE(info->transitionType(transitions.at(3)), QScxmlStateMachineInfo::InternalTransition);
+ QCOMPARE(info->transitionSource(transitions.at(3)), states.at(3));
+ QCOMPARE(info->transitionTargets(transitions.at(3)).size(), 1);
+ QCOMPARE(info->transitionTargets(transitions.at(3)).at(0), states.at(4));
+
+ // initial transition that activates the first (anonymous) state
+ QCOMPARE(info->transitionType(transitions.at(4)), QScxmlStateMachineInfo::SyntheticTransition);
+ QCOMPARE(info->stateType(info->transitionSource(transitions.at(4))),
+ QScxmlStateMachineInfo::StateMachineRootState);
+ QCOMPARE(info->transitionTargets(transitions.at(4)).size(), 1);
+ QCOMPARE(info->transitionTargets(transitions.at(4)).at(0), states.at(0));
+
+ // "initial" transition in the next state that activates all sub-states
+ QCOMPARE(info->transitionType(transitions.at(5)), QScxmlStateMachineInfo::SyntheticTransition);
+ QCOMPARE(info->transitionSource(transitions.at(5)), states.at(1));
+ QCOMPARE(info->transitionTargets(transitions.at(5)).size(), 2);
+ QCOMPARE(info->transitionTargets(transitions.at(5)).at(0), states.at(2));
+ QCOMPARE(info->transitionTargets(transitions.at(5)).at(1), states.at(3));
+
+ Recorder recorder;
+ QObject::connect(info, &QScxmlStateMachineInfo::statesEntered,
+ &recorder, &Recorder::statesEntered);
+ QObject::connect(info, &QScxmlStateMachineInfo::statesExited,
+ &recorder, &Recorder::statesExited);
+ QObject::connect(info, &QScxmlStateMachineInfo::transitionsTriggered,
+ &recorder, &Recorder::transitionsTriggered);
+ QObject::connect(stateMachine.data(), &QScxmlStateMachine::reachedStableState,
+ &recorder, &Recorder::reachedStableState);
+
+ // initial step into first anonymous state
+ stateMachine->start();
+ QVERIFY(recorder.finishMacroStep());
+ QCOMPARE(recorder.enterCount, 1);
+ QCOMPARE(recorder.entered, QVector<QScxmlStateMachineInfo::StateId>() << 0);
+ QVERIFY(recorder.exited.isEmpty());
+
+ recorder.clear();
+
+ // step from anonymous state into the parallel state, which activates "a" and "b" (in THAT
+ // order!)
+ stateMachine->submitEvent("step");
+ QVERIFY(recorder.finishMacroStep());
+ QCOMPARE(recorder.enterCount, 1);
+ QCOMPARE(recorder.entered, QVector<QScxmlStateMachineInfo::StateId>() << 1 << 2 << 3);
+ QCOMPARE(recorder.exited, QVector<QScxmlStateMachineInfo::StateId>() << 0);
+ QCOMPARE(recorder.transitionTriggerCount, 1);
+ QCOMPARE(recorder.transitions, QVector<QScxmlStateMachineInfo::TransitionId>() << 1);
+
+ recorder.clear();
+
+ // step from the state "b" into "theEnd", which exits "b", "a", and "next" in exactly that
+ // order
+ stateMachine->submitEvent("step");
+ QVERIFY(recorder.finishMacroStep());
+ QCOMPARE(recorder.enterCount, 1);
+ QCOMPARE(recorder.entered, QVector<QScxmlStateMachineInfo::StateId>() << 4);
+ QCOMPARE(recorder.exited, QVector<QScxmlStateMachineInfo::StateId>() << 3 << 2 << 1);
+ QCOMPARE(recorder.transitionTriggerCount, 1);
+ QCOMPARE(recorder.transitions, QVector<QScxmlStateMachineInfo::TransitionId>() << 2);
+}
+
+
+QTEST_MAIN(tst_StateMachineInfo)
+
+#include "tst_statemachineinfo.moc"
+
+
diff --git a/tests/auto/statemachineinfo/tst_statemachineinfo.qrc b/tests/auto/statemachineinfo/tst_statemachineinfo.qrc
new file mode 100644
index 0000000..0e464d4
--- /dev/null
+++ b/tests/auto/statemachineinfo/tst_statemachineinfo.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/tst_statemachineinfo">
+ <file>statemachine.scxml</file>
+ </qresource>
+</RCC>