summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@insta.fi>2021-03-05 11:57:30 +0200
committerJuha Vuolle <juha.vuolle@insta.fi>2021-05-03 13:52:02 +0300
commit61dbf282ba718771e432dfbbd618cad2dc728c5b (patch)
tree5253b37274276d1dd65df4d12e2a7d90c676af7e /tests/auto
parent4e28b3753e297541baaa45ef6c5651989ff7ce82 (diff)
QtScxml QML-facing properties bindable support additions part 1
This commit adds the bindable support to following QScxmlStateMachine properties: initialized, initialValues, loader, dataModel and tableData Task-number: QTBUG-89895 Change-Id: I33545d9d45a4fbf52a4a220d559b7ee75351a268 Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/shared/bindableutils.h52
-rw-r--r--tests/auto/statemachine/tst_statemachine.cpp60
2 files changed, 112 insertions, 0 deletions
diff --git a/tests/auto/shared/bindableutils.h b/tests/auto/shared/bindableutils.h
index 6e9f657..4a45f89 100644
--- a/tests/auto/shared/bindableutils.h
+++ b/tests/auto/shared/bindableutils.h
@@ -33,6 +33,57 @@
#include <QObject>
// This is a helper function to test basics of typical bindable
+// properties that are read-only (but can change) 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
+// "data0" is the initial datavalue
+// "data1" is an instance of the propertydata and must differ from data0
+// "propertyName" is the name of the property we are interested in testing
+// "modifierFunction" that does whatever is needed to change the underlying property
+// A custom "dataComparator" can be provided for cases that the data doesn't have operator==
+template<typename TestedClass, typename TestedData>
+void testReadableBindableBasics(TestedClass& testedClass, TestedData data0, TestedData data1,
+ const char* propertyName,
+ std::function<void()> modifierFunction = [](){ qWarning() << "Error, data modifier function must be provided"; },
+ std::function<bool(TestedData,TestedData)> dataComparator = [](TestedData d1, TestedData d2) { return d1 == d2; })
+{
+ // 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(propertyName);
+
+ // Fail gracefully if preconditions to use this helper function are not met:
+ QVERIFY2(metaProperty.isBindable() && metaProperty.hasNotifySignal(), qPrintable(id));
+ QVERIFY2(modifierFunction, qPrintable(id));
+ // Create a signal spy for the property changed -signal
+ QSignalSpy spy(&testedClass, metaProperty.notifySignal());
+ QUntypedBindable bindable = metaProperty.bindable(&testedClass);
+
+ // Verify initial data is as expected
+ QVERIFY2(dataComparator(testedClass.property(propertyName).template value<TestedData>(), data0), qPrintable(id));
+ // Use the property as the source in a binding
+ QProperty<bool> data1Used([&](){
+ return dataComparator(testedClass.property(propertyName).template value<TestedData>(), data1);
+ });
+ // Verify binding's initial state
+ QVERIFY2(data1Used == false, qPrintable(id));
+ // Call the supplied modifier function and verify that the value and binding both change
+ modifierFunction();
+ QVERIFY2(data1Used == true, qPrintable(id));
+ QVERIFY2(dataComparator(testedClass.property(propertyName).template value<TestedData>(), data1), qPrintable(id));
+ QVERIFY2(spy.count() == 1, qPrintable(id + ", actual: " + QString::number(spy.count())));
+}
+
+
+// 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
@@ -44,6 +95,7 @@
// The "data1" and "data2" must differ from one another, and
// the "data1" must differ from instance property's initial state
// "propertyName" is the name of the property we are interested in testing
+// A custom "dataComparator" can be provided for cases that the data doesn't have operator==
template<typename TestedClass, typename TestedData>
void testWritableBindableBasics(TestedClass& testedClass, TestedData data1,
TestedData data2, const char* propertyName,
diff --git a/tests/auto/statemachine/tst_statemachine.cpp b/tests/auto/statemachine/tst_statemachine.cpp
index a7464b3..03b30d6 100644
--- a/tests/auto/statemachine/tst_statemachine.cpp
+++ b/tests/auto/statemachine/tst_statemachine.cpp
@@ -33,6 +33,9 @@
#include <QtScxml/qscxmlstatemachine.h>
#include <QtScxml/qscxmlinvokableservice.h>
#include <QtScxml/private/qscxmlstatemachine_p.h>
+#include <QtScxml/QScxmlNullDataModel>
+
+#include "../shared/bindableutils.h"
enum { SpyWaitTime = 8000 };
@@ -57,6 +60,8 @@ private Q_SLOTS:
void multipleInvokableServices(); // QTBUG-61484
void logWithoutExpr();
+
+ void bindings();
};
void tst_StateMachine::stateNames_data()
@@ -455,6 +460,61 @@ void tst_StateMachine::logWithoutExpr()
QTRY_COMPARE(logSpy.count(), 1);
}
+void tst_StateMachine::bindings()
+{
+ // -- QScxmlStateMachine::initialized
+ std::unique_ptr<QScxmlStateMachine> stateMachine1(
+ QScxmlStateMachine::fromFile(QString(":/tst_statemachine/invoke.scxml")));
+ QVERIFY(stateMachine1.get());
+ testReadableBindableBasics<QScxmlStateMachine, bool>(
+ *stateMachine1, false, true, "initialized", [&](){ stateMachine1.get()->start(); });
+
+ // -- QScxmlStateMachine::initialValues
+ QVariantMap map1{{"map", 1}};
+ QVariantMap map2{{"map", 2}};
+ testWritableBindableBasics<QScxmlStateMachine, QVariantMap>(
+ *stateMachine1, map1, map2, "initialValues");
+
+ // -- QScxmlStateMachine::loader
+ class MockLoader: public QScxmlCompiler::Loader
+ {
+ public:
+ QByteArray load(const QString&, const QString&, QStringList*) override { return QByteArray(); }
+ };
+ MockLoader loader1;
+ MockLoader loader2;
+ testWritableBindableBasics<QScxmlStateMachine, QScxmlCompiler::Loader*>(
+ *stateMachine1, &loader1, &loader2, "loader");
+
+ // -- QScxmlStateMachine::dataModel
+ // Use non-existent file below, as valid file would initialize the model
+ std::unique_ptr<QScxmlStateMachine> stateMachine2(
+ QScxmlStateMachine::fromFile(QString("not_a_real_file")));
+ std::unique_ptr<QScxmlStateMachine> stateMachine3(
+ QScxmlStateMachine::fromFile(QString("not_a_real_file")));
+ QScxmlNullDataModel model1;
+ QScxmlNullDataModel model2;
+ // Use the "readable" test helper as the data can only change once
+ testReadableBindableBasics<QScxmlStateMachine, QScxmlDataModel*>(
+ *stateMachine2, nullptr, &model1, "dataModel",
+ [&](){ stateMachine2->setDataModel(&model1); });
+ // verify that setting the model twice will not break the binding (setting is ignored)
+ QProperty<QScxmlDataModel*> modelProperty(&model1);
+ stateMachine3.get()->bindableDataModel().setBinding(Qt::makePropertyBinding(modelProperty));
+ QVERIFY(stateMachine3.get()->bindableDataModel().hasBinding());
+ QVERIFY(stateMachine3.get()->dataModel() == &model1);
+ stateMachine3.get()->setDataModel(&model2); // should be ignored
+ QVERIFY(stateMachine3.get()->dataModel() == &model1);
+ QVERIFY(stateMachine3.get()->bindableDataModel().hasBinding());
+
+ // -- QScxmlStateMachine::tableData
+ // Use the statemachine to generate the tabledDatas for testing
+ std::unique_ptr<QScxmlStateMachine> stateMachine4(
+ QScxmlStateMachine::fromFile(QString(":/tst_statemachine/invoke.scxml")));
+ testWritableBindableBasics<QScxmlStateMachine, QScxmlTableData*>(
+ *stateMachine2, stateMachine1.get()->tableData(), stateMachine4.get()->tableData(), "tableData");
+}
+
QTEST_MAIN(tst_StateMachine)
#include "tst_statemachine.moc"