Rearrange tests and C++ class definitions in tst_qmlcompiler_manual
Now that C++ class declarations moved into a header, there's little reason to have them diluted among the test cases, so move the test cases up and leave the rest below those Change-Id: Ia43423b27dc1f87b797abeeef5daae068314fb74 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
e4eabbbb10
commit
8d7d79e1ba
|
@ -68,6 +68,427 @@ private:
|
|||
void signalHandlers_impl(const QUrl &url);
|
||||
};
|
||||
|
||||
void tst_qmlcompiler_manual::cppBinding()
|
||||
{
|
||||
QQmlEngine e;
|
||||
HelloWorld::url = testFileUrl("HelloWorld.qml");
|
||||
HelloWorld created(&e);
|
||||
|
||||
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!"));
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::signalHandlers_impl(const QUrl &url)
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_signalHandlers::url = url;
|
||||
ANON_signalHandlers created(&e);
|
||||
|
||||
// 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:/QmltcManualTests/data/signalHandlers.qml"));
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::jsFunctions()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_javaScriptFunctions::url = testFileUrl("javaScriptFunctions.qml");
|
||||
ANON_javaScriptFunctions created(&e);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::changingBindings()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_changingBindings::url = testFileUrl("changingBindings.qml");
|
||||
ANON_changingBindings created(&e);
|
||||
|
||||
// test initial binding
|
||||
QCOMPARE(created.initialBindingCallCount, 1); // eager evaluation
|
||||
QCOMPARE(created.property("p2").toInt(), 2); // p1 + 1
|
||||
QCOMPARE(created.initialBindingCallCount, 1);
|
||||
|
||||
// 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, 2); // eager evaluation
|
||||
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);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::propertyAlias()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyAlias::url = testFileUrl("propertyAlias.qml");
|
||||
ANON_propertyAlias created(&e);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::propertyChangeHandler()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyChangeHandler::url = testFileUrl("propertyChangeHandler.qml");
|
||||
ANON_propertyChangeHandler created(&e);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::propertyReturningFunction()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyReturningFunction::url = testFileUrl("propertyReturningFunction.qml");
|
||||
ANON_propertyReturningFunction created(&e);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::locallyImported()
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
|
||||
LocallyImported created(&e);
|
||||
QCOMPARE(created.getCount(), 1);
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(&created);
|
||||
QVERIFY(ctx);
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("foo")), &created);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::localImport()
|
||||
{
|
||||
// NB: compare object creation compiler against QQmlComponent
|
||||
{
|
||||
QQmlEngine e;
|
||||
QQmlComponent comp(&e);
|
||||
comp.loadUrl(testFileUrl("localImport.qml"));
|
||||
QScopedPointer<QObject> root(comp.create());
|
||||
QVERIFY2(root, qPrintable(comp.errorString()));
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(root.get());
|
||||
QVERIFY(ctx);
|
||||
QVERIFY(ctx->parentContext());
|
||||
QCOMPARE(ctx->contextProperty("foo"), QVariant());
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("bar")), root.get());
|
||||
QCOMPARE(ctx->objectForName("foo"), nullptr);
|
||||
QCOMPARE(ctx->objectForName("bar"), root.get());
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent(), QQmlContextData::get(e.rootContext()));
|
||||
|
||||
int count = root->property("count").toInt();
|
||||
QVariant magicValue {};
|
||||
QMetaObject::invokeMethod(root.get(), "getMagicValue", Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
|
||||
count = root->property("count").toInt();
|
||||
magicValue = QVariant();
|
||||
QMetaObject::invokeMethod(root.get(), "localGetMagicValue",
|
||||
Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
}
|
||||
|
||||
// In this case, the context hierarchy is the following:
|
||||
// * LocallyImported: rootContext -> locallyImportedContext
|
||||
// * ANON_localImport: ... -> locallyImportedContext -> localImportContext
|
||||
//
|
||||
// this resembles the object hierarchy where LocallyImported is a base class
|
||||
// of ANON_localImport. having an explicit parent context (from
|
||||
// LocallyImported) guarantees that e.g. parent id / base class methods are
|
||||
// found during JavaScript (property) lookups
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
ANON_localImport::url = testFileUrl("localImport.qml");
|
||||
|
||||
ANON_localImport created(&e);
|
||||
QCOMPARE(created.getP1(), 41);
|
||||
QCOMPARE(created.getCount(), 42);
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(&created);
|
||||
QVERIFY(ctx);
|
||||
QVERIFY(ctx->parentContext());
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: 'foo' could actually be found in generated "
|
||||
"C++ base class context",
|
||||
Continue);
|
||||
QCOMPARE(ctx->contextProperty("foo"), QVariant());
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("bar")), &created);
|
||||
// NB: even though ctx->contextProperty("foo") finds the object,
|
||||
// objectForName("foo") still returns nullptr as "foo" exists in the
|
||||
// ctx->parent()
|
||||
QCOMPARE(ctx->objectForName("foo"), nullptr);
|
||||
QCOMPARE(ctx->objectForName("bar"), &created);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: LocallyImported is a _visible_ parent of "
|
||||
"ANON_localImport, same stays true for context",
|
||||
Continue);
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent()->parent(),
|
||||
QQmlContextData::get(e.rootContext()));
|
||||
|
||||
int count = created.getCount();
|
||||
QCOMPARE(created.getMagicValue().toInt(), (count * 3 + 1));
|
||||
count = created.getCount();
|
||||
QCOMPARE(created.localGetMagicValue().toInt(), (count * 3 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::neighbors()
|
||||
{
|
||||
{
|
||||
QQmlEngine e;
|
||||
QQmlComponent comp(&e);
|
||||
comp.loadUrl(testFileUrl("neighbors.qml"));
|
||||
QScopedPointer<QObject> root(comp.create());
|
||||
QVERIFY2(root, qPrintable(comp.errorString()));
|
||||
|
||||
auto rootCtx = QQmlContextData::get(e.contextForObject(root.get()));
|
||||
QQmlListReference children(root.get(), "data");
|
||||
QCOMPARE(children.size(), 2);
|
||||
auto child1Ctx = QQmlContextData::get(e.contextForObject(children.at(0)));
|
||||
auto child2Ctx = QQmlContextData::get(e.contextForObject(children.at(1)));
|
||||
|
||||
QCOMPARE(rootCtx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(child1Ctx, rootCtx);
|
||||
QCOMPARE(child2Ctx, rootCtx);
|
||||
QCOMPARE(child2Ctx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
|
||||
QQmlContext *rootQmlCtx = rootCtx->asQQmlContext();
|
||||
QCOMPARE(rootQmlCtx->objectForName("root"), root.get());
|
||||
QCOMPARE(rootQmlCtx->objectForName("child1"), children.at(0));
|
||||
QCOMPARE(rootQmlCtx->objectForName("child2"), children.at(1));
|
||||
}
|
||||
|
||||
// this case is different from tst_qmlcompiler_manual::localImport() as
|
||||
// LocallyImported is not a parent of a document root. Thus, the context
|
||||
// hierarchy:
|
||||
// * ANON_neighbors: rootContext -> neighborsContext
|
||||
// * ANON_neighbors_QtObject: rootContext -> neighborsContext
|
||||
// * LocallyImported: ... -> neighborsContext -> locallyImportedContext
|
||||
// * ANON_neighbors_LocallyImported: ... -> locallyImportedContext
|
||||
//
|
||||
// this should resemble the context hierarchy that QQmlObjectCreator
|
||||
// assembles, but here the outer context of ANON_neighbors_LocallyImported
|
||||
// remains to be the one from LocallyImported base class, which guarantees
|
||||
// that we can lookup stuff that originates from LocallyImported.
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
ANON_neighbors::url = testFileUrl("neighbors.qml");
|
||||
ANON_neighbors_QtObject::url = testFileUrl("neighbors.qml");
|
||||
ANON_neighbors_LocallyImported::url2 = testFileUrl("neighbors.qml");
|
||||
|
||||
ANON_neighbors created(&e);
|
||||
QQmlListReference children(&created, "data");
|
||||
QCOMPARE(children.size(), 2);
|
||||
ANON_neighbors_QtObject *child1 = qobject_cast<ANON_neighbors_QtObject *>(children.at(0));
|
||||
ANON_neighbors_LocallyImported *child2 =
|
||||
qobject_cast<ANON_neighbors_LocallyImported *>(children.at(1));
|
||||
QVERIFY(child1 && child2);
|
||||
|
||||
auto rootCtx = QQmlContextData::get(e.contextForObject(&created));
|
||||
auto child1Ctx = QQmlContextData::get(e.contextForObject(child1));
|
||||
auto child2Ctx = QQmlContextData::get(e.contextForObject(child2));
|
||||
|
||||
QCOMPARE(rootCtx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(child1Ctx, rootCtx);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: non-root object with generated C++ base has "
|
||||
"the context of that base",
|
||||
Continue);
|
||||
QCOMPARE(child2Ctx, rootCtx);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: non-root object with generated C++ base has "
|
||||
"the context of that base",
|
||||
Continue);
|
||||
QCOMPARE(child2Ctx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
// the rootCtx is actually a parent in this case
|
||||
QCOMPARE(child2Ctx->parent(), rootCtx);
|
||||
|
||||
QQmlContext *rootQmlCtx = rootCtx->asQQmlContext();
|
||||
QCOMPARE(rootQmlCtx->objectForName("root"), &created);
|
||||
QCOMPARE(rootQmlCtx->objectForName("child1"), child1);
|
||||
QCOMPARE(rootQmlCtx->objectForName("child2"), child2);
|
||||
|
||||
QCOMPARE(child1->getP(), 41);
|
||||
QCOMPARE(child1->getP2(), child2->getCount() * 2);
|
||||
QCOMPARE(child2->getP(), child1->getP() + 1);
|
||||
|
||||
child1->setP(44);
|
||||
QCOMPARE(child2->getP(), 45);
|
||||
|
||||
child2->setCount(4);
|
||||
QCOMPARE(child1->getP2(), 8);
|
||||
|
||||
int count = child2->getCount();
|
||||
QVariant magicValue {};
|
||||
QMetaObject::invokeMethod(child2, "getMagicValue", Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// test workaround: hardcode runtime function indices. because they could be
|
||||
// rather unexpected and passing wrong ones leads to UB and flakiness.
|
||||
//
|
||||
|
@ -218,23 +639,6 @@ HelloWorld::HelloWorld(QQmlEngine *e, QObject *parent)
|
|||
|
||||
QUrl HelloWorld::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::cppBinding()
|
||||
{
|
||||
QQmlEngine e;
|
||||
HelloWorld::url = testFileUrl("HelloWorld.qml");
|
||||
HelloWorld created(&e);
|
||||
|
||||
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!"));
|
||||
}
|
||||
|
||||
ANON_signalHandlers::ANON_signalHandlers(QQmlEngine *e, QObject *parent)
|
||||
: QObject(parent), ContextRegistrator(e, this)
|
||||
{
|
||||
|
@ -294,58 +698,6 @@ void ANON_signalHandlers::qmlEmitSignal2WithArgs(QString x, int y)
|
|||
|
||||
QUrl ANON_signalHandlers::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::signalHandlers_impl(const QUrl &url)
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_signalHandlers::url = url;
|
||||
ANON_signalHandlers created(&e);
|
||||
|
||||
// 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:/QmltcManualTests/data/signalHandlers.qml"));
|
||||
}
|
||||
|
||||
ANON_javaScriptFunctions::ANON_javaScriptFunctions(QQmlEngine *e, QObject *parent)
|
||||
: QObject(parent), ContextRegistrator(e, this)
|
||||
{
|
||||
|
@ -388,23 +740,6 @@ bool ANON_javaScriptFunctions::func3()
|
|||
|
||||
QUrl ANON_javaScriptFunctions::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::jsFunctions()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_javaScriptFunctions::url = testFileUrl("javaScriptFunctions.qml");
|
||||
ANON_javaScriptFunctions created(&e);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ANON_changingBindings::resetToInitialBinding()
|
||||
{
|
||||
QPropertyBinding<int> ANON_changingBindings_p2_binding(
|
||||
|
@ -448,52 +783,6 @@ void ANON_changingBindings::resetToNewBinding()
|
|||
|
||||
QUrl ANON_changingBindings::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::changingBindings()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_changingBindings::url = testFileUrl("changingBindings.qml");
|
||||
ANON_changingBindings created(&e);
|
||||
|
||||
// test initial binding
|
||||
QCOMPARE(created.initialBindingCallCount, 1); // eager evaluation
|
||||
QCOMPARE(created.property("p2").toInt(), 2); // p1 + 1
|
||||
QCOMPARE(created.initialBindingCallCount, 1);
|
||||
|
||||
// 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, 2); // eager evaluation
|
||||
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);
|
||||
}
|
||||
|
||||
void ANON_propertyAlias::resetToInitialBinding()
|
||||
{
|
||||
QPropertyBinding<int> ANON_propertyAlias_origin_binding(
|
||||
|
@ -559,67 +848,6 @@ int ANON_propertyAlias::getAliasValue()
|
|||
|
||||
QUrl ANON_propertyAlias::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::propertyAlias()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyAlias::url = testFileUrl("propertyAlias.qml");
|
||||
ANON_propertyAlias created(&e);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
ANON_propertyChangeHandler::ANON_propertyChangeHandler(QQmlEngine *e, QObject *parent)
|
||||
: QObject(parent), ContextRegistrator(e, this)
|
||||
{
|
||||
|
@ -662,35 +890,6 @@ void ANON_propertyChangeHandler::ANON_propertyChangeHandler_p_changeHandler::ope
|
|||
|
||||
QUrl ANON_propertyChangeHandler::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::propertyChangeHandler()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyChangeHandler::url = testFileUrl("propertyChangeHandler.qml");
|
||||
ANON_propertyChangeHandler created(&e);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
ANON_propertyReturningFunction::ANON_propertyReturningFunction(QQmlEngine *e, QObject *parent)
|
||||
: QObject(parent), ContextRegistrator(e, this)
|
||||
{
|
||||
|
@ -712,21 +911,6 @@ ANON_propertyReturningFunction::ANON_propertyReturningFunction(QQmlEngine *e, QO
|
|||
|
||||
QUrl ANON_propertyReturningFunction::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::propertyReturningFunction()
|
||||
{
|
||||
QQmlEngine e;
|
||||
ANON_propertyReturningFunction::url = testFileUrl("propertyReturningFunction.qml");
|
||||
ANON_propertyReturningFunction created(&e);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LocallyImported::LocallyImported(QObject *parent) : QObject(parent) { }
|
||||
|
||||
LocallyImported::LocallyImported(QQmlEngine *e, QObject *parent) : LocallyImported(parent)
|
||||
|
@ -866,96 +1050,6 @@ Q_INVOKABLE QVariant ANON_localImport::localGetMagicValue()
|
|||
|
||||
QUrl ANON_localImport::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::locallyImported()
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
|
||||
LocallyImported created(&e);
|
||||
QCOMPARE(created.getCount(), 1);
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(&created);
|
||||
QVERIFY(ctx);
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("foo")), &created);
|
||||
}
|
||||
|
||||
void tst_qmlcompiler_manual::localImport()
|
||||
{
|
||||
// NB: compare object creation compiler against QQmlComponent
|
||||
{
|
||||
QQmlEngine e;
|
||||
QQmlComponent comp(&e);
|
||||
comp.loadUrl(testFileUrl("localImport.qml"));
|
||||
QScopedPointer<QObject> root(comp.create());
|
||||
QVERIFY2(root, qPrintable(comp.errorString()));
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(root.get());
|
||||
QVERIFY(ctx);
|
||||
QVERIFY(ctx->parentContext());
|
||||
QCOMPARE(ctx->contextProperty("foo"), QVariant());
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("bar")), root.get());
|
||||
QCOMPARE(ctx->objectForName("foo"), nullptr);
|
||||
QCOMPARE(ctx->objectForName("bar"), root.get());
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent(), QQmlContextData::get(e.rootContext()));
|
||||
|
||||
int count = root->property("count").toInt();
|
||||
QVariant magicValue {};
|
||||
QMetaObject::invokeMethod(root.get(), "getMagicValue", Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
|
||||
count = root->property("count").toInt();
|
||||
magicValue = QVariant();
|
||||
QMetaObject::invokeMethod(root.get(), "localGetMagicValue",
|
||||
Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
}
|
||||
|
||||
// In this case, the context hierarchy is the following:
|
||||
// * LocallyImported: rootContext -> locallyImportedContext
|
||||
// * ANON_localImport: ... -> locallyImportedContext -> localImportContext
|
||||
//
|
||||
// this resembles the object hierarchy where LocallyImported is a base class
|
||||
// of ANON_localImport. having an explicit parent context (from
|
||||
// LocallyImported) guarantees that e.g. parent id / base class methods are
|
||||
// found during JavaScript (property) lookups
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
ANON_localImport::url = testFileUrl("localImport.qml");
|
||||
|
||||
ANON_localImport created(&e);
|
||||
QCOMPARE(created.getP1(), 41);
|
||||
QCOMPARE(created.getCount(), 42);
|
||||
|
||||
QQmlContext *ctx = e.contextForObject(&created);
|
||||
QVERIFY(ctx);
|
||||
QVERIFY(ctx->parentContext());
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: 'foo' could actually be found in generated "
|
||||
"C++ base class context",
|
||||
Continue);
|
||||
QCOMPARE(ctx->contextProperty("foo"), QVariant());
|
||||
QCOMPARE(qvariant_cast<QObject *>(ctx->contextProperty("bar")), &created);
|
||||
// NB: even though ctx->contextProperty("foo") finds the object,
|
||||
// objectForName("foo") still returns nullptr as "foo" exists in the
|
||||
// ctx->parent()
|
||||
QCOMPARE(ctx->objectForName("foo"), nullptr);
|
||||
QCOMPARE(ctx->objectForName("bar"), &created);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: LocallyImported is a _visible_ parent of "
|
||||
"ANON_localImport, same stays true for context",
|
||||
Continue);
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(QQmlContextData::get(ctx)->parent()->parent(),
|
||||
QQmlContextData::get(e.rootContext()));
|
||||
|
||||
int count = created.getCount();
|
||||
QCOMPARE(created.getMagicValue().toInt(), (count * 3 + 1));
|
||||
count = created.getCount();
|
||||
QCOMPARE(created.localGetMagicValue().toInt(), (count * 3 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
ANON_neighbors_QtObject::ANON_neighbors_QtObject(QObject *parent) : QObject(parent) { }
|
||||
|
||||
ANON_neighbors_QtObject::ANON_neighbors_QtObject(QQmlEngine *e, QObject *parent)
|
||||
|
@ -1110,100 +1204,6 @@ void ANON_neighbors::finalize(QQmlEngine *e)
|
|||
|
||||
QUrl ANON_neighbors::url = QUrl(); // workaround
|
||||
|
||||
void tst_qmlcompiler_manual::neighbors()
|
||||
{
|
||||
{
|
||||
QQmlEngine e;
|
||||
QQmlComponent comp(&e);
|
||||
comp.loadUrl(testFileUrl("neighbors.qml"));
|
||||
QScopedPointer<QObject> root(comp.create());
|
||||
QVERIFY2(root, qPrintable(comp.errorString()));
|
||||
|
||||
auto rootCtx = QQmlContextData::get(e.contextForObject(root.get()));
|
||||
QQmlListReference children(root.get(), "data");
|
||||
QCOMPARE(children.size(), 2);
|
||||
auto child1Ctx = QQmlContextData::get(e.contextForObject(children.at(0)));
|
||||
auto child2Ctx = QQmlContextData::get(e.contextForObject(children.at(1)));
|
||||
|
||||
QCOMPARE(rootCtx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(child1Ctx, rootCtx);
|
||||
QCOMPARE(child2Ctx, rootCtx);
|
||||
QCOMPARE(child2Ctx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
|
||||
QQmlContext *rootQmlCtx = rootCtx->asQQmlContext();
|
||||
QCOMPARE(rootQmlCtx->objectForName("root"), root.get());
|
||||
QCOMPARE(rootQmlCtx->objectForName("child1"), children.at(0));
|
||||
QCOMPARE(rootQmlCtx->objectForName("child2"), children.at(1));
|
||||
}
|
||||
|
||||
// this case is different from tst_qmlcompiler_manual::localImport() as
|
||||
// LocallyImported is not a parent of a document root. Thus, the context
|
||||
// hierarchy:
|
||||
// * ANON_neighbors: rootContext -> neighborsContext
|
||||
// * ANON_neighbors_QtObject: rootContext -> neighborsContext
|
||||
// * LocallyImported: ... -> neighborsContext -> locallyImportedContext
|
||||
// * ANON_neighbors_LocallyImported: ... -> locallyImportedContext
|
||||
//
|
||||
// this should resemble the context hierarchy that QQmlObjectCreator
|
||||
// assembles, but here the outer context of ANON_neighbors_LocallyImported
|
||||
// remains to be the one from LocallyImported base class, which guarantees
|
||||
// that we can lookup stuff that originates from LocallyImported.
|
||||
{
|
||||
QQmlEngine e;
|
||||
LocallyImported::url = testFileUrl("LocallyImported.qml");
|
||||
ANON_neighbors::url = testFileUrl("neighbors.qml");
|
||||
ANON_neighbors_QtObject::url = testFileUrl("neighbors.qml");
|
||||
ANON_neighbors_LocallyImported::url2 = testFileUrl("neighbors.qml");
|
||||
|
||||
ANON_neighbors created(&e);
|
||||
QQmlListReference children(&created, "data");
|
||||
QCOMPARE(children.size(), 2);
|
||||
ANON_neighbors_QtObject *child1 = qobject_cast<ANON_neighbors_QtObject *>(children.at(0));
|
||||
ANON_neighbors_LocallyImported *child2 =
|
||||
qobject_cast<ANON_neighbors_LocallyImported *>(children.at(1));
|
||||
QVERIFY(child1 && child2);
|
||||
|
||||
auto rootCtx = QQmlContextData::get(e.contextForObject(&created));
|
||||
auto child1Ctx = QQmlContextData::get(e.contextForObject(child1));
|
||||
auto child2Ctx = QQmlContextData::get(e.contextForObject(child2));
|
||||
|
||||
QCOMPARE(rootCtx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
QCOMPARE(child1Ctx, rootCtx);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: non-root object with generated C++ base has "
|
||||
"the context of that base",
|
||||
Continue);
|
||||
QCOMPARE(child2Ctx, rootCtx);
|
||||
QEXPECT_FAIL("",
|
||||
"Inconsistent with QQmlComponent: non-root object with generated C++ base has "
|
||||
"the context of that base",
|
||||
Continue);
|
||||
QCOMPARE(child2Ctx->parent(), QQmlContextData::get(e.rootContext()));
|
||||
// the rootCtx is actually a parent in this case
|
||||
QCOMPARE(child2Ctx->parent(), rootCtx);
|
||||
|
||||
QQmlContext *rootQmlCtx = rootCtx->asQQmlContext();
|
||||
QCOMPARE(rootQmlCtx->objectForName("root"), &created);
|
||||
QCOMPARE(rootQmlCtx->objectForName("child1"), child1);
|
||||
QCOMPARE(rootQmlCtx->objectForName("child2"), child2);
|
||||
|
||||
QCOMPARE(child1->getP(), 41);
|
||||
QCOMPARE(child1->getP2(), child2->getCount() * 2);
|
||||
QCOMPARE(child2->getP(), child1->getP() + 1);
|
||||
|
||||
child1->setP(44);
|
||||
QCOMPARE(child2->getP(), 45);
|
||||
|
||||
child2->setCount(4);
|
||||
QCOMPARE(child1->getP2(), 8);
|
||||
|
||||
int count = child2->getCount();
|
||||
QVariant magicValue {};
|
||||
QMetaObject::invokeMethod(child2, "getMagicValue", Q_RETURN_ARG(QVariant, magicValue));
|
||||
QCOMPARE(magicValue.toInt(), (count * 3 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qmlcompiler_manual)
|
||||
|
||||
#include "tst_qmlcompiler_manual.moc"
|
||||
|
|
Loading…
Reference in New Issue