summaryrefslogtreecommitdiffstats
path: root/tests/auto/qscriptclass/tst_qscriptclass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qscriptclass/tst_qscriptclass.cpp')
-rw-r--r--tests/auto/qscriptclass/tst_qscriptclass.cpp887
1 files changed, 674 insertions, 213 deletions
diff --git a/tests/auto/qscriptclass/tst_qscriptclass.cpp b/tests/auto/qscriptclass/tst_qscriptclass.cpp
index 0645319..9ab8318 100644
--- a/tests/auto/qscriptclass/tst_qscriptclass.cpp
+++ b/tests/auto/qscriptclass/tst_qscriptclass.cpp
@@ -65,10 +65,27 @@ public:
private slots:
void newInstance();
- void getAndSetProperty();
+ void setScriptClassOfExistingObject();
+ void setScriptClassOfNonQtScriptObject();
+ void getAndSetPropertyFromCpp();
+ void getAndSetPropertyFromJS();
+ void deleteUndeletableProperty();
+ void writeReadOnlyProperty();
+ void writePropertyWithoutWriteAccess();
void getProperty_invalidValue();
void enumerate();
- void extension();
+ void extension_None();
+ void extension_Callable();
+ void extension_Callable_construct();
+ void extension_HasInstance();
+ void originalProperties1();
+ void originalProperties2();
+ void originalProperties3();
+ void originalProperties4();
+ void defaultImplementations();
+ void scriptClassObjectInPrototype();
+ void scriptClassWithNullEngine();
+ void scriptClassInOtherEngine();
};
tst_QScriptClass::tst_QScriptClass()
@@ -301,7 +318,12 @@ void TestClass::setProperty(QScriptValue &object, const QScriptString &name,
CustomProperty *prop = findCustomProperty(name);
if (!prop)
return;
- prop->value = value;
+ if (prop->pflags & QScriptValue::ReadOnly)
+ return;
+ if (!value.isValid()) // deleteProperty() requested
+ removeCustomProperty(name);
+ else
+ prop->value = value;
}
QScriptValue::PropertyFlags TestClass::propertyFlags(
@@ -595,7 +617,7 @@ void tst_QScriptClass::newInstance()
QScriptValue obj1 = eng.newObject(&cls);
QVERIFY(!obj1.data().isValid());
QVERIFY(obj1.prototype().strictlyEquals(cls.prototype()));
- QEXPECT_FAIL("", "classname is not implemented", Continue);
+ QEXPECT_FAIL("", "QTBUG-17599: classname is not implemented", Continue);
QCOMPARE(obj1.toString(), QString::fromLatin1("[object TestClass]"));
QCOMPARE(obj1.scriptClass(), (QScriptClass*)&cls);
@@ -604,7 +626,14 @@ void tst_QScriptClass::newInstance()
QVERIFY(obj2.data().strictlyEquals(num));
QVERIFY(obj2.prototype().strictlyEquals(cls.prototype()));
QCOMPARE(obj2.scriptClass(), (QScriptClass*)&cls);
+ QVERIFY(!obj2.equals(obj1));
+ QVERIFY(!obj2.strictlyEquals(obj1));
+}
+void tst_QScriptClass::setScriptClassOfExistingObject()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
QScriptValue obj3 = eng.newObject();
QCOMPARE(obj3.scriptClass(), (QScriptClass*)0);
obj3.setScriptClass(&cls);
@@ -618,7 +647,12 @@ void tst_QScriptClass::newInstance()
TestClass cls2(&eng);
obj3.setScriptClass(&cls2);
QCOMPARE(obj3.scriptClass(), (QScriptClass*)&cls2);
+}
+void tst_QScriptClass::setScriptClassOfNonQtScriptObject()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
// undefined behavior really, but shouldn't crash
QScriptValue arr = eng.newArray();
QVERIFY(arr.isArray());
@@ -632,7 +666,7 @@ void tst_QScriptClass::newInstance()
QVERIFY(arr.isObject());
}
-void tst_QScriptClass::getAndSetProperty()
+void tst_QScriptClass::getAndSetPropertyFromCpp()
{
QScriptEngine eng;
@@ -644,7 +678,9 @@ void tst_QScriptClass::getAndSetProperty()
QScriptString bar = eng.toStringHandle("bar");
QScriptValue num(&eng, 123);
- // should behave just like normal
+ // Initially our TestClass instances have no custom properties,
+ // and queryProperty() will always return false.
+ // Hence, the properties will be created as normal JS properties.
for (int x = 0; x < 2; ++x) {
QScriptValue &o = (x == 0) ? obj1 : obj2;
for (int y = 0; y < 2; ++y) {
@@ -705,7 +741,7 @@ void tst_QScriptClass::getAndSetProperty()
QCOMPARE(obj1.propertyFlags(foo2), foo2Pflags);
QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1));
QVERIFY(cls.lastQueryPropertyName() == foo2);
- QEXPECT_FAIL("", "classObject.getOwnPropertyDescriptor() reads the property value", Continue);
+ QEXPECT_FAIL("", "QTBUG-17601: classObject.getOwnPropertyDescriptor() reads the property value", Continue);
QVERIFY(!cls.lastPropertyObject().isValid());
QVERIFY(cls.lastPropertyFlagsObject().strictlyEquals(obj1));
QVERIFY(cls.lastPropertyFlagsName() == foo2);
@@ -731,6 +767,14 @@ void tst_QScriptClass::getAndSetProperty()
QCOMPARE(cls.lastPropertyId(), foo2Id);
}
+ // attempt to delete custom property
+ obj1.setProperty(foo2, QScriptValue());
+ // delete real property
+ obj1.setProperty(foo, QScriptValue());
+ QVERIFY(!obj1.property(foo).isValid());
+ obj1.setProperty(foo, num);
+ QVERIFY(obj1.property(foo).equals(num));
+
// remove script class; normal properties should remain
obj1.setScriptClass(0);
QCOMPARE(obj1.scriptClass(), (QScriptClass*)0);
@@ -742,6 +786,80 @@ void tst_QScriptClass::getAndSetProperty()
QVERIFY(!obj1.property(bar).isValid());
}
+void tst_QScriptClass::getAndSetPropertyFromJS()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess
+ | QScriptClass::HandlesWriteAccess,
+ /*id=*/1, /*flags=*/0, /*value=*/123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+
+ // Accessing a custom property
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 456);
+
+ // Accessing a new JS property
+ QVERIFY(eng.evaluate("o.y").isUndefined());
+ QCOMPARE(eng.evaluate("o.y = 789; o.y").toInt32(), 789);
+
+ // Deleting custom property
+ QVERIFY(eng.evaluate("delete o.x").toBool());
+ QVERIFY(eng.evaluate("o.x").isUndefined());
+
+ // Deleting JS property
+ QVERIFY(eng.evaluate("delete o.y").toBool());
+ QVERIFY(eng.evaluate("o.y").isUndefined());
+}
+
+void tst_QScriptClass::deleteUndeletableProperty()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"), QScriptClass::HandlesWriteAccess,
+ /*id=*/0, QScriptValue::Undeletable, QScriptValue());
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ QVERIFY(!eng.evaluate("delete o.x").toBool());
+}
+
+void tst_QScriptClass::writeReadOnlyProperty()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess
+ | QScriptClass::HandlesWriteAccess,
+ /*id=*/0, QScriptValue::ReadOnly, 123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ // Note that if a property is read-only, the setProperty()
+ // reimplementation will still get called; it's up to that
+ // function to respect the ReadOnly flag.
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 123);
+}
+
+void tst_QScriptClass::writePropertyWithoutWriteAccess()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess,
+ /*id=*/0, /*flags=*/0, 123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+
+ // This will create a JS property on the instance that
+ // shadows the custom property.
+ // This behavior is not documented. It might be more
+ // intuitive to treat a property that only handles read
+ // access as a read-only, non-shadowable property.
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 456);
+
+ QVERIFY(eng.evaluate("delete o.x").toBool());
+ // Now the custom property is seen again.
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+}
+
void tst_QScriptClass::getProperty_invalidValue()
{
QScriptEngine eng;
@@ -791,10 +909,12 @@ void tst_QScriptClass::enumerate()
cls.setIterationEnabled(true);
QScriptValueIterator it(obj);
+ // This test relies on the order in which properties are enumerated,
+ // which we don't guarantee. However, for compatibility's sake we prefer
+ // that normal JS properties come before QScriptClass properties.
for (int x = 0; x < 2; ++x) {
QVERIFY(it.hasNext());
it.next();
- QEXPECT_FAIL("", "", Abort);
QVERIFY(it.scriptName() == foo);
QVERIFY(it.hasNext());
it.next();
@@ -813,230 +933,571 @@ void tst_QScriptClass::enumerate()
}
}
-void tst_QScriptClass::extension()
+void tst_QScriptClass::extension_None()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setCallableMode(TestClass::NotCallable);
+ QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
+ QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
+ QScriptValue obj = eng.newObject(&cls);
+ QVERIFY(!obj.call().isValid());
+ QCOMPARE((int)cls.lastExtensionType(), -1);
+ QVERIFY(!obj.instanceOf(obj));
+ QCOMPARE((int)cls.lastExtensionType(), -1);
+ QVERIFY(!obj.construct().isValid());
+}
+
+void tst_QScriptClass::extension_Callable()
{
QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setCallableMode(TestClass::CallableReturnsSum);
+ QVERIFY(cls.supportsExtension(QScriptClass::Callable));
+
+ QScriptValue obj = eng.newObject(&cls);
+ eng.globalObject().setProperty("obj", obj);
+ obj.setProperty("one", QScriptValue(&eng, 1));
+ obj.setProperty("two", QScriptValue(&eng, 2));
+ obj.setProperty("three", QScriptValue(&eng, 3));
+ // From C++
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setCallableMode(TestClass::NotCallable);
- QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
- QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
- QScriptValue obj = eng.newObject(&cls);
- QVERIFY(!obj.call().isValid());
- QCOMPARE((int)cls.lastExtensionType(), -1);
- QVERIFY(!obj.instanceOf(obj));
- QCOMPARE((int)cls.lastExtensionType(), -1);
+ QScriptValueList args;
+ args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
+ QScriptValue ret = obj.call(obj, args);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qsreal(1+2+3+4+5));
}
- // Callable
+ // From JS
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setCallableMode(TestClass::CallableReturnsSum);
- QVERIFY(cls.supportsExtension(QScriptClass::Callable));
-
- QScriptValue obj = eng.newObject(&cls);
- eng.globalObject().setProperty("obj", obj);
- obj.setProperty("one", QScriptValue(&eng, 1));
- obj.setProperty("two", QScriptValue(&eng, 2));
- obj.setProperty("three", QScriptValue(&eng, 3));
- // From C++
- cls.clearReceivedArgs();
- {
- QScriptValueList args;
- args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
- QScriptValue ret = obj.call(obj, args);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toNumber(), qsreal(15));
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("obj(4, 5)");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toNumber(), qsreal(15));
- }
+ QScriptValue ret = eng.evaluate("obj(4, 5)");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qsreal(1+2+3+4+5));
+ }
- cls.setCallableMode(TestClass::CallableReturnsArgument);
- // From C++
- cls.clearReceivedArgs();
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toInt32(), 123);
- }
- cls.clearReceivedArgs();
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << true);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isBoolean());
- QCOMPARE(ret.toBoolean(), true);
- }
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
- QVERIFY(ret.isString());
- QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
- }
- {
- QScriptValue objobj = eng.newObject();
- QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(objobj));
- }
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
- QVERIFY(ret.isUndefined());
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("obj(123)");
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toInt32(), 123);
- }
+ cls.setCallableMode(TestClass::CallableReturnsArgument);
+ // From C++
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << true);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isBoolean());
+ QCOMPARE(ret.toBoolean(), true);
+ }
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
+ }
+ {
+ QScriptValue objobj = eng.newObject();
+ QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(objobj));
+ }
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
+ QVERIFY(ret.isUndefined());
+ }
+ // From JS
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("obj(123)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
- cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
- {
- QScriptValue ret = obj.call(obj);
- QVERIFY(ret.isUndefined());
- }
+ cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
+ {
+ QScriptValue ret = obj.call(obj);
+ QVERIFY(ret.isUndefined());
+ }
- cls.setCallableMode(TestClass::CallableReturnsThisObject);
- // From C++
- {
- QScriptValue ret = obj.call(obj);
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj()");
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
+ cls.setCallableMode(TestClass::CallableReturnsThisObject);
+ // From C++
+ {
+ QScriptValue ret = obj.call(obj);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj()");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
- cls.setCallableMode(TestClass::CallableReturnsCallee);
- // From C++
- {
- QScriptValue ret = obj.call();
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj()");
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
+ cls.setCallableMode(TestClass::CallableReturnsCallee);
+ // From C++
+ {
+ QScriptValue ret = obj.call();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj()");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
- cls.setCallableMode(TestClass::CallableReturnsArgumentsObject);
- // From C++
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
- QVERIFY(ret.isObject());
- QVERIFY(ret.property("length").isNumber());
- QCOMPARE(ret.property("length").toInt32(), 1);
- QVERIFY(ret.property(0).isNumber());
- QCOMPARE(ret.property(0).toInt32(), 123);
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj(123)");
- QVERIFY(ret.isObject());
- QVERIFY(ret.property("length").isNumber());
- QCOMPARE(ret.property("length").toInt32(), 1);
- QVERIFY(ret.property(0).isNumber());
- QCOMPARE(ret.property(0).toInt32(), 123);
- }
+ cls.setCallableMode(TestClass::CallableReturnsArgumentsObject);
+ // From C++
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("length").isNumber());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ QVERIFY(ret.property(0).isNumber());
+ QCOMPARE(ret.property(0).toInt32(), 123);
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj(123)");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("length").isNumber());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ QVERIFY(ret.property(0).isNumber());
+ QCOMPARE(ret.property(0).toInt32(), 123);
+ }
+}
- // construct()
- // From C++
- cls.clearReceivedArgs();
- cls.setCallableMode(TestClass::CallableReturnsGlobalObject);
- {
- QScriptValue ret = obj.construct();
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("new obj()");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
- // From C++
- cls.clearReceivedArgs();
- cls.setCallableMode(TestClass::CallableInitializesThisObject);
- {
- QScriptValue ret = obj.construct();
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isQObject());
- QCOMPARE(ret.toQObject(), (QObject*)&eng);
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("new obj()");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isQObject());
- QCOMPARE(ret.toQObject(), (QObject*)&eng);
- }
+void tst_QScriptClass::extension_Callable_construct()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptValue obj = eng.newObject(&cls);
+ eng.globalObject().setProperty("obj", obj);
+
+ // From C++
+ cls.clearReceivedArgs();
+ cls.setCallableMode(TestClass::CallableReturnsGlobalObject);
+ {
+ QScriptValue ret = obj.construct();
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
}
- // HasInstance
+ // From JS
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setHasInstance(true);
- QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));
+ QScriptValue ret = eng.evaluate("new obj()");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
+ // From C++
+ cls.clearReceivedArgs();
+ cls.setCallableMode(TestClass::CallableInitializesThisObject);
+ {
+ QScriptValue ret = obj.construct();
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject*)&eng);
+ }
+ // From JS
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("new obj()");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject*)&eng);
+ }
+}
- QScriptValue obj = eng.newObject(&cls);
- obj.setProperty("foo", QScriptValue(&eng, 123));
- QScriptValue plain = eng.newObject();
- QVERIFY(!plain.instanceOf(obj));
+void tst_QScriptClass::extension_HasInstance()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setHasInstance(true);
+ QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));
- eng.globalObject().setProperty("HasInstanceTester", obj);
- eng.globalObject().setProperty("hasInstanceValue", plain);
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
- QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
- QCOMPARE(lst.size(), 2);
- QVERIFY(lst.at(0).strictlyEquals(obj));
- QVERIFY(lst.at(1).strictlyEquals(plain));
- QVERIFY(ret.isBoolean());
- QVERIFY(!ret.toBoolean());
- }
+ QScriptValue obj = eng.newObject(&cls);
+ obj.setProperty("foo", QScriptValue(&eng, 123));
+ QScriptValue plain = eng.newObject();
+ QVERIFY(!plain.instanceOf(obj));
- plain.setProperty("foo", QScriptValue(&eng, 456));
- QVERIFY(!plain.instanceOf(obj));
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QVERIFY(ret.isBoolean());
- QVERIFY(!ret.toBoolean());
- }
+ eng.globalObject().setProperty("HasInstanceTester", obj);
+ eng.globalObject().setProperty("hasInstanceValue", plain);
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
+ QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
+ QCOMPARE(lst.size(), 2);
+ QVERIFY(lst.at(0).strictlyEquals(obj));
+ QVERIFY(lst.at(1).strictlyEquals(plain));
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+ }
- plain.setProperty("foo", obj.property("foo"));
- QVERIFY(plain.instanceOf(obj));
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QVERIFY(ret.isBoolean());
- QVERIFY(ret.toBoolean());
- }
+ plain.setProperty("foo", QScriptValue(&eng, 456));
+ QVERIFY(!plain.instanceOf(obj));
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+ }
+
+ plain.setProperty("foo", obj.property("foo"));
+ QVERIFY(plain.instanceOf(obj));
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+ }
+}
+
+// tests made to match Qt 4.7 (JSC) behaviour
+void tst_QScriptClass::originalProperties1()
+{
+ QScriptEngine eng;
+
+ QScriptString orig1 = eng.toStringHandle("orig1");
+ QScriptString orig2 = eng.toStringHandle("orig2");
+ QScriptString orig3 = eng.toStringHandle("orig3");
+ QScriptString new1 = eng.toStringHandle("new1");
+ QScriptString new2 = eng.toStringHandle("new2");
+
+ {
+ TestClass cls1(&eng);
+ cls1.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 89);
+ cls1.addCustomProperty(new1, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "hello");
+
+ TestClass cls2(&eng);
+ cls2.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 59);
+ cls2.addCustomProperty(new2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "world");
+
+ QScriptValue obj1 = eng.newObject();
+ obj1.setProperty(orig1 , 42);
+ obj1.setProperty(orig2 , "foo");
+ obj1.prototype().setProperty(orig3, "bar");
+
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("bar"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QVERIFY(!obj1.property(new2).isValid());
+
+ eng.globalObject().setProperty("obj" , obj1);
+
+ obj1.setScriptClass(&cls1);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("bar"));
+ QCOMPARE(obj1.property(new1).toString(), QString::fromLatin1("hello"));
+ QVERIFY(!obj1.property(new2).isValid());
+
+ QScriptValue obj2 = eng.evaluate("obj");
+ QCOMPARE(obj2.scriptClass(), &cls1);
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QCOMPARE(obj2.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj2.property(orig3).toString(), QString::fromLatin1("bar"));
+ QCOMPARE(obj2.property(new1).toString(), QString::fromLatin1("hello"));
+ QVERIFY(!obj2.property(new2).isValid());
+
+ obj1.setScriptClass(&cls2);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("bar"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("world"));
+
+ QCOMPARE(obj2.scriptClass(), &cls2);
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QCOMPARE(obj2.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj2.property(orig3).toString(), QString::fromLatin1("bar"));
+ QVERIFY(!obj2.property(new1).isValid());
+ QCOMPARE(obj2.property(new2).toString(), QString::fromLatin1("world"));
+
+ obj1.setScriptClass(0);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("bar"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QVERIFY(!obj1.property(new2).isValid());
+ }
+}
+
+void tst_QScriptClass::originalProperties2()
+{
+ QScriptEngine eng;
+
+ QScriptString orig1 = eng.toStringHandle("orig1");
+ QScriptString orig2 = eng.toStringHandle("orig2");
+ QScriptString orig3 = eng.toStringHandle("orig3");
+ QScriptString new1 = eng.toStringHandle("new1");
+ QScriptString new2 = eng.toStringHandle("new2");
+
+ {
+ TestClass cls1(&eng);
+ cls1.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 89);
+ cls1.addCustomProperty(new1, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "hello");
+
+ TestClass cls2(&eng);
+ cls2.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 59);
+ cls2.addCustomProperty(new2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "world");
+
+ QScriptValue obj1 = eng.newObject();
+ obj1.setProperty(orig1 , 42);
+ obj1.setProperty(orig2 , "foo");
+ obj1.prototype().setProperty(orig3, "bar");
+
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("bar"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QVERIFY(!obj1.property(new2).isValid());
+
+ obj1.setScriptClass(&cls1);
+ obj1.setProperty(orig1 , QScriptValue(&eng, 852));
+ obj1.setProperty(orig2 , "oli");
+ obj1.setProperty(orig3 , "fu*c");
+ obj1.setProperty(new1 , "moo");
+ obj1.setProperty(new2 , "allo?");
+ QCOMPARE(obj1.property(orig1).toInt32(), 852);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("fu*c"));
+ QCOMPARE(obj1.property(new1).toString(), QString::fromLatin1("moo"));
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("allo?"));
+
+ obj1.setScriptClass(&cls2);
+ QCOMPARE(obj1.property(orig1).toInt32(), 852);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("fu*c"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("allo?"));
+
+ obj1.setScriptClass(0);
+ QCOMPARE(obj1.property(orig1).toInt32(), 852);
+ QCOMPARE(obj1.property(orig2).toString(), QString::fromLatin1("foo"));
+ QCOMPARE(obj1.property(orig3).toString(), QString::fromLatin1("fu*c"));
+ QVERIFY(!obj1.property(new1).isValid());
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("allo?"));
+ }
+}
+
+void tst_QScriptClass::originalProperties3()
+{
+ QScriptEngine eng;
+
+ QScriptString orig1 = eng.toStringHandle("orig1");
+ QScriptString orig2 = eng.toStringHandle("orig2");
+ QScriptString orig3 = eng.toStringHandle("orig3");
+ QScriptString new1 = eng.toStringHandle("new1");
+ QScriptString new2 = eng.toStringHandle("new2");
+
+ {
+ TestClass cls1(&eng);
+ cls1.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 89);
+ cls1.addCustomProperty(new1, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "hello");
+
+ TestClass cls2(&eng);
+ cls2.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 59);
+ cls2.addCustomProperty(new2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "world");
+
+ QScriptValue obj1 = eng.newObject(&cls1);
+ QVERIFY(!obj1.property(orig1).isValid());
+ QCOMPARE(obj1.property(orig2).toInt32(), 89);
+ QCOMPARE(obj1.property(new1).toString(), QString::fromLatin1("hello"));
+ QVERIFY(!obj1.property(new2).isValid());
+ obj1.setProperty(orig1, 42);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+
+ eng.globalObject().setProperty("obj" , obj1);
+ obj1.setScriptClass(&cls2);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toInt32(), 59);
+ QVERIFY(!obj1.property(new1).isValid());
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("world"));
+
+ QScriptValue obj2 = eng.evaluate("obj");
+ QCOMPARE(obj2.scriptClass(), &cls2);
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QCOMPARE(obj2.property(orig2).toInt32(), 59);
+ QVERIFY(!obj2.property(new1).isValid());
+ QCOMPARE(obj2.property(new2).toString(), QString::fromLatin1("world"));
+
+ obj1.setScriptClass(0);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QVERIFY(!obj1.property(orig2).isValid());
+ QVERIFY(!obj1.property(new1).isValid());
+ QVERIFY(!obj1.property(new2).isValid());
+
+ QCOMPARE(obj2.scriptClass(), (QScriptClass *)0);
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QVERIFY(!obj2.property(orig2).isValid());
+ QVERIFY(!obj2.property(new1).isValid());
+ QVERIFY(!obj2.property(new2).isValid());
}
}
+void tst_QScriptClass::originalProperties4()
+{
+ QScriptEngine eng;
+
+ QScriptString orig1 = eng.toStringHandle("orig1");
+ QScriptString orig2 = eng.toStringHandle("orig2");
+ QScriptString orig3 = eng.toStringHandle("orig3");
+ QScriptString new1 = eng.toStringHandle("new1");
+ QScriptString new2 = eng.toStringHandle("new2");
+
+ {
+ TestClass cls1(&eng);
+ cls1.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 89);
+ cls1.addCustomProperty(new1, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "hello");
+
+ TestClass cls2(&eng);
+ cls2.addCustomProperty(orig2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, 59);
+ cls2.addCustomProperty(new2, QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess, 1, 0, "world");
+
+ QScriptValue obj1 = eng.newObject(&cls1);
+ QVERIFY(!obj1.property(orig1).isValid());
+ QCOMPARE(obj1.property(orig2).toInt32(), 89);
+ QCOMPARE(obj1.property(new1).toString(), QString::fromLatin1("hello"));
+ QVERIFY(!obj1.property(new2).isValid());
+
+ eng.globalObject().setProperty("obj" , obj1);
+
+ obj1.setScriptClass(0);
+ QVERIFY(obj1.isObject());
+ QVERIFY(!obj1.property(orig1).isValid());
+ QVERIFY(!obj1.property(orig2).isValid());
+ QVERIFY(!obj1.property(new1).isValid());
+ QVERIFY(!obj1.property(new2).isValid());
+ obj1.setProperty(orig1, 42);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+
+ QScriptValue obj2 = eng.evaluate("obj");
+ QCOMPARE(obj2.scriptClass(), (QScriptClass *)0);
+ QVERIFY(obj2.isObject());
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QVERIFY(!obj2.property(orig2).isValid());
+ QVERIFY(!obj2.property(new1).isValid());
+ QVERIFY(!obj2.property(new2).isValid());
+
+ obj1.setScriptClass(&cls2);
+ QCOMPARE(obj1.property(orig1).toInt32(), 42);
+ QCOMPARE(obj1.property(orig2).toInt32(), 59);
+ QVERIFY(!obj1.property(new1).isValid());
+ QCOMPARE(obj1.property(new2).toString(), QString::fromLatin1("world"));
+
+ QCOMPARE(obj2.scriptClass(), (QScriptClass *)(&cls2));
+ QCOMPARE(obj2.property(orig1).toInt32(), 42);
+ QCOMPARE(obj2.property(orig2).toInt32(), 59);
+ QVERIFY(!obj2.property(new1).isValid());
+ QCOMPARE(obj2.property(new2).toString(), QString::fromLatin1("world"));
+ }
+}
+
+void tst_QScriptClass::defaultImplementations()
+{
+ QScriptEngine eng;
+
+ QScriptClass defaultClass(&eng);
+ QCOMPARE(defaultClass.engine(), &eng);
+ QVERIFY(!defaultClass.prototype().isValid());
+ QCOMPARE(defaultClass.name(), QString());
+
+ QScriptValue obj = eng.newObject(&defaultClass);
+ QCOMPARE(obj.scriptClass(), &defaultClass);
+
+ QScriptString name = eng.toStringHandle("foo");
+ uint id = -1;
+ QCOMPARE(defaultClass.queryProperty(obj, name, QScriptClass::HandlesReadAccess, &id), QScriptClass::QueryFlags(0));
+ QVERIFY(!defaultClass.property(obj, name, id).isValid());
+ QCOMPARE(defaultClass.propertyFlags(obj, name, id), QScriptValue::PropertyFlags(0));
+ defaultClass.setProperty(obj, name, id, 123);
+ QVERIFY(!obj.property(name).isValid());
+
+ QCOMPARE(defaultClass.newIterator(obj), (QScriptClassPropertyIterator*)0);
+
+ QVERIFY(!defaultClass.supportsExtension(QScriptClass::Callable));
+ QVERIFY(!defaultClass.supportsExtension(QScriptClass::HasInstance));
+ QVERIFY(!defaultClass.extension(QScriptClass::Callable).isValid());
+ QVERIFY(!defaultClass.extension(QScriptClass::HasInstance).isValid());
+}
+
+void tst_QScriptClass::scriptClassObjectInPrototype()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptValue plainObject = eng.newObject();
+ QScriptValue classObject = eng.newObject(&cls);
+ plainObject.setPrototype(classObject);
+ QVERIFY(plainObject.prototype().equals(classObject));
+ eng.globalObject().setProperty("plainObject", plainObject);
+ eng.globalObject().setProperty("classObject", classObject);
+
+ QScriptString name = eng.toStringHandle("x");
+ cls.addCustomProperty(name, QScriptClass::HandlesReadAccess, /*id=*/1, /*flags=*/0, /*value=*/123);
+ QVERIFY(plainObject.property(name).equals(classObject.property(name)));
+ QVERIFY(eng.evaluate("plainObject.x == classObject.x").toBool());
+
+ // Add a property that shadows the one in the script class.
+ plainObject.setProperty(name, 456);
+ QVERIFY(!plainObject.property(name).equals(classObject.property(name)));
+ QVERIFY(eng.evaluate("plainObject.x != classObject.x").toBool());
+
+ QVERIFY(eng.evaluate("delete plainObject.x").toBool());
+ QVERIFY(eng.evaluate("plainObject.x == classObject.x").toBool());
+}
+
+void tst_QScriptClass::scriptClassWithNullEngine()
+{
+ QScriptClass cls(0);
+ QCOMPARE(cls.engine(), (QScriptEngine*)0);
+ QScriptEngine eng;
+ QScriptValue obj = eng.newObject(&cls);
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.scriptClass(), &cls);
+ // The class could have been "bound" to the engine at this point,
+ // but it's currently not.
+ // This behavior is not documented and is subject to change.
+ QCOMPARE(cls.engine(), (QScriptEngine*)0);
+ // The engine pointer stored in the QScriptClass is not actually used
+ // during property access, so this still works.
+ obj.setProperty("x", 123);
+ QVERIFY(obj.property("x").isNumber());
+}
+
+void tst_QScriptClass::scriptClassInOtherEngine()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptEngine eng2;
+ // We don't check that the class is associated with another engine, so
+ // we only get a warning when trying to set the prototype of the new
+ // instance.
+ // This behavior is not documented and is subject to change.
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ QScriptValue obj = eng2.newObject(&cls);
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.scriptClass(), &cls);
+
+ obj.setProperty("x", 123);
+ QVERIFY(obj.property("x").isNumber());
+}
+
QTEST_MAIN(tst_QScriptClass)
#include "tst_qscriptclass.moc"