summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@insta.fi>2021-02-18 21:28:37 +0200
committerJuha Vuolle <juha.vuolle@insta.fi>2021-05-03 13:51:52 +0300
commitf87d6ad8eabc03be67bc23136ec0bae488d8ee28 (patch)
tree9352ed93e51d492e644aae1a0bbf95a653575efc /tests
parent4c6cdbf36f73a933daf8cc345156a2b52c03b7c1 (diff)
QtScxml QML-facing properties bindable support
This commit adds the bindable support the QML facing properties that were feasible for such support. Task-number: QTBUG-89895 Change-Id: Ia8c9ada1c4bf9f14a1460363e79befd82975539d Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/scxmlqmlcpp/CMakeLists.txt15
-rw-r--r--tests/auto/qml/scxmlqmlcpp/brokenstatemachine.scxml61
-rw-r--r--tests/auto/qml/scxmlqmlcpp/statemachine.scxml111
-rw-r--r--tests/auto/qml/scxmlqmlcpp/submachineA.scxml4
-rw-r--r--tests/auto/qml/scxmlqmlcpp/submachineB.scxml4
-rw-r--r--tests/auto/qml/scxmlqmlcpp/topmachine.scxml19
-rw-r--r--tests/auto/qml/scxmlqmlcpp/tst_scxmlqmlcpp.cpp248
7 files changed, 379 insertions, 83 deletions
diff --git a/tests/auto/qml/scxmlqmlcpp/CMakeLists.txt b/tests/auto/qml/scxmlqmlcpp/CMakeLists.txt
index deb900f..67268d5 100644
--- a/tests/auto/qml/scxmlqmlcpp/CMakeLists.txt
+++ b/tests/auto/qml/scxmlqmlcpp/CMakeLists.txt
@@ -6,3 +6,18 @@ qt_internal_add_test(tst_scxmlqmlcpp
Qt::ScxmlQmlPrivate
Qt::CorePrivate
)
+
+qt_internal_add_resource(tst_scxmlqmlcpp "tst_compiled"
+ PREFIX
+ "/"
+ FILES
+ "submachineA.scxml"
+ "submachineB.scxml"
+ "topmachine.scxml"
+ "statemachine.scxml"
+ "brokenstatemachine.scxml"
+)
+
+qt6_add_statecharts(tst_scxmlqmlcpp
+ topmachine.scxml
+)
diff --git a/tests/auto/qml/scxmlqmlcpp/brokenstatemachine.scxml b/tests/auto/qml/scxmlqmlcpp/brokenstatemachine.scxml
new file mode 100644
index 0000000..4864303
--- /dev/null
+++ b/tests/auto/qml/scxmlqmlcpp/brokenstatemachine.scxml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/****************************************************************************
+**
+** 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<scxml
+ xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:qt="http://theqtcompany.com/scxml/2015/06/"
+ version="1.0"
+ name="IntentionallyBrokenStateMachine"
+ initial="working"
+>
+ I am broken
+</scxml>
diff --git a/tests/auto/qml/scxmlqmlcpp/statemachine.scxml b/tests/auto/qml/scxmlqmlcpp/statemachine.scxml
new file mode 100644
index 0000000..3cf023e
--- /dev/null
+++ b/tests/auto/qml/scxmlqmlcpp/statemachine.scxml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/****************************************************************************
+**
+** 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<scxml
+ xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:qt="http://theqtcompany.com/scxml/2015/06/"
+ version="1.0"
+ name="TrafficLightStateMachine"
+ initial="working"
+>
+ <state id="working" initial="yellow">
+ <state id="red">
+ <onentry>
+ <send event="startGoingGreen" delay="3s"/>
+ </onentry>
+ <transition event="startGoingGreen" target="redGoingGreen"/>
+ </state>
+
+ <state id="yellow" initial="greenGoingRed">
+ <state id="redGoingGreen">
+ <onentry>
+ <send event="goGreen" delay="1s"/>
+ </onentry>
+ <transition event="goGreen" target="green"/>
+ </state>
+
+ <state id="greenGoingRed">
+ <onentry>
+ <send event="goRed" delay="1s"/>
+ </onentry>
+ <transition event="goRed" target="red"/>
+ </state>
+ </state>
+
+ <state id="green">
+ <onentry>
+ <send event="startGoingRed" delay="3s"/>
+ </onentry>
+ <transition event="startGoingRed" target="greenGoingRed"/>
+ </state>
+
+ <transition event="smash" target="broken"/>
+ </state>
+
+ <state id="broken" initial="blinking">
+ <state id="blinking">
+ <onentry>
+ <send event="unblink" delay="1s"/>
+ </onentry>
+ <transition event="unblink" target="unblinking"/>
+ </state>
+
+ <state id="unblinking">
+ <onentry>
+ <send event="blink" delay="1s"/>
+ </onentry>
+ <transition event="blink" target="blinking"/>
+ </state>
+
+ <transition event="repair" target="working"/>
+ </state>
+</scxml>
diff --git a/tests/auto/qml/scxmlqmlcpp/submachineA.scxml b/tests/auto/qml/scxmlqmlcpp/submachineA.scxml
new file mode 100644
index 0000000..0924b2e
--- /dev/null
+++ b/tests/auto/qml/scxmlqmlcpp/submachineA.scxml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" name="SubMachine">
+ <final id="topState"/>
+</scxml>
diff --git a/tests/auto/qml/scxmlqmlcpp/submachineB.scxml b/tests/auto/qml/scxmlqmlcpp/submachineB.scxml
new file mode 100644
index 0000000..0924b2e
--- /dev/null
+++ b/tests/auto/qml/scxmlqmlcpp/submachineB.scxml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" name="SubMachine">
+ <final id="topState"/>
+</scxml>
diff --git a/tests/auto/qml/scxmlqmlcpp/topmachine.scxml b/tests/auto/qml/scxmlqmlcpp/topmachine.scxml
new file mode 100644
index 0000000..b733c6a
--- /dev/null
+++ b/tests/auto/qml/scxmlqmlcpp/topmachine.scxml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" name="TopMachine" datamodel="ecmascript">
+ <datamodel>
+ <data id="doneCounter" expr="0"/>
+ </datamodel>
+ <state id="topState">
+ <invoke type="scxml" id="submachine.1" src="file:submachineA.scxml"/>
+ <invoke type="scxml" id="submachine.2" src="file:submachineA.scxml"/>
+ <invoke type="scxml" id="submachine.3" src="file:submachineB.scxml"/>
+ <transition event="done.invoke">
+ <assign location="doneCounter" expr="doneCounter + 1"/>
+ <if cond="doneCounter === 3">
+ <send event="goToFinal" delay="1s"/>
+ </if>
+ </transition>
+ <transition event="goToFinal" target="finalState"/>
+ </state>
+ <final id="finalState"/>
+</scxml>
diff --git a/tests/auto/qml/scxmlqmlcpp/tst_scxmlqmlcpp.cpp b/tests/auto/qml/scxmlqmlcpp/tst_scxmlqmlcpp.cpp
index 1a1aa1d..408530e 100644
--- a/tests/auto/qml/scxmlqmlcpp/tst_scxmlqmlcpp.cpp
+++ b/tests/auto/qml/scxmlqmlcpp/tst_scxmlqmlcpp.cpp
@@ -29,7 +29,14 @@
#include <QtTest>
#include <QObject>
#include <QtScxml/QScxmlStateMachine>
+#include <QtScxml/QScxmlNullDataModel>
#include <QtScxmlQml/private/eventconnection_p.h>
+#include <QtScxmlQml/private/invokedservices_p.h>
+#include <QtScxmlQml/private/statemachineloader_p.h>
+#include "topmachine.h"
+#include <functional>
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlComponent>
#include <memory>
#include <QDebug>
@@ -39,99 +46,174 @@ class tst_scxmlqmlcpp: public QObject
Q_OBJECT
private slots:
void bindings();
+private:
+
+ // This is a helper function to test basics of typical bindable
+ // properties that are writable. Primarily ensure:
+ // - properties work as before bindings
+ // - added bindable aspects work
+ //
+ // "TestedClass" is the class type we are testing
+ // "TestedData" is the data type of the property we are testing
+ // "testedClass" is an instance of the class we are interested testing
+ // "data1" and "data2" are two different instances of property data to set and get
+ // "propertyName" is the name of the property we are interested in testing
+ template<typename TestedClass, typename TestedData>
+ void testWritableBindableBasics(TestedClass& testedClass, TestedData data1,
+ TestedData data2, const char* propertyName)
+ {
+ // Get the property we are testing
+ const QMetaObject *metaObject = testedClass.metaObject();
+ QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName));
+
+ // Generate a string to help identify failures (as this is a generic template)
+ QString id(metaObject->className());
+ id.append(QStringLiteral("::"));
+ id.append(metaProperty.name());
+
+ // Fail gracefully if preconditions to use this helper function are not met:
+ QVERIFY2(metaProperty.isBindable() && metaProperty.isWritable()
+ && metaProperty.hasNotifySignal(), qPrintable(id));
+ // Create a signal spy for the property changed -signal
+ QSignalSpy spy(&testedClass, metaProperty.notifySignal());
+ QUntypedBindable bindable = metaProperty.bindable(&testedClass);
+
+ // Test basic property read and write
+ testedClass.setProperty(propertyName, QVariant::fromValue(data1));
+ QVERIFY2(testedClass.property(propertyName).template value<TestedData>() == data1, qPrintable(id));
+ QVERIFY2(spy.count() == 1, qPrintable(id + ", actual: " + QString::number(spy.count())));
+
+ // Test setting a binding as a source for the property
+ QProperty<TestedData> property1(data1);
+ QProperty<TestedData> property2(data2);
+ QVERIFY2(!bindable.hasBinding(), qPrintable(id));
+ bindable.setBinding(Qt::makePropertyBinding(property2));
+ QVERIFY2(bindable.hasBinding(), qPrintable(id));
+ // Check that the value also changed
+ QVERIFY2(testedClass.property(propertyName).template value<TestedData>() == data2, qPrintable(id));
+ QVERIFY2(spy.count() == 2, qPrintable(id + ", actual: " + QString::number(spy.count())));
+ // Same test but with a lambda binding (cast to be able to set the lambda directly)
+ QBindable<TestedData> *typedBindable = static_cast<QBindable<TestedData>*>(&bindable);
+ typedBindable->setBinding([&](){ return property1.value(); });
+ QVERIFY2(typedBindable->hasBinding(), qPrintable(id));
+ QVERIFY2(testedClass.property(propertyName).template value<TestedData>() == data1, qPrintable(id));
+ QVERIFY2(spy.count() == 3, qPrintable(id + ", actual: " + QString::number(spy.count())));
+
+ // Remove binding by setting a value directly
+ QVERIFY2(bindable.hasBinding(), qPrintable(id));
+ testedClass.setProperty(propertyName, QVariant::fromValue(data2));
+ QVERIFY2(testedClass.property(propertyName).template value<TestedData>() == data2, qPrintable(id));
+ QVERIFY2(!bindable.hasBinding(), qPrintable(id));
+ QVERIFY2(spy.count() == 4, qPrintable(id + ", actual: " + QString::number(spy.count())));
+
+ // Test using the property as the source in a binding
+ QProperty<bool> data1Used([&](){
+ return testedClass.property(propertyName).template value<TestedData>() == data1;
+ });
+ QVERIFY2(data1Used == false, qPrintable(id));
+ testedClass.setProperty(propertyName, QVariant::fromValue(data1));
+ QVERIFY2(data1Used == true, qPrintable(id));
+ }
};
void tst_scxmlqmlcpp::bindings() {
- // First create some statemachine instances
- std::unique_ptr<QScxmlStateMachine> sm0(nullptr);
- std::unique_ptr<QScxmlStateMachine> sm1(QScxmlStateMachine::fromFile("no_real_file_needed"));
- std::unique_ptr<QScxmlStateMachine> sm2(QScxmlStateMachine::fromFile("no_real_file_needed"));
-
// -- test eventconnection::stateMachine
QScxmlEventConnection eventConnection;
- QSignalSpy ecStateMachineSpy(&eventConnection, &QScxmlEventConnection::stateMachineChanged);
-
- // initially no state machine
- QVERIFY(eventConnection.bindableStateMachine().value() == nullptr);
- QCOMPARE(ecStateMachineSpy.count(), 0);
-
- // access state machine through getter/setter
- eventConnection.setStateMachine(sm1.get());
- QVERIFY(eventConnection.bindableStateMachine().value() == sm1.get());
- QVERIFY(eventConnection.stateMachine() == sm1.get());
- QCOMPARE(ecStateMachineSpy.count(), 1);
-
- // access state machine through properties
- eventConnection.setProperty("stateMachine", QVariant::fromValue(sm2.get()));
- QVERIFY(eventConnection.bindableStateMachine().value() == sm2.get());
- QVERIFY(eventConnection.property("stateMachine").value<QScxmlStateMachine*>() == sm2.get());
- QCOMPARE(ecStateMachineSpy.count(), 2);
-
- // set state machine through property binding
- QProperty<QScxmlStateMachine*> smp1;
- eventConnection.bindableStateMachine().setBinding(Qt::makePropertyBinding(smp1));
- QVERIFY(eventConnection.stateMachine() == nullptr);
- QCOMPARE(ecStateMachineSpy.count(), 3);
-
- // set state machine through lambda property binding
- QProperty<QScxmlStateMachine*> smp2(sm2.get());
- eventConnection.bindableStateMachine().setBinding([&](){ return smp2.value(); });
- QVERIFY(eventConnection.stateMachine() == sm2.get());
- QCOMPARE(ecStateMachineSpy.count(), 4);
-
- // remove binding by setting a value directly
- QVERIFY(eventConnection.bindableStateMachine().hasBinding());
- eventConnection.setStateMachine(nullptr);
- QVERIFY(!eventConnection.bindableStateMachine().hasBinding());
-
- // bind *to* the stateMachine property
- QProperty<bool> hasMachineProperty(false);
- QVERIFY(!hasMachineProperty.value()); // initially no state machine
- hasMachineProperty.setBinding([&](){ return eventConnection.stateMachine() ? true : false; });
- QVERIFY(!hasMachineProperty.value()); // still no state machine
- eventConnection.setStateMachine(sm1.get());
- QVERIFY(hasMachineProperty.value()); // a statemachine via binding
+ std::unique_ptr<QScxmlStateMachine> sm1(QScxmlStateMachine::fromFile("no_real_file_needed"));
+ std::unique_ptr<QScxmlStateMachine> sm2(QScxmlStateMachine::fromFile("no_real_file_needed"));
+ testWritableBindableBasics<QScxmlEventConnection, QScxmlStateMachine*>(
+ eventConnection, sm1.get(), sm2.get(), "stateMachine");
// -- test eventconnection::events
QStringList eventList1{{"event1"},{"event2"}};
QStringList eventList2{{"event3"},{"event4"}};
- QSignalSpy ecEventsSpy(&eventConnection, &QScxmlEventConnection::eventsChanged);
- QCOMPARE(eventConnection.events().count(), 0);
-
- // setter / getter access
- eventConnection.setEvents(eventList1);
- QCOMPARE(eventConnection.bindableEvents().value(), eventList1);
- QCOMPARE(eventConnection.events(), eventList1);
- QCOMPARE(ecEventsSpy.count(), 1);
-
- // property access
- eventConnection.setProperty("events", eventList2);
- QCOMPARE(eventConnection.bindableEvents().value(), eventList2);
- QCOMPARE(eventConnection.property("events"), eventList2);
- QCOMPARE(ecEventsSpy.count(), 2);
-
- // property binding updates
- QProperty<bool> toggle(true);
- QProperty<QStringList> evp1([&](){ return toggle ? eventList1 : eventList2;});
- eventConnection.bindableEvents().setBinding(Qt::makePropertyBinding(evp1));
- QCOMPARE(eventConnection.events(), eventList1);
- toggle = false;
- QCOMPARE(eventConnection.events(), eventList2);
- QCOMPARE(ecEventsSpy.count(), 4);
-
- // remove binding by setting value
- QVERIFY(eventConnection.bindableEvents().hasBinding());
- eventConnection.setEvents(eventList1);
- QVERIFY(!eventConnection.bindableEvents().hasBinding());
- QCOMPARE(ecEventsSpy.count(), 5);
-
- // bind *to* the events property
- QProperty<bool> hasEvents([&](){ return !eventConnection.events().isEmpty(); });
- QVERIFY(hasEvents);
- eventConnection.setEvents({});
- QVERIFY(!hasEvents);
- QCOMPARE(ecEventsSpy.count(), 6);
+ testWritableBindableBasics<QScxmlEventConnection, QStringList>(
+ eventConnection, eventList1, eventList2, "events");
+
+ // -- test invokedservices::statemachine
+ QScxmlInvokedServices invokedServices;
+ testWritableBindableBasics<QScxmlInvokedServices, QScxmlStateMachine*>(
+ invokedServices, sm1.get(), sm2.get(), "stateMachine");
+
+ // -- test invokedservices::children
+ TopMachine topSm;
+ invokedServices.setStateMachine(&topSm);
+ QCOMPARE(invokedServices.children().count(), 0);
+ QCOMPARE(topSm.invokedServices().count(), 0);
+
+ // at some point during the topSm execution there are 3 invoked services
+ // of the same name ('3' filters out as '1' at QML binding)
+ topSm.start();
+ QTRY_COMPARE(topSm.invokedServices().count(), 3);
+ QCOMPARE(invokedServices.children().count(), 1);
+
+ // after completion invoked services drop back to 0
+ QTRY_COMPARE(topSm.invokedServices().count(), 0);
+ QCOMPARE(invokedServices.children().count(), 0);
+
+ // bind *to* the invokedservices property and check that we observe same changes
+ // during the topSm execution
+ QProperty<qsizetype> serviceCounter;
+ serviceCounter.setBinding([&](){ return invokedServices.children().count(); });
+
+ QCOMPARE(serviceCounter, 0);
+ topSm.start();
+ QTRY_COMPARE(serviceCounter, 1);
+ QCOMPARE(topSm.invokedServices().count(), 3);
+
+ // -- test statemachineloader::initialValues
+ QScxmlStateMachineLoader stateMachineLoader;
+ QVariantMap values1{{"key1","value1"}, {"key2","value2"}};
+ QVariantMap values2{{"key3","value3"}, {"key4","value4"}};
+ testWritableBindableBasics<QScxmlStateMachineLoader, QVariantMap>(
+ stateMachineLoader, values1, values2, "initialValues");
+
+ // -- test statemachineloader::source
+ QUrl source1(QStringLiteral("qrc:///statemachine.scxml"));
+ QUrl source2(QStringLiteral("qrc:///topmachine.scxml"));
+ // The 'setSource' assumes a valid qml context, so we need to create a bit differently
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick\n; import QtScxml\n; Item { StateMachineLoader { objectName: \'sml\'; } }", QUrl());
+ std::unique_ptr<QObject> root(component.create());
+ QScxmlStateMachineLoader *sml = qobject_cast<QScxmlStateMachineLoader*>(root->findChild<QObject*>("sml"));
+ QVERIFY(sml != nullptr);
+ testWritableBindableBasics<QScxmlStateMachineLoader, QUrl>(*sml, source1, source2, "source");
+
+ // -- test statemachineloader::datamodel
+ QScxmlNullDataModel model1;
+ QScxmlNullDataModel model2;
+ testWritableBindableBasics<QScxmlStateMachineLoader,QScxmlDataModel*>
+ (stateMachineLoader, &model1, &model2, "dataModel");
+
+ // -- test statemachineloader::statemachine
+ // The statemachine can be indirectly set by setting the source
+ QSignalSpy smSpy(sml, &QScxmlStateMachineLoader::stateMachineChanged);
+ QUrl sourceNonexistent(QStringLiteral("qrc:///file_doesnt_exist.scxml"));
+ QUrl sourceBroken(QStringLiteral("qrc:///brokenstatemachine.scxml"));
+
+ QVERIFY(sml->stateMachine() != nullptr);
+ QTest::ignoreMessage(QtWarningMsg,
+ "<Unknown File>:3:11: QML StateMachineLoader: Cannot open 'qrc:///file_doesnt_exist.scxml' for reading.");
+ sml->setSource(sourceNonexistent);
+ QVERIFY(sml->stateMachine() == nullptr);
+ QCOMPARE(smSpy.count(), 1);
+ QTest::ignoreMessage(QtWarningMsg,
+ "<Unknown File>:3:11: QML StateMachineLoader: :/brokenstatemachine.scxml:59:1: error: initial state 'working' not found for <scxml> element");
+ QTest::ignoreMessage(QtWarningMsg,
+ "SCXML document has errors");
+ QTest::ignoreMessage(QtWarningMsg,
+ "<Unknown File>:3:11: QML StateMachineLoader: Something went wrong while parsing 'qrc:///brokenstatemachine.scxml':\n");
+ sml->setSource(sourceBroken);
+ QVERIFY(sml->stateMachine() == nullptr);
+ QCOMPARE(smSpy.count(), 1);
+
+ QProperty<bool> hasStateMachine([&](){ return sml->stateMachine() ? true : false; });
+ QVERIFY(hasStateMachine == false);
+ sml->setSource(source1);
+ QCOMPARE(smSpy.count(), 2);
+ QVERIFY(hasStateMachine == true);
}
QTEST_MAIN(tst_scxmlqmlcpp)