summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2010-04-09 13:43:35 (GMT)
committerKent Hansen <kent.hansen@nokia.com>2010-04-09 14:31:12 (GMT)
commit06add85eb8a9bd8f53acd162ce665d46e7ebc137 (patch)
treebb9b6d404e1a3e6bedac121096d9a1076eb80655 /tests
parent8f75ee78746a311434db3fe5a3793c6f725fa210 (diff)
downloadQt-06add85eb8a9bd8f53acd162ce665d46e7ebc137.zip
Qt-06add85eb8a9bd8f53acd162ce665d46e7ebc137.tar.gz
Qt-06add85eb8a9bd8f53acd162ce665d46e7ebc137.tar.bz2
Regressions in Global Object prototype access
In 4.5, changing the prototype of the (custom) global object used to "Just Work"(tm). In the JSC-based back-end, the built-in global object acts as a proxy if a custom global object is set, because JSC doesn't (yet, anyway) provide a way to replace the global object. To complicate this further, we also have a proxy to the original global object (that bypasses the custom global object proxying (!)). This is so that properties of the original global object can still be accessed with the QtScript C++ API when a custom global object has been set. Unfortunately, JSObject::prototype()/setPrototype() are not virtual, meaning that a change of prototype in the source object is not reflected in the proxy or vice versa. Work around this for now by syncing the prototype at the appropriate places (QScriptEngine::setGlobalObject(), QScriptValue::setPrototype()). This fixes all except the case when a prototype is set from JS, since such a write doesn't go through our public C++ API. But this case can be detected and handled by the global object's JSObject::put() reimplementation. Created a separate report for that issue: QTBUG-9737. Task-number: QTBUG-7066 Reviewed-by: Jedrzej Nowacki
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp
index cbc36a7..f556fa1 100644
--- a/tests/auto/qscriptengine/tst_qscriptengine.cpp
+++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp
@@ -104,6 +104,8 @@ private slots:
void getSetGlobalObject();
void globalObjectProperties();
void globalObjectGetterSetterProperty();
+ void customGlobalObjectWithPrototype();
+ void globalObjectWithCustomPrototype();
void builtinFunctionNames_data();
void builtinFunctionNames();
void checkSyntax_data();
@@ -1174,6 +1176,131 @@ void tst_QScriptEngine::globalObjectGetterSetterProperty()
QVERIFY(global.property("baz").equals(789));
}
+void tst_QScriptEngine::customGlobalObjectWithPrototype()
+{
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine engine;
+ QScriptValue wrap = engine.newObject();
+ QScriptValue global = engine.globalObject();
+ QScriptValue originalGlobalProto = global.prototype();
+ if (!x) {
+ // Set prototype before setting global object
+ wrap.setPrototype(global);
+ QVERIFY(wrap.prototype().strictlyEquals(global));
+ engine.setGlobalObject(wrap);
+ } else {
+ // Set prototype after setting global object
+ engine.setGlobalObject(wrap);
+ wrap.setPrototype(global);
+ QVERIFY(wrap.prototype().strictlyEquals(global));
+ }
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("hasOwnProperty('print')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.hasOwnProperty('print')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+
+ QScriptValue anotherProto = engine.newObject();
+ anotherProto.setProperty("anotherProtoProperty", 123);
+ global.setPrototype(anotherProto);
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+
+ wrap.setPrototype(anotherProto);
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: print"));
+ }
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+ QVERIFY(global.prototype().strictlyEquals(anotherProto));
+
+ global.setPrototype(originalGlobalProto);
+ engine.setGlobalObject(global);
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: anotherProtoProperty"));
+ }
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(global.property("print")));
+ }
+ QVERIFY(!anotherProto.property("print").isValid());
+ }
+}
+
+void tst_QScriptEngine::globalObjectWithCustomPrototype()
+{
+ QScriptEngine engine;
+ QScriptValue proto = engine.newObject();
+ proto.setProperty("protoProperty", 123);
+ QScriptValue global = engine.globalObject();
+ QScriptValue originalProto = global.prototype();
+ global.setPrototype(proto);
+ {
+ QScriptValue ret = engine.evaluate("protoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.protoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+
+ // Custom prototype set from JS
+ {
+ QScriptValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a");
+ QVERIFY(ret.isNumber());
+ QEXPECT_FAIL("", "QTBUG-9737", Continue);
+ QVERIFY(ret.strictlyEquals(global.property("a")));
+ }
+}
+
void tst_QScriptEngine::builtinFunctionNames_data()
{
QTest::addColumn<QString>("expression");