aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qjsvalue
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-03-04 16:46:42 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-03-18 16:35:02 +0100
commit748411fa64412db1650e04ee7b4405b8fbc53d42 (patch)
treea3c94175c04a8465cb602d4d4deb557a37c1923d /tests/auto/qml/qjsvalue
parent7230005ef66f22a7ee3addff95b1e8d9060dc5a1 (diff)
Store a QV4::ReturnedValue in QJSValue
Being careful, we can now save primitive values inline. We use the heap pointer of QV4::Value as either QString* or QV4::Value* for complex types. We cannot store persistent managed QV4::Value without the double indirection as those need to be allocated in a special place. The generic QVariant case is not supported anymore. The only place where it was actually needed were the stream operators for QJSValue. Those were fundamentally broken: * A managed QJSValue saved and loaded from a stream was converted to a QVariant-type QJSValue * QVariant-type QJSValues were not callable, could not be objects or arrays, or any of the special types. * Cyclic references were forcibly broken when saving to a data stream. In general the support for saving and loading of managed types to/from a data stream was so abysmally bad that we don't lose much by dropping it. [ChangeLog][QML][Important Behavior Changes] When saving a QJSValue to a QDataStream only primitive values or strings will be retained. Support for objects and arrays was incomplete and unreliable already before. It cannot work correctly as we don't necessarily have a JavaScript heap when loading a QJSValue from a stream. Therefore, we don't have a proper place to keep any managed values. Using QVariant to keep them instead is a bad idea because QVariant cannot represent everything a QJSValue can contain. Fixes: QTBUG-75174 Change-Id: I75697670639bca8d4b1668763d7020c4cf871bda Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml/qjsvalue')
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp52
1 files changed, 35 insertions, 17 deletions
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 0d0bd2ae7e..85c29957b4 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -66,7 +66,7 @@ void tst_QJSValue::ctor_undefinedWithEngine()
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // undefined is not managed
#endif
}
}
@@ -80,7 +80,7 @@ void tst_QJSValue::ctor_nullWithEngine()
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // null is not managed
#endif
}
}
@@ -95,7 +95,7 @@ void tst_QJSValue::ctor_boolWithEngine()
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // bool is not managed
#endif
}
}
@@ -110,7 +110,7 @@ void tst_QJSValue::ctor_intWithEngine()
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // int is not managed
#endif
}
}
@@ -144,7 +144,7 @@ void tst_QJSValue::ctor_uintWithEngine()
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // uint is not managed
#endif
}
}
@@ -178,7 +178,7 @@ void tst_QJSValue::ctor_floatWithEngine()
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
#ifdef QT_DEPRECATED
- QCOMPARE(v.engine(), &eng);
+ QCOMPARE(v.engine(), nullptr); // float is not managed
#endif
}
}
@@ -250,14 +250,14 @@ void tst_QJSValue::ctor_copyAndAssignWithEngine()
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
#ifdef QT_DEPRECATED
- QCOMPARE(v2.engine(), &eng);
+ QCOMPARE(v2.engine(), nullptr); // not managed
#endif
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
#ifdef QT_DEPRECATED
- QCOMPARE(v3.engine(), &eng);
+ QCOMPARE(v3.engine(), nullptr); // not managed
#endif
QJSValue v4 = eng.toScriptValue(2.0);
@@ -466,6 +466,7 @@ void tst_QJSValue::toString()
#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
#endif
+ QEXPECT_FAIL("", "We cannot save and restore objects to/from a data stream", Continue);
QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
}
@@ -480,6 +481,7 @@ void tst_QJSValue::toString()
#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
#endif
+ QEXPECT_FAIL("", "We cannot save and restore arrays to/from a data stream", Continue);
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
}
@@ -1627,10 +1629,15 @@ void tst_QJSValue::getSetProperty_twoEngines()
QJSEngine otherEngine;
QJSValue otherNum = otherEngine.toScriptValue(123);
- QTest::ignoreMessage(QtWarningMsg, "QJSValue::setProperty(oof) failed: cannot set value created in a different engine");
object.setProperty("oof", otherNum);
- QVERIFY(!object.hasOwnProperty("oof"));
- QVERIFY(object.property("oof").isUndefined());
+ QVERIFY(object.hasOwnProperty("oof")); // primitive values don't have an engine
+ QVERIFY(object.property("oof").isNumber());
+
+ QJSValue otherString = otherEngine.toScriptValue(QString::fromLatin1("nope"));
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setProperty(eek) failed: cannot set value created in a different engine");
+ object.setProperty("eek", otherString);
+ QVERIFY(!object.hasOwnProperty("eek")); // strings are managed
+ QVERIFY(object.property("eek").isUndefined());
}
void tst_QJSValue::getSetProperty_gettersAndSettersThrowErrorJS()
@@ -1696,7 +1703,7 @@ void tst_QJSValue::getSetProperty()
object.setProperty("foo", strstr);
QCOMPARE(object.property("foo").toString(), strstr.toString());
#ifdef QT_DEPRECATED
- QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
+ QVERIFY(strstr.engine() != &eng); // the value has not been bound to the engine
#endif
QJSValue numnum = QJSValue(123.0);
@@ -1941,10 +1948,15 @@ void tst_QJSValue::call_twoEngines()
"cannot call function with thisObject created in "
"a different engine");
QVERIFY(fun.callWithInstance(object).isUndefined());
+
+ // Primitive value doesn't need an engine
+ QVERIFY(!fun.call(QJSValueList() << eng.toScriptValue(123)).isUndefined());
+
QTest::ignoreMessage(QtWarningMsg, "QJSValue::call() failed: "
"cannot call function with argument created in "
"a different engine");
- QVERIFY(fun.call(QJSValueList() << eng.toScriptValue(123)).isUndefined());
+ QVERIFY(fun.call(QJSValueList() << eng.toScriptValue(QString::fromLatin1("string")))
+ .isUndefined());
{
QJSValue fun = eng.evaluate("Object");
QVERIFY(fun.isCallable());
@@ -2079,10 +2091,15 @@ void tst_QJSValue::construct_twoEngines()
QJSEngine engine;
QJSEngine otherEngine;
QJSValue ctor = engine.evaluate("(function (a, b) { this.foo = 123; })");
+
QJSValue arg = otherEngine.toScriptValue(124567);
+ QVERIFY(!ctor.callAsConstructor(QJSValueList() << arg).isUndefined());
+
+ QJSValue arg2 = otherEngine.toScriptValue(QString::fromLatin1("string"));
QTest::ignoreMessage(QtWarningMsg, "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
- QVERIFY(ctor.callAsConstructor(QJSValueList() << arg).isUndefined());
+ QVERIFY(ctor.callAsConstructor(QJSValueList() << arg2).isUndefined());
QTest::ignoreMessage(QtWarningMsg, "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
+
QVERIFY(ctor.callAsConstructor(QJSValueList() << arg << otherEngine.newObject()).isUndefined());
}
@@ -2588,7 +2605,7 @@ void tst_QJSValue::engineDeleted()
delete eng;
- QVERIFY(v1.isUndefined());
+ QVERIFY(!v1.isUndefined()); // Primitive value is stored inline
QVERIFY(v2.isUndefined());
QVERIFY(v3.isUndefined());
QVERIFY(v4.isUndefined());
@@ -2777,6 +2794,7 @@ void tst_QJSValue::jsvalueArrayToSequenceType()
QCOMPARE(instanceCount, 0);
}
+struct QJSValuePrivateAccess : public QJSValuePrivate { using QJSValuePrivate::setRawValue; };
void tst_QJSValue::deleteFromDifferentThread()
{
#if !QT_CONFIG(thread)
@@ -2785,7 +2803,7 @@ void tst_QJSValue::deleteFromDifferentThread()
QV4::PersistentValueStorage storage(engine->handle());
QCOMPARE(storage.firstPage, nullptr);
QJSValue jsval;
- QJSValuePrivate::setRawValue(&jsval, storage.allocate());
+ QJSValuePrivateAccess::setRawValue(&jsval, storage.allocate());
QVERIFY(storage.firstPage != nullptr);
QMutex mutex;
@@ -2794,7 +2812,7 @@ void tst_QJSValue::deleteFromDifferentThread()
std::unique_ptr<QThread> thread(QThread::create([&]() {
QMutexLocker locker(&mutex);
QJSValuePrivate::free(&jsval);
- QJSValuePrivate::setRawValue(&jsval, nullptr);
+ QJSValuePrivate::setValue(&jsval, QV4::Encode::undefined());
QVERIFY(storage.firstPage != nullptr);
condition.wakeOne();
}));