aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp')
-rw-r--r--tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp812
1 files changed, 0 insertions, 812 deletions
diff --git a/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp b/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp
deleted file mode 100644
index 3a754a28ca..0000000000
--- a/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp
+++ /dev/null
@@ -1,812 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <qtest.h>
-#include <QDebug>
-
-#include <QtCore/qscopedpointer.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlcomponent.h>
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmltypedata_p.h>
-
-#include "../../shared/util.h"
-
-#include <array>
-#include <memory>
-
-class tst_qmlcompiler_manual : public QQmlDataTest
-{
- Q_OBJECT
-
-private slots:
- void cppBinding();
- void signalHandlers();
- void signalHandlers_qmlcachegen();
- void jsFunctions();
- void changingBindings();
- void propertyAlias();
- void propertyChangeHandler();
- void propertyReturningFunction();
-
-private:
- void signalHandlers_impl(const QUrl &url);
-};
-
-// test workaround: hardcode runtime function indices. because they could be
-// rather unexpected and passing wrong ones leads to UB and flakiness.
-//
-// NB: if you update the QML files that are used by the QQmlEngine runtime
-// function execution, make sure that the hardcoded values are in sync with
-// those changes! An example of when things could go wrong: adding new, removing
-// old or changing the order of e.g. bindings on properties, signal handlers, JS
-// functions
-namespace FunctionIndices {
-static constexpr int HELLO_WORLD_GREETING_BINDING = 0;
-
-static constexpr int SIGNAL_HANDLERS_ON_SIGNAL1 = 1;
-static constexpr int SIGNAL_HANDLERS_ON_SIGNAL2 = 3;
-static constexpr int SIGNAL_HANDLERS_QML_EMIT_SIGNAL1 = 4;
-static constexpr int SIGNAL_HANDLERS_QML_EMIT_SIGNAL2 = 5;
-static constexpr int SIGNAL_HANDLERS_QML_EMIT_SIGNAL2_WITH_ARGS = 6;
-
-static constexpr int JS_FUNCTIONS_FUNC1 = 0;
-static constexpr int JS_FUNCTIONS_FUNC2 = 1;
-static constexpr int JS_FUNCTIONS_FUNC3 = 2;
-
-static constexpr int CHANGING_BINDINGS_P2_BINDING = 0;
-static constexpr int CHANGING_BINDINGS_RESET_TO_CONSTANT = 1;
-static constexpr int CHANGING_BINDINGS_RESET_TO_NEW_BINDING = 2;
-
-static constexpr int PROPERTY_ALIAS_ORIGIN_BINDING = 0;
-static constexpr int PROPERTY_ALIAS_RESET_ALIAS_TO_CONSTANT = 1;
-static constexpr int PROPERTY_ALIAS_RESET_ORIGIN_TO_CONSTANT = 2;
-static constexpr int PROPERTY_ALIAS_RESET_ALIAS_TO_NEW_BINDING = 3;
-static constexpr int PROPERTY_ALIAS_RESET_ORIGIN_TO_NEW_BINDING = 5;
-static constexpr int PROPERTY_ALIAS_GET_ALIAS_VALUE = 7;
-
-static constexpr int PROPERTY_CHANGE_HANDLER_P_BINDING = 0;
-static constexpr int PROPERTY_CHANGE_HANDLER_ON_P_CHANGED = 1;
-
-static constexpr int PROPERTY_RETURNING_FUNCTION_F_BINDING = 0;
-};
-
-// test utility function for type erasure. the "real" code would be
-// auto-generated by the compiler
-template<typename... IOArgs, size_t Size = sizeof...(IOArgs) + 1>
-static void typeEraseArguments(std::array<void *, Size> &a, std::array<QMetaType, Size-1> &t,
- IOArgs &&... args)
-{
- a = { /* return type */ nullptr, /* rest */
- const_cast<void *>(
- reinterpret_cast<const void *>(std::addressof(std::forward<IOArgs>(args))))... };
- t = {
- /* types */ QMetaType::fromType<std::decay_t<IOArgs>>()... };
-}
-
-class HelloWorld : public QObject
-{
- Q_OBJECT
- QML_NAMED_ELEMENT(HelloWorld);
- Q_PROPERTY(QString hello READ getHello WRITE setHello BINDABLE bindableHello)
- Q_PROPERTY(QString greeting READ getGreeting WRITE setGreeting BINDABLE bindableGreeting)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
-
- HelloWorld(QObject *parent = nullptr) : QObject(parent)
- {
- hello = QStringLiteral("Hello, World");
- QPropertyBinding<QString> HelloWorldCpp_greeting_binding(
- [&]() {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::HELLO_WORLD_GREETING_BINDING;
- return qjsvalue_cast<QString>(e->executeRuntimeFunction(url, index, this));
- },
- QT_PROPERTY_DEFAULT_BINDING_LOCATION);
- bindableGreeting().setBinding(HelloWorldCpp_greeting_binding);
- }
-
- QString getHello() { return hello.value(); }
- QString getGreeting() { return greeting.value(); }
-
- void setHello(const QString &hello_) { hello.setValue(hello_); }
- void setGreeting(const QString &greeting_) { greeting.setValue(greeting_); }
-
- QBindable<QString> bindableHello() { return QBindable<QString>(&hello); }
- QBindable<QString> bindableGreeting() { return QBindable<QString>(&greeting); }
-
- Q_OBJECT_BINDABLE_PROPERTY(HelloWorld, QString, hello);
- Q_OBJECT_BINDABLE_PROPERTY(HelloWorld, QString, greeting);
-};
-
-void tst_qmlcompiler_manual::cppBinding()
-{
- HelloWorld created;
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
- created.url = testFileUrl("HelloWorld.qml"); // workaround
-
- QCOMPARE(created.property("hello").toString(), QStringLiteral("Hello, World"));
- QCOMPARE(created.getGreeting(), QStringLiteral("Hello, World!"));
- QCOMPARE(created.property("greeting").toString(), QStringLiteral("Hello, World!"));
-
- created.setProperty("hello", QStringLiteral("Hello, Qml"));
-
- QCOMPARE(created.property("hello").toString(), QStringLiteral("Hello, Qml"));
- QCOMPARE(created.property("greeting").toString(), QStringLiteral("Hello, Qml!"));
- QCOMPARE(created.getGreeting(), QStringLiteral("Hello, Qml!"));
-}
-
-class ANON_signalHandlers : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int signal1P READ getSignal1P WRITE setSignal1P BINDABLE bindableSignal1P)
- Q_PROPERTY(QString signal2P1 READ getSignal2P1 WRITE setSignal2P1 BINDABLE bindableSignal2P1)
- Q_PROPERTY(int signal2P2 READ getSignal2P2 WRITE setSignal2P2 BINDABLE bindableSignal2P2)
- Q_PROPERTY(QString signal2P3 READ getSignal2P3 WRITE setSignal2P3 BINDABLE bindableSignal2P3)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
-
- ANON_signalHandlers(QObject *parent = nullptr) : QObject(parent)
- {
- signal1P = 0;
- signal2P1 = QStringLiteral("");
- signal2P2 = 0;
- signal2P3 = QStringLiteral("");
-
- QObject::connect(this, &ANON_signalHandlers::signal1, this,
- &ANON_signalHandlers::onSignal1);
- QObject::connect(this, &ANON_signalHandlers::signal2, this,
- &ANON_signalHandlers::onSignal2);
- }
-
- int getSignal1P() { return signal1P.value(); }
- QString getSignal2P1() { return signal2P1.value(); }
- int getSignal2P2() { return signal2P2.value(); }
- QString getSignal2P3() { return signal2P3.value(); }
-
- void setSignal1P(const int &signal1P_) { signal1P.setValue(signal1P_); }
- void setSignal2P1(const QString &signal2P1_) { signal2P1.setValue(signal2P1_); }
- void setSignal2P2(const int &signal2P2_) { signal2P2.setValue(signal2P2_); }
- void setSignal2P3(const QString &signal2P3_) { signal2P3.setValue(signal2P3_); }
-
- QBindable<int> bindableSignal1P() { return QBindable<int>(&signal1P); }
- QBindable<QString> bindableSignal2P1() { return QBindable<QString>(&signal2P1); }
- QBindable<int> bindableSignal2P2() { return QBindable<int>(&signal2P2); }
- QBindable<QString> bindableSignal2P3() { return QBindable<QString>(&signal2P3); }
-
- Q_OBJECT_BINDABLE_PROPERTY(ANON_signalHandlers, int, signal1P);
- Q_OBJECT_BINDABLE_PROPERTY(ANON_signalHandlers, QString, signal2P1);
- Q_OBJECT_BINDABLE_PROPERTY(ANON_signalHandlers, int, signal2P2);
- Q_OBJECT_BINDABLE_PROPERTY(ANON_signalHandlers, QString, signal2P3);
-
-signals:
- void signal1();
- void signal2(QString x, int y);
-
-public slots:
- void onSignal1()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::SIGNAL_HANDLERS_ON_SIGNAL1;
- e->executeRuntimeFunction(url, index, this);
- }
-
- void onSignal2(QString x, int y)
- {
- constexpr int argc = 2;
- std::array<void *, argc+1> a {};
- std::array<QMetaType, argc> t {};
- typeEraseArguments(a, t, x, y);
-
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const qsizetype index = FunctionIndices::SIGNAL_HANDLERS_ON_SIGNAL2;
- e->executeRuntimeFunction(url, index, this, argc, a.data(), t.data());
- }
-
-public:
- void qmlEmitSignal1()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::SIGNAL_HANDLERS_QML_EMIT_SIGNAL1;
- e->executeRuntimeFunction(url, index, this);
- }
-
- void qmlEmitSignal2()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::SIGNAL_HANDLERS_QML_EMIT_SIGNAL2;
- e->executeRuntimeFunction(url, index, this);
- }
-
- void qmlEmitSignal2WithArgs(QString x, int y)
- {
- constexpr int argc = 2;
- std::array<void *, argc+1> a {};
- std::array<QMetaType, argc> t {};
- typeEraseArguments(a, t, x, y);
-
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::SIGNAL_HANDLERS_QML_EMIT_SIGNAL2_WITH_ARGS;
- e->executeRuntimeFunction(url, index, this, argc, a.data(), t.data());
- }
-};
-
-void tst_qmlcompiler_manual::signalHandlers_impl(const QUrl &url)
-{
- ANON_signalHandlers created;
- created.url = url; // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- // signal emission works from C++
- emit created.signal1();
- emit created.signal2(QStringLiteral("42"), 42);
-
- QCOMPARE(created.property("signal1P").toInt(), 1);
- QCOMPARE(created.property("signal2P1").toString(), QStringLiteral("42"));
- QCOMPARE(created.property("signal2P2").toInt(), 42);
- QCOMPARE(created.property("signal2P3").toString(), QStringLiteral("4242"));
-
- // signal emission works through meta object system
- QMetaObject::invokeMethod(&created, "signal1");
- QMetaObject::invokeMethod(&created, "signal2", Q_ARG(QString, QStringLiteral("foo")),
- Q_ARG(int, 23));
-
- QCOMPARE(created.property("signal1P").toInt(), 2);
- QCOMPARE(created.property("signal2P1").toString(), QStringLiteral("foo"));
- QCOMPARE(created.property("signal2P2").toInt(), 23);
- QCOMPARE(created.property("signal2P3").toString(), QStringLiteral("foo23"));
-
- // signal emission works through QML/JS
- created.qmlEmitSignal1();
- created.qmlEmitSignal2();
-
- QCOMPARE(created.property("signal1P").toInt(), 3);
- QCOMPARE(created.property("signal2P1").toString(), QStringLiteral("xyz"));
- QCOMPARE(created.property("signal2P2").toInt(), 123);
- QCOMPARE(created.property("signal2P3").toString(), QStringLiteral("xyz123"));
-
- created.qmlEmitSignal2WithArgs(QStringLiteral("abc"), 0);
- QCOMPARE(created.property("signal2P1").toString(), QStringLiteral("abc"));
- QCOMPARE(created.property("signal2P2").toInt(), 0);
- QCOMPARE(created.property("signal2P3").toString(), QStringLiteral("abc0"));
-}
-
-void tst_qmlcompiler_manual::signalHandlers()
-{
- // use QQmlTypeCompiler's compilation unit
- signalHandlers_impl(testFileUrl("signalHandlers.qml"));
-}
-
-void tst_qmlcompiler_manual::signalHandlers_qmlcachegen()
-{
- // use qmlcachegen's compilation unit
- signalHandlers_impl(QUrl("qrc:/data/signalHandlers.qml"));
-}
-
-class ANON_javaScriptFunctions : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int func1P READ getFunc1P WRITE setFunc1P)
- Q_PROPERTY(QString func2P READ getFunc2P WRITE setFunc2P)
- Q_PROPERTY(bool func3P READ getFunc3P WRITE setFunc3P)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
-
- ANON_javaScriptFunctions(QObject *parent = nullptr) : QObject(parent)
- {
- func1P = 0;
- func2P = QStringLiteral("");
- func3P = false;
- }
-
- int getFunc1P() { return func1P.value(); }
- QString getFunc2P() { return func2P.value(); }
- bool getFunc3P() { return func3P.value(); }
-
- void setFunc1P(const int &func1P_) { func1P.setValue(func1P_); }
- void setFunc2P(const QString &func2P_) { func2P.setValue(func2P_); }
- void setFunc3P(const bool &func3P_) { func3P.setValue(func3P_); }
-
- // try if just QProperty works
- QProperty<int> func1P;
- QProperty<QString> func2P;
- QProperty<bool> func3P;
-
- void func1()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::JS_FUNCTIONS_FUNC1;
- e->executeRuntimeFunction(url, index, this);
- }
-
- void func2(QString x)
- {
- constexpr int argc = 1;
- std::array<void *, argc+1> a {};
- std::array<QMetaType, argc> t {};
- typeEraseArguments(a, t, x);
-
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::JS_FUNCTIONS_FUNC2;
- e->executeRuntimeFunction(url, index, this, argc, a.data(), t.data());
- }
-
- bool func3()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::JS_FUNCTIONS_FUNC3;
- return qjsvalue_cast<bool>(e->executeRuntimeFunction(url, index, this));
- }
-};
-
-void tst_qmlcompiler_manual::jsFunctions()
-{
- ANON_javaScriptFunctions created;
- created.url = testFileUrl("javaScriptFunctions.qml"); // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- created.func1();
- created.func2(QStringLiteral("abc"));
-
- QCOMPARE(created.property("func1P").toInt(), 1);
- QCOMPARE(created.property("func2P").toString(), QStringLiteral("abc"));
- QCOMPARE(created.func3(), false);
-
- created.setProperty("func3P", true);
- QCOMPARE(created.func3(), true);
-}
-
-class ANON_changingBindings : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int p1 READ getP1 WRITE setP1 BINDABLE bindableP1)
- Q_PROPERTY(int p2 READ getP2 WRITE setP2 BINDABLE bindableP2)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
- // test util to monitor binding execution
- int initialBindingCallCount = 0;
- // test util: allows to set C++ binding multiple times
- void resetToInitialBinding()
- {
- QPropertyBinding<int> ANON_changingBindings_p2_binding(
- [&]() {
- initialBindingCallCount++;
-
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::CHANGING_BINDINGS_P2_BINDING;
- return qjsvalue_cast<int>(e->executeRuntimeFunction(url, index, this));
- },
- QT_PROPERTY_DEFAULT_BINDING_LOCATION);
- bindableP2().setBinding(ANON_changingBindings_p2_binding);
- }
-
- ANON_changingBindings(QObject *parent = nullptr) : QObject(parent)
- {
- p1 = 1;
- resetToInitialBinding();
- }
-
- int getP1() { return p1.value(); }
- int getP2() { return p2.value(); }
-
- void setP1(int p1_) { p1.setValue(p1_); }
- void setP2(int p2_) { p2.setValue(p2_); }
-
- QBindable<int> bindableP1() { return QBindable<int>(&p1); }
- QBindable<int> bindableP2() { return QBindable<int>(&p2); }
-
- Q_OBJECT_BINDABLE_PROPERTY(ANON_changingBindings, int, p1);
- Q_OBJECT_BINDABLE_PROPERTY(ANON_changingBindings, int, p2);
-
- void resetToConstant()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::CHANGING_BINDINGS_RESET_TO_CONSTANT;
- e->executeRuntimeFunction(url, index, this);
- }
-
- void resetToNewBinding()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::CHANGING_BINDINGS_RESET_TO_NEW_BINDING;
- e->executeRuntimeFunction(url, index, this);
- }
-};
-
-void tst_qmlcompiler_manual::changingBindings()
-{
- ANON_changingBindings created;
- created.url = testFileUrl("changingBindings.qml"); // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- // test initial binding
- QCOMPARE(created.initialBindingCallCount, 0);
- QCOMPARE(created.property("p2").toInt(), 2); // p1 + 1
- QCOMPARE(created.initialBindingCallCount, 1); // lazy evaluation
-
- // test JS constant value
- created.resetToConstant();
- QCOMPARE(created.property("p2").toInt(), 42); // p2 = 42
- QCOMPARE(created.initialBindingCallCount, 1);
-
- // test Qt.binding()
- created.resetToNewBinding();
- created.setProperty("p1", 100);
- QCOMPARE(created.property("p2").toInt(), 200); // p1 * 2
- QCOMPARE(created.initialBindingCallCount, 1);
-
- // test setting initial (C++) binding
- created.setProperty("p1", 11);
- created.resetToInitialBinding();
- QCOMPARE(created.initialBindingCallCount, 1);
- QCOMPARE(created.property("p2").toInt(), 12); // p1 + 1 (again)
- QCOMPARE(created.initialBindingCallCount, 2);
-
- // test resetting value through C++
- created.setP2(0);
- created.setP1(-10);
-
- QCOMPARE(created.property("p2").toInt(), 0);
- QCOMPARE(created.initialBindingCallCount, 2);
-
- created.setProperty("p2", 1);
- QCOMPARE(created.property("p2").toInt(), 1);
- QCOMPARE(created.initialBindingCallCount, 2);
-
- // test binding can be set again even after reset from C++
- created.resetToNewBinding();
- QCOMPARE(created.property("p2").toInt(), -20);
- QCOMPARE(created.initialBindingCallCount, 2);
-}
-
-class ANON_propertyAlias : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int dummy READ getDummy WRITE setDummy NOTIFY dummyChanged)
- Q_PROPERTY(int origin READ getOrigin WRITE setOrigin BINDABLE bindableOrigin)
- Q_PROPERTY(int aliasToOrigin READ getAliasToOrigin WRITE setAliasToOrigin BINDABLE
- bindableAliasToOrigin)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
- // test util: allows to set C++ binding multiple times
- void resetToInitialBinding()
- {
- QPropertyBinding<int> ANON_propertyAlias_origin_binding(
- [&]() {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_ORIGIN_BINDING;
- return qjsvalue_cast<int>(e->executeRuntimeFunction(url, index, this));
- },
- QT_PROPERTY_DEFAULT_BINDING_LOCATION);
- bindableOrigin().setBinding(ANON_propertyAlias_origin_binding);
- }
-
- ANON_propertyAlias(QObject *parent = nullptr) : QObject(parent)
- {
- dummy = 12;
- resetToInitialBinding();
- }
-
- int getDummy() { return dummy.value(); }
- int getOrigin() { return origin.value(); }
- int getAliasToOrigin() { return getOrigin(); }
-
- void setDummy(int dummy_)
- {
- dummy.setValue(dummy_);
- // emit is essential for Qt.binding() to work correctly
- emit dummyChanged();
- }
- void setOrigin(int origin_) { origin.setValue(origin_); }
- void setAliasToOrigin(int aliasToOrigin_) { setOrigin(aliasToOrigin_); }
-
- QBindable<int> bindableOrigin() { return QBindable<int>(&origin); }
- QBindable<int> bindableAliasToOrigin() { return bindableOrigin(); }
-
- QProperty<int> dummy;
- QProperty<int> origin;
-
- void resetAliasToConstant()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_RESET_ALIAS_TO_CONSTANT;
- e->executeRuntimeFunction(url, index, this);
- }
- void resetOriginToConstant()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_RESET_ORIGIN_TO_CONSTANT;
- e->executeRuntimeFunction(url, index, this);
- }
- void resetAliasToNewBinding()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_RESET_ALIAS_TO_NEW_BINDING;
- e->executeRuntimeFunction(url, index, this);
- }
- void resetOriginToNewBinding()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_RESET_ORIGIN_TO_NEW_BINDING;
- e->executeRuntimeFunction(url, index, this);
- }
-
- int getAliasValue()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_ALIAS_GET_ALIAS_VALUE;
- return qjsvalue_cast<int>(e->executeRuntimeFunction(url, index, this));
- }
-
-signals:
- void dummyChanged();
-};
-
-void tst_qmlcompiler_manual::propertyAlias()
-{
- ANON_propertyAlias created;
- created.url = testFileUrl("propertyAlias.qml"); // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- // test initial binding
- QCOMPARE(created.property("origin").toInt(), 6); // dummy / 2
- QCOMPARE(created.property("aliasToOrigin").toInt(), 6);
-
- QCOMPARE(created.getAliasValue(), 6);
- QCOMPARE(created.getAliasToOrigin(), 6);
- created.setDummy(10);
- QCOMPARE(created.property("aliasToOrigin").toInt(), 5);
- QCOMPARE(created.getAliasValue(), 5);
- QCOMPARE(created.getAliasToOrigin(), 5);
-
- // test the C++ setter
- created.setOrigin(7);
- QCOMPARE(created.property("aliasToOrigin").toInt(), 7);
- QCOMPARE(created.getAliasValue(), 7);
- QCOMPARE(created.getAliasToOrigin(), 7);
-
- // test meta-object setter
- created.setProperty("origin", 1);
- QCOMPARE(created.property("aliasToOrigin").toInt(), 1);
- QCOMPARE(created.getAliasValue(), 1);
- QCOMPARE(created.getAliasToOrigin(), 1);
-
- // test QML/JS setter
- created.resetOriginToConstant();
- QCOMPARE(created.property("aliasToOrigin").toInt(), 189);
- QCOMPARE(created.getAliasValue(), 189);
- QCOMPARE(created.getAliasToOrigin(), 189);
-
- // test QML/JS alias setter
- created.resetAliasToConstant();
- QCOMPARE(created.property("origin").toInt(), 42);
- QCOMPARE(created.getOrigin(), 42);
- // check the alias just to make sure it also works
- QCOMPARE(created.property("aliasToOrigin").toInt(), 42);
- QCOMPARE(created.getAliasValue(), 42);
- QCOMPARE(created.getAliasToOrigin(), 42);
-
- // test QML/JS binding reset
- created.resetOriginToNewBinding(); // dummy
- created.setDummy(99);
- QCOMPARE(created.property("aliasToOrigin").toInt(), 99);
- QCOMPARE(created.getAliasValue(), 99);
- QCOMPARE(created.getAliasToOrigin(), 99);
-
- // test QML/JS binding reset through alias
- created.resetAliasToNewBinding(); // dummy * 3
- created.setDummy(-8);
- QCOMPARE(created.property("origin").toInt(), -24);
- QCOMPARE(created.getOrigin(), -24);
- QCOMPARE(created.property("aliasToOrigin").toInt(), -24);
- QCOMPARE(created.getAliasValue(), -24);
- QCOMPARE(created.getAliasToOrigin(), -24);
-}
-
-class ANON_propertyChangeHandler : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int dummy READ getDummy WRITE setDummy)
- Q_PROPERTY(int p READ getP WRITE setP BINDABLE bindableP)
- Q_PROPERTY(int watcher READ getWatcher WRITE setWatcher)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
-
- ANON_propertyChangeHandler(QObject *parent = nullptr) : QObject(parent)
- {
- dummy = 42;
- QPropertyBinding<int> ANON_propertyChangeHandler_p_binding(
- [&]() {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_CHANGE_HANDLER_P_BINDING;
- return qjsvalue_cast<int>(e->executeRuntimeFunction(url, index, this));
- },
- QT_PROPERTY_DEFAULT_BINDING_LOCATION);
- bindableP().setBinding(ANON_propertyChangeHandler_p_binding);
- watcher = 0;
-
- // NB: make sure property change handler appears after setBinding().
- // this prevents preliminary binding evaluation (which would fail as
- // this object doesn't yet know about qmlEngine(this))
- pChangeHandler.reset(new QPropertyChangeHandler<ANON_propertyChangeHandler_p_changeHandler>(
- bindableP().onValueChanged(ANON_propertyChangeHandler_p_changeHandler(this))));
- }
-
- int getDummy() { return dummy.value(); }
- int getP() { return p.value(); }
- int getWatcher() { return watcher.value(); }
-
- void setDummy(int dummy_) { dummy.setValue(dummy_); }
- void setP(int p_) { p.setValue(p_); }
- void setWatcher(int watcher_) { watcher.setValue(watcher_); }
-
- QBindable<int> bindableP() { return QBindable<int>(&p); }
-
- QProperty<int> dummy;
- QProperty<int> p;
- QProperty<int> watcher;
-
- // property change handler:
- struct ANON_propertyChangeHandler_p_changeHandler
- {
- ANON_propertyChangeHandler *This = nullptr;
- ANON_propertyChangeHandler_p_changeHandler(ANON_propertyChangeHandler *obj) : This(obj) { }
-
- void operator()()
- {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(This));
- const auto index = FunctionIndices::PROPERTY_CHANGE_HANDLER_ON_P_CHANGED;
- e->executeRuntimeFunction(This->url, index, This);
- }
- };
- // the handler object has to be alive as long as the object
- std::unique_ptr<QPropertyChangeHandler<ANON_propertyChangeHandler_p_changeHandler>>
- pChangeHandler;
-};
-
-void tst_qmlcompiler_manual::propertyChangeHandler()
-{
- ANON_propertyChangeHandler created;
- created.url = testFileUrl("propertyChangeHandler.qml"); // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- // test that fetching "dirty" property value doesn't trigger property change
- // handler
- QCOMPARE(created.getWatcher(), 0);
- QCOMPARE(created.getP(), 42); // due to binding
- QCOMPARE(created.getWatcher(), 0);
- QCOMPARE(created.property("watcher").toInt(), 0);
-
- // test that binding triggers property change handler
- created.setDummy(20);
- QCOMPARE(created.getWatcher(), 20);
- QCOMPARE(created.property("watcher").toInt(), 20);
-
- // test that property setting (through C++) triggers property change handler
- created.setWatcher(-100);
- created.setProperty("p", 18);
- QCOMPARE(created.getWatcher(), 18);
-
- // test that property setting triggers property change handler
- created.setWatcher(-47);
- created.setP(96);
- QCOMPARE(created.property("watcher").toInt(), 96);
-}
-
-class ANON_propertyReturningFunction : public QObject
-{
- Q_OBJECT
- QML_ANONYMOUS
- Q_PROPERTY(int counter READ getCounter WRITE setCounter)
- Q_PROPERTY(QVariant f READ getF WRITE setF BINDABLE bindableF)
-
-public:
- // test workaround: the url is resolved by the test base class, so use
- // member variable to store the resolved url used as argument in engine
- // evaluation of runtime functions
- QUrl url;
-
- ANON_propertyReturningFunction(QObject *parent = nullptr) : QObject(parent)
- {
- QPropertyBinding<QVariant> ANON_propertyReturningFunction_f_binding(
- [&]() {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(this));
- const auto index = FunctionIndices::PROPERTY_RETURNING_FUNCTION_F_BINDING;
- return qjsvalue_cast<QVariant>(e->executeRuntimeFunction(url, index, this));
- },
- QT_PROPERTY_DEFAULT_BINDING_LOCATION);
- bindableF().setBinding(ANON_propertyReturningFunction_f_binding);
- }
-
- int getCounter() { return counter.value(); }
- QVariant getF() { return f.value(); }
-
- void setCounter(int counter_) { counter.setValue(counter_); }
- void setF(QVariant f_) { f.setValue(f_); }
-
- QBindable<QVariant> bindableF() { return QBindable<QVariant>(&f); }
-
- QProperty<int> counter;
- QProperty<QVariant> f;
-};
-
-void tst_qmlcompiler_manual::propertyReturningFunction()
-{
- ANON_propertyReturningFunction created;
- created.url = testFileUrl("propertyReturningFunction.qml"); // workaround
- QQmlEngine e;
- e.setContextForObject(&created, e.rootContext());
-
- QCOMPARE(created.getCounter(), 0);
- QVariant function = created.getF();
- Q_UNUSED(function); // ignored as it can't be used currently
- QCOMPARE(created.getCounter(), 0);
-
- created.property("f");
- QCOMPARE(created.getCounter(), 0);
-}
-
-QTEST_MAIN(tst_qmlcompiler_manual)
-
-#include "tst_qmlcompiler_manual.moc"