aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmlecmascript
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmlecmascript')
-rw-r--r--tests/auto/qml/qqmlecmascript/BLACKLIST2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs2.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qpropertyBindingNoQPropertyCapture.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp133
8 files changed, 218 insertions, 6 deletions
diff --git a/tests/auto/qml/qqmlecmascript/BLACKLIST b/tests/auto/qml/qqmlecmascript/BLACKLIST
deleted file mode 100644
index bd25566eef..0000000000
--- a/tests/auto/qml/qqmlecmascript/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[gcCrashRegressionTest]
-macos arm
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml b/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml
new file mode 100644
index 0000000000..17116bb091
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml
@@ -0,0 +1,11 @@
+import QtQml
+
+
+QtObject {
+ id: root
+
+ component Test : QtObject {}
+
+ property alias myalias: other
+ property var direct: Test { id: other }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js
new file mode 100644
index 0000000000..f51ab662ab
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js
@@ -0,0 +1,29 @@
+function init() {
+ Array.prototype.doPush = Array.prototype.push
+}
+
+function nasty() {
+ var sc_Vector = Array;
+ var push = sc_Vector.prototype.doPush;
+
+ // Change the memberData to hold something nasty on the current internalClass
+ sc_Vector.prototype.doPush = 5;
+
+ // Trigger a re-allocation of memberData
+ for (var i = 0; i < 256; ++i)
+ sc_Vector.prototype[i + "string"] = function() { return 98; }
+
+ // Change the (new) memberData back, to hold our doPush function again.
+ // This should propagate a protoId change all the way up to the lookup.
+ sc_Vector.prototype.doPush = push;
+}
+
+function func() {
+ var b = [];
+
+ // This becomes a lookup internally, which stores protoId and a pointer
+ // into the memberData. It should get invalidated when memberData is re-allocated.
+ b.doPush(3);
+
+ return b;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml
new file mode 100644
index 0000000000..e313770bf5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml
@@ -0,0 +1,13 @@
+import QtQml
+
+import "internalClassParentGc.js" as Foo
+
+QtObject {
+ Component.onCompleted: {
+ gc();
+ Foo.init();
+ Foo.func();
+ Foo.nasty();
+ objectName = Foo.func()[0];
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs.qml b/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs.qml
new file mode 100644
index 0000000000..7f1b5b0317
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs.qml
@@ -0,0 +1,8 @@
+import QtQml
+
+QtObject {
+ id: root
+ required property QtObject invokableObject
+
+ Component.onCompleted: root.invokableObject.method_QObject(Component)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs2.qml b/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs2.qml
new file mode 100644
index 0000000000..1904740b26
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qmlTypeWrapperArgs2.qml
@@ -0,0 +1,9 @@
+import QtQml
+import QtQml as NS
+
+QtObject {
+ id: root
+ required property QtObject invokableObject
+
+ Component.onCompleted: root.invokableObject.method_QObject(NS)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qpropertyBindingNoQPropertyCapture.qml b/tests/auto/qml/qqmlecmascript/data/qpropertyBindingNoQPropertyCapture.qml
new file mode 100644
index 0000000000..d3a151efe3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qpropertyBindingNoQPropertyCapture.qml
@@ -0,0 +1,19 @@
+import QtQuick
+
+Item {
+ objectName: "redRectangle"
+ id: redRectangle
+
+ property bool b: false
+ function toggle() { b = !b }
+ width: b ? 600 : 500
+
+ Item {
+ id: blueRectangle
+ objectName: "blueRectangle"
+ // width: b ? (100 + redRectangle.width / 2) : 25
+ width: b ? redRectangle.width : 25
+ }
+
+ property int blueRectangleWidth: blueRectangle.width
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 7ea5ef6e4b..4beedc4e88 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -119,6 +119,7 @@ private slots:
void outerBindingOverridesInnerBinding();
void aliasPropertyAndBinding();
void aliasPropertyReset();
+ void aliasPropertyToIC();
void nonExistentAttachedObject();
void scope();
void importScope();
@@ -315,6 +316,7 @@ private slots:
void bindingBoundFunctions();
void qpropertyAndQtBinding();
void qpropertyBindingReplacement();
+ void qpropertyBindingNoQPropertyCapture();
void deleteRootObjectInCreation();
void onDestruction();
void onDestructionViaGC();
@@ -409,6 +411,7 @@ private slots:
void urlConstruction();
void urlPropertyInvalid();
void urlPropertySet();
+ void colonAfterProtocol();
void urlSearchParamsConstruction();
void urlSearchParamsMethods();
void variantConversionMethod();
@@ -430,6 +433,8 @@ private slots:
void functionNameInFunctionScope();
void functionAsDefaultArgument();
+ void internalClassParentGc();
+
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
static void verifyContextLifetime(const QQmlRefPointer<QQmlContextData> &ctxt);
@@ -1932,6 +1937,24 @@ void tst_qqmlecmascript::aliasPropertyReset()
QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
}
+void tst_qqmlecmascript::aliasPropertyToIC()
+{
+ QQmlEngine engine;
+ std::unique_ptr<QObject> root;
+
+ // test that a manual write (of undefined) to a resettable aliased property succeeds
+ QQmlComponent c(&engine, testFileUrl("aliasPropertyToIC.qml"));
+ root.reset(c.create());
+ QVERIFY(root);
+ auto mo = root->metaObject();
+ int aliasIndex = mo->indexOfProperty("myalias");
+ auto prop = mo->property(aliasIndex);
+ QVERIFY(prop.isAlias());
+ auto fromAlias = prop.read(root.get()).value<QObject *>();
+ auto direct = root->property("direct").value<QObject *>();
+ QCOMPARE(fromAlias, direct);
+}
+
void tst_qqmlecmascript::componentCreation_data()
{
QTest::addColumn<QString>("method");
@@ -3144,6 +3167,26 @@ void tst_qqmlecmascript::callQtInvokables()
QCOMPARE(o->actuals().count(), 1);
QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr));
+ {
+ o->reset();
+ QQmlComponent comp(&qmlengine, testFileUrl("qmlTypeWrapperArgs.qml"));
+ QScopedPointer<QObject> root {comp.createWithInitialProperties({{"invokableObject", QVariant::fromValue(o)}}) };
+ QVERIFY(root);
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), 13);
+ QCOMPARE(o->actuals().count(), 1);
+ QCOMPARE(o->actuals().at(0).value<QObject *>()->metaObject()->className(), "QQmlComponentAttached");
+ }
+
+ {
+ o->reset();
+ QQmlComponent comp(&qmlengine, testFileUrl("qmlTypeWrapperArgs2.qml"));
+ QScopedPointer<QObject> root {comp.createWithInitialProperties({{"invokableObject", QVariant::fromValue(o)}}) };
+ QVERIFY(root);
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), -1); // no function got called due to incompatible arguments
+ }
+
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", QV4::Primitive::undefinedValue()));
QCOMPARE(o->error(), false);
@@ -7741,6 +7784,28 @@ void tst_qqmlecmascript::qpropertyBindingReplacement()
QCOMPARE(root->objectName(), u"overwritten"_qs);
}
+void tst_qqmlecmascript::qpropertyBindingNoQPropertyCapture()
+{
+
+ QQmlEngine engine;
+ QQmlComponent comp(&engine, testFileUrl("qpropertyBindingNoQPropertyCapture.qml"));
+ std::unique_ptr<QObject> root(comp.create());
+ QVERIFY2(root, qPrintable(comp.errorString()));
+ auto redRectangle = root.get();
+
+ QQmlProperty blueRectangleWidth(redRectangle, "blueRectangleWidth", &engine);
+
+ auto toggle = [&](){
+ QMetaObject::invokeMethod(root.get(), "toggle");
+ };
+
+ QCOMPARE(blueRectangleWidth.read().toInt(), 25);
+ toggle();
+ QCOMPARE(blueRectangleWidth.read().toInt(), 600);
+ toggle();
+ QCOMPARE(blueRectangleWidth.read().toInt(), 25);
+}
+
void tst_qqmlecmascript::deleteRootObjectInCreation()
{
QQmlEngine engine;
@@ -9565,7 +9630,7 @@ void tst_qqmlecmascript::urlConstruction()
QV4::UrlObject *validUrl = ret->as<QV4::UrlObject>();
QVERIFY(validUrl != nullptr);
- QCOMPARE(validUrl->protocol(), "https");
+ QCOMPARE(validUrl->protocol(), "https:");
QCOMPARE(validUrl->hostname(), "example.com");
QCOMPARE(validUrl->username(), "username");
QCOMPARE(validUrl->password(), "password");
@@ -9585,7 +9650,7 @@ void tst_qqmlecmascript::urlConstruction()
QV4::UrlObject *validRelativeUrl = retRel->as<QV4::UrlObject>();
QVERIFY(validRelativeUrl != nullptr);
- QCOMPARE(validRelativeUrl->protocol(), "https");
+ QCOMPARE(validRelativeUrl->protocol(), "https:");
QCOMPARE(validRelativeUrl->hostname(), "example.com");
QCOMPARE(validRelativeUrl->username(), "username");
QCOMPARE(validRelativeUrl->password(), "password");
@@ -9645,7 +9710,7 @@ void tst_qqmlecmascript::urlPropertySet()
// protocol
QVERIFY(EVALUATE("this.url.protocol = 'https';"));
- QCOMPARE(url->protocol(), "https");
+ QCOMPARE(url->protocol(), "https:");
QCOMPARE(url->href(), "https://localhost/a/b/c");
QCOMPARE(url->origin(), "https://localhost");
@@ -9708,7 +9773,7 @@ void tst_qqmlecmascript::urlPropertySet()
"this.url.href = "
"'https://username:password@example.com:1234/path/to/something?search=value#hash';"));
- QCOMPARE(url->protocol(), "https");
+ QCOMPARE(url->protocol(), "https:");
QCOMPARE(url->hostname(), "example.com");
QCOMPARE(url->username(), "username");
QCOMPARE(url->password(), "password");
@@ -9722,6 +9787,57 @@ void tst_qqmlecmascript::urlPropertySet()
QCOMPARE(url->hash(), "#hash");
}
+void tst_qqmlecmascript::colonAfterProtocol()
+{
+ QQmlEngine qmlengine;
+
+ QObject *o = new QObject(&qmlengine);
+
+ QV4::ExecutionEngine *engine = qmlengine.handle();
+ QV4::Scope scope(engine);
+
+ QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o));
+
+ QV4::ScopedValue ret(scope, EVALUATE("this.url = new URL('http://localhost/a/b/c');"));
+ QV4::UrlObject *url = ret->as<QV4::UrlObject>();
+ QVERIFY(url != nullptr);
+
+ // https without colon
+ QVERIFY(EVALUATE("this.url.protocol = 'https';"));
+ QCOMPARE(url->protocol(), "https:");
+ QCOMPARE(url->href(), "https://localhost/a/b/c");
+ QCOMPARE(url->origin(), "https://localhost");
+
+ QV4::ScopedValue retHttps(scope, EVALUATE("this.url = new URL('https://localhost/a/b/c');"));
+ QV4::UrlObject *urlHttps = retHttps->as<QV4::UrlObject>();
+ QVERIFY(urlHttps != nullptr);
+
+ // ftp with a colon
+ QVERIFY(EVALUATE("this.url.protocol = 'ftp:';"));
+ QCOMPARE(urlHttps->protocol(), "ftp:");
+ QCOMPARE(urlHttps->href(), "ftp://localhost/a/b/c");
+ QCOMPARE(urlHttps->origin(), "ftp://localhost");
+
+ QV4::ScopedValue retHttp(scope, EVALUATE("this.url = new URL('http://localhost/a/b/c');"));
+ QV4::UrlObject *ftpHttps = retHttp->as<QV4::UrlObject>();
+ QVERIFY(ftpHttps != nullptr);
+
+ // ftp with three colons
+ QVERIFY(EVALUATE("this.url.protocol = 'ftp:::';"));
+ QCOMPARE(ftpHttps->protocol(), "ftp:");
+ QCOMPARE(ftpHttps->href(), "ftp://localhost/a/b/c");
+ QCOMPARE(ftpHttps->origin(), "ftp://localhost");
+
+ QV4::ScopedValue retWss(scope, EVALUATE("this.url = new URL('wss://localhost/a/b/c');"));
+ QV4::UrlObject *urlFtpHttp = retWss->as<QV4::UrlObject>();
+ QVERIFY(urlFtpHttp != nullptr);
+
+ // ftp and http with a colon inbetween
+ QVERIFY(EVALUATE("this.url.protocol = 'ftp:http:';"));
+ QCOMPARE(urlFtpHttp->protocol(), "ftp:");
+ QCOMPARE(urlFtpHttp->href(), "ftp://localhost/a/b/c");
+ QCOMPARE(urlFtpHttp->origin(), "ftp://localhost");
+}
void tst_qqmlecmascript::urlSearchParamsConstruction()
{
@@ -10090,6 +10206,15 @@ void tst_qqmlecmascript::functionAsDefaultArgument()
QCOMPARE(root->objectName(), "didRun");
}
+void tst_qqmlecmascript::internalClassParentGc()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("internalClassParentGc.qml"));
+ QScopedPointer root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->objectName(), "3");
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"