aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/declarative/declarative.pro5
-rw-r--r--tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h4
-rw-r--r--tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro4
-rw-r--r--tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro4
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.h10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp25
-rw-r--r--tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro4
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro4
-rw-r--r--tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro3
-rw-r--r--tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro4
-rw-r--r--tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro4
-rw-r--r--tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro2
-rw-r--r--tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro2
-rw-r--r--tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro4
-rw-r--r--tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro2
-rw-r--r--tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro4
-rw-r--r--tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro4
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp2
-rw-r--r--tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro4
-rw-r--r--tests/auto/declarative/qjsengine/qjsengine.pro21
-rw-r--r--tests/auto/declarative/qjsengine/script/com/__init__.js9
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js9
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js1
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js5
-rw-r--r--tests/auto/declarative/qjsengine/tst_qjsengine.cpp6491
-rw-r--r--tests/auto/declarative/qjsvalue/qjsvalue.pro10
-rw-r--r--tests/auto/declarative/qjsvalue/tst_qjsvalue.cpp4109
-rw-r--r--tests/auto/declarative/qjsvalue/tst_qjsvalue.h205
-rw-r--r--tests/auto/declarative/qjsvalueiterator/qjsvalueiterator.pro5
-rw-r--r--tests/auto/declarative/qjsvalueiterator/tst_qjsvalueiterator.cpp527
-rw-r--r--tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro1
-rw-r--r--tests/auto/declarative/qsgborderimage/qsgborderimage.pro1
-rw-r--r--tests/auto/declarative/qsgflickable/qsgflickable.pro1
-rw-r--r--tests/auto/declarative/qsgflipable/qsgflipable.pro1
-rw-r--r--tests/auto/declarative/qsggridview/qsggridview.pro1
-rw-r--r--tests/auto/declarative/qsgitem2/qsgitem.pro1
-rw-r--r--tests/auto/declarative/qsglistview/qsglistview.pro1
-rw-r--r--tests/auto/declarative/qsgpathview/qsgpathview.pro1
-rw-r--r--tests/auto/declarative/qsgpositioners/qsgpositioners.pro1
-rw-r--r--tests/auto/declarative/qsgtext/qsgtext.pro1
-rw-r--r--tests/auto/declarative/qsgtextedit/qsgtextedit.pro1
-rw-r--r--tests/auto/declarative/qsgtextinput/qsgtextinput.pro1
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro1
-rw-r--r--tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro3
-rw-r--r--tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro4
-rw-r--r--tests/benchmarks/declarative/holistic/holistic.pro2
-rw-r--r--tests/benchmarks/declarative/holistic/testtypes.h2
-rw-r--r--tests/benchmarks/declarative/script/script.pro2
67 files changed, 11466 insertions, 93 deletions
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 43a2a682de..a99656a3ee 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -20,7 +20,10 @@ PUBLICTESTS += \
qdeclarativepixmapcache \
qdeclarativeqt \
qdeclarativetranslation \
- qdeclarativexmlhttprequest
+ qdeclarativexmlhttprequest \
+ qjsvalue \
+ qjsvalueiterator \
+ qjsengine
PRIVATETESTS += \
qdeclarativeanimations \
diff --git a/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro b/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
index 7109f2da65..50d63fea42 100644
--- a/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
+++ b/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script network
+QT += network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativecomponent.cpp
diff --git a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
index 564b088817..49150c8481 100644
--- a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
+++ b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro b/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
index 430224e1e8..cd5577219d 100644
--- a/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
+++ b/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
@@ -8,4 +8,4 @@ SOURCES += tst_qdeclarativedebug.cpp \
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro b/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
index 880255b6b2..189133a526 100644
--- a/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
+++ b/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
@@ -5,4 +5,4 @@ macx:CONFIG -= app_bundle
HEADERS += ../shared/debugutil_p.h
SOURCES += tst_qdeclarativedebugclient.cpp \
../shared/debugutil.cpp
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h b/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
index 84956d0bb7..c08f6fd639 100644
--- a/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
+++ b/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
@@ -48,7 +48,7 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QScriptEngine;
+class QJSEngine;
class QDeclarativeEngine;
// Helper methods to access private API through a stable interface
@@ -56,7 +56,7 @@ class QDeclarativeEngine;
class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
{
public:
- static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static QJSEngine *getScriptEngine(QDeclarativeEngine *engine);
static void setAnimationSlowDownFactor(qreal factor);
// Enables remote debugging functionality
diff --git a/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro b/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
index e9e8e73319..1e62c12363 100644
--- a/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
+++ b/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += network declarative script
+contains(QT_CONFIG,declarative): QT += network declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativedebughelper.cpp
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro b/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
index 55ddeb28a3..785e8a7bf1 100644
--- a/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
+++ b/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
@@ -8,4 +8,4 @@ SOURCES += tst_qdeclarativedebugservice.cpp \
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
index 03834ed428..4b7aff339c 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
+++ b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script network
+contains(QT_CONFIG,declarative): QT += declarative network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativeecmascript.cpp \
@@ -22,4 +22,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
index ea8d2c01c7..160a57215b 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
@@ -42,7 +42,7 @@
#include <QWidget>
#include <QPlainTextEdit>
#include <QDeclarativeEngine>
-#include <QScriptEngine>
+#include <QJSEngine>
class BaseExtensionObject : public QObject
{
@@ -101,17 +101,17 @@ public:
void setWidth(int) { }
};
-static QScriptValue script_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QJSValue script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
static int testProperty = 13;
- QScriptValue v = scriptEngine->newObject();
+ QJSValue v = scriptEngine->newObject();
v.setProperty("scriptTestProperty", testProperty++);
return v;
}
-static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QObject *qobject_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
@@ -122,7 +122,7 @@ static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEng
return o;
}
-static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(scriptEngine)
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
index aebfb22b7c..afb361e2d7 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
@@ -53,7 +53,7 @@
#include <QtGui/qvector3d.h>
#include <QtGui/QPixmap>
#include <QtCore/qdatetime.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtDeclarative/qdeclarativescriptstring.h>
#include <QtDeclarative/qdeclarativecomponent.h>
@@ -581,7 +581,7 @@ public:
}
};
-Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QJSValue);
class MyInvokableBaseObject : public QObject
{
Q_OBJECT
@@ -614,7 +614,7 @@ public:
Q_INVOKABLE QPointF method_NoArgs_QPointF() { invoke(3); return QPointF(123, 4.5); }
Q_INVOKABLE QObject *method_NoArgs_QObject() { invoke(4); return this; }
Q_INVOKABLE MyInvokableObject *method_NoArgs_unknown() { invoke(5); return this; }
- Q_INVOKABLE QScriptValue method_NoArgs_QScriptValue() { invoke(6); return QScriptValue("Hello world"); }
+ Q_INVOKABLE QJSValue method_NoArgs_QScriptValue() { invoke(6); return QJSValue("Hello world"); }
Q_INVOKABLE QVariant method_NoArgs_QVariant() { invoke(7); return QVariant("QML rocks"); }
Q_INVOKABLE void method_int(int a) { invoke(8); m_actuals << a; }
@@ -623,8 +623,8 @@ public:
Q_INVOKABLE void method_QString(QString a) { invoke(11); m_actuals << a; }
Q_INVOKABLE void method_QPointF(QPointF a) { invoke(12); m_actuals << a; }
Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_QScriptValue(QScriptValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_intQScriptValue(int a, QScriptValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
+ Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
+ Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; }
Q_INVOKABLE void method_overload(int a, int b) { invoke(17); m_actuals << a << b; }
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index b1bc5bda2b..6c629a80f7 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -49,7 +49,6 @@
#include <QtCore/qdir.h>
#include <QtCore/qnumeric.h>
#include <private/qdeclarativeengine_p.h>
-#include <private/qscriptdeclarativeclass_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
#include "../../../shared/util.h"
@@ -1600,7 +1599,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QDeclarativeEngine qmlengine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
- QV8Engine *engine = &ep->v8engine;
+ QV8Engine *engine = ep->v8engine();
v8::HandleScope handle_scope;
v8::Context::Scope scope(engine->context());
@@ -1693,8 +1692,6 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 5);
QCOMPARE(o.actuals().count(), 0);
- // XXX enable once qml/qtscript integration is implemented
-#if 0
o.reset();
{
v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
@@ -1704,7 +1701,6 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 6);
QCOMPARE(o.actuals().count(), 0);
}
-#endif
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
@@ -1920,35 +1916,33 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
- // XXX enable once qml/qtscript integration is implemented
-#if 0
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
@@ -1956,7 +1950,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(4));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
@@ -1964,7 +1958,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(8));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
@@ -1972,7 +1966,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(3));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
@@ -1980,8 +1974,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(44));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
-#endif
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
o.reset();
QVERIFY(EVALUATE_ERROR("object.method_overload()"));
diff --git a/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro b/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
index a3ca541485..a4cdd81266 100644
--- a/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
+++ b/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
SOURCES += tst_qdeclarativeinstruction.cpp
macx:CONFIG -= app_bundle
@@ -9,4 +9,4 @@ macx:CONFIG -= app_bundle
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
index 88dc6128ed..71d2066608 100644
--- a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
+++ b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script network
+QT += network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativelanguage.cpp \
@@ -20,4 +20,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
index 85340e70e6..83ea7992ed 100644
--- a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
+++ b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
@@ -1,6 +1,5 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativelistmodel.cpp
@@ -15,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
index d96b26aee9..fd55ed5160 100644
--- a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
+++ b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
index cd9dabf3bd..304e168e00 100644
--- a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
+++ b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
SOURCES += tst_qdeclarativeqt.cpp
macx:CONFIG -= app_bundle
@@ -16,4 +16,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
index 9187bea10b..cedb92743e 100644
--- a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
+++ b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativescriptdebugging.cpp
@@ -18,4 +18,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
index 5bc4261a28..c8f8e9139b 100644
--- a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
+++ b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
index 9885c6521e..f2b5928915 100644
--- a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
+++ b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
index c48cdf7b55..a51eaf34de 100644
--- a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
+++ b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += sql script
+QT += sql
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativesqldatabase.cpp
@@ -15,4 +15,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
index c34b8d8319..9823c21836 100644
--- a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
+++ b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
@@ -13,4 +13,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
index 0a2005d15d..9b66edff41 100644
--- a/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
+++ b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script network
+contains(QT_CONFIG,declarative): QT += declarative network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativev4.cpp \
@@ -16,4 +16,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
index f5567e96ed..f1c64398e9 100644
--- a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
+++ b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
@@ -17,4 +17,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
index 08ae7c164c..d7dfe96c65 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
+++ b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativeworkerscript.cpp
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
index cbf152bf8b..5e67360e15 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
+++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
@@ -43,7 +43,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtDeclarative/qdeclarativeengine.h>
diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
index bedd0a4602..139d4b4e0b 100644
--- a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
+++ b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script gui network
+contains(QT_CONFIG,declarative): QT += declarative gui network
contains(QT_CONFIG,xmlpatterns) {
QT += xmlpatterns
DEFINES += QTEST_XMLPATTERNS
@@ -18,4 +18,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qjsengine/qjsengine.pro b/tests/auto/declarative/qjsengine/qjsengine.pro
new file mode 100644
index 0000000000..87e52ce25d
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/qjsengine.pro
@@ -0,0 +1,21 @@
+load(qttest_p4)
+QT += declarative
+macx:CONFIG -= app_bundle
+SOURCES += tst_qjsengine.cpp
+
+wince* {
+ DEFINES += SRCDIR=\\\"./\\\"
+} else:!symbian {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+wince*|symbian: {
+ addFiles.files = script
+ addFiles.path = .
+ DEPLOYMENT += addFiles
+}
+
+symbian: {
+ TARGET.UID3 = 0xE0340006
+ DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x",""))
+}
diff --git a/tests/auto/declarative/qjsengine/script/com/__init__.js b/tests/auto/declarative/qjsengine/script/com/__init__.js
new file mode 100644
index 0000000000..7db3ee4cac
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/__init__.js
@@ -0,0 +1,9 @@
+var wasDefinedAlready = (this["com"] != undefined);
+__setupPackage__("com");
+com.wasDefinedAlready = wasDefinedAlready;
+com.name = __extension__;
+com.level = 1;
+
+com.postInitCallCount = 0;
+com.originalPostInit = __postInit__;
+__postInit__ = function() { ++com.postInitCallCount; };
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js
new file mode 100644
index 0000000000..a55b1328ba
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js
@@ -0,0 +1,9 @@
+var wasDefinedAlready = (com["trolltech"] != undefined);
+__setupPackage__("com.trolltech");
+com.trolltech.wasDefinedAlready = wasDefinedAlready;
+com.trolltech.name = __extension__;
+com.trolltech.level = com.level + 1;
+
+com.trolltech.postInitCallCount = 0;
+com.trolltech.originalPostInit = __postInit__;
+__postInit__ = function() { ++com.trolltech.postInitCallCount; };
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js
new file mode 100644
index 0000000000..2f4cad48da
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js
@@ -0,0 +1 @@
+__import__("com.trolltech.recursive");
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js
new file mode 100644
index 0000000000..55bc35b5f2
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js
@@ -0,0 +1,5 @@
+function () {
+}
+
+0 = 1;
+
diff --git a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp
new file mode 100644
index 0000000000..49febdbf5e
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp
@@ -0,0 +1,6491 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qjsengine.h>
+#include <qgraphicsitem.h>
+#include <qstandarditemmodel.h>
+#include <QtCore/qnumeric.h>
+#include <stdlib.h>
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QObjectList)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+#if defined(Q_OS_SYMBIAN)
+# define STRINGIFY(x) #x
+# define TOSTRING(x) STRINGIFY(x)
+# define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID)
+#endif
+
+// The JavaScriptCore GC marks the C stack. To try to ensure that there is
+// no JSObject* left in stack memory by the compiler, we call this function
+// to zap some bytes of memory before calling collectGarbage().
+static void zapSomeStack()
+{
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+}
+
+static void collectGarbage_helper(QJSEngine &eng)
+{
+ zapSomeStack();
+ eng.collectGarbage();
+}
+
+class tst_QJSEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QJSEngine();
+ virtual ~tst_QJSEngine();
+
+private slots:
+ void constructWithParent();
+#if 0 // FIXME: no QScriptContext
+ void currentContext();
+ void pushPopContext();
+#endif
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void getSetDefaultPrototype_int();
+ void getSetDefaultPrototype_customType();
+#endif
+#if 0 // FIXME: no QScriptContext
+ void newFunction();
+ void newFunctionWithArg();
+ void newFunctionWithProto();
+#endif
+ void newObject();
+ void newArray();
+ void newArray_HooliganTask218092();
+ void newArray_HooliganTask233836();
+ void newVariant();
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void newVariant_defaultPrototype();
+#endif
+#if 0 // ###FIXME: No QVariant object promotion API
+ void newVariant_promoteObject();
+ void newVariant_replaceValue();
+#endif
+ void newVariant_valueOfToString();
+#if 0 // ###FIXME: No QVariant object promotion API
+ void newVariant_promoteNonObject();
+ void newVariant_promoteNonQScriptObject();
+#endif
+ void newRegExp();
+ void jsRegExp();
+ void newDate();
+ void jsParseDate();
+ void newQObject();
+ void newQObject_ownership();
+ void newQObject_promoteObject();
+ void newQObject_sameQObject();
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void newQObject_defaultPrototype();
+#endif
+ void newQObject_promoteNonObject();
+ void newQObject_promoteNonQScriptObject();
+#if 0 // ### FIXME: No QScript Metaobject support right now
+ void newQMetaObject();
+ void newActivationObject();
+#endif
+#if 0 // ###FIXME: No setGlobalObject support - yay
+ void getSetGlobalObjectSimple();
+ void getSetGlobalObject();
+#endif
+ void globalObjectProperties();
+ void globalObjectEquals();
+#if 0 // ###FIXME: No QScriptValueIterator API
+ void globalObjectProperties_enumerate();
+#endif
+ void createGlobalObjectProperty();
+ void globalObjectGetterSetterProperty();
+#if 0 // ###FIXME: No support for setting the global object
+ void customGlobalObjectWithPrototype();
+#endif
+ void globalObjectWithCustomPrototype();
+ void builtinFunctionNames_data();
+ void builtinFunctionNames();
+#if 0 // ###FIXME: No syntax checking result
+ void checkSyntax_data();
+ void checkSyntax();
+#endif
+#if 0 // ###FIXME: No support for canEvaluate
+ void canEvaluate_data();
+ void canEvaluate();
+#endif
+ void evaluate_data();
+ void evaluate();
+#if 0 // ###FIXME: no support for c-style callbacks
+ void nestedEvaluate();
+#endif
+#if 0 // ### FIXME: No c-style callbacks
+ void uncaughtException();
+#endif
+ void errorMessage_QT679();
+ void valueConversion_basic();
+#if 0 // FIXME: No API for custom types
+ void valueConversion_customType();
+ void valueConversion_sequence();
+#endif
+ void valueConversion_QVariant();
+#if 0 // FIXME: No support for custom types
+ void valueConversion_hooliganTask248802();
+#endif
+ void valueConversion_basic2();
+ void valueConversion_dateTime();
+ void valueConversion_regExp();
+#if 0 // FIXME: No qScriptValueFromValue
+ void qScriptValueFromValue_noEngine();
+#endif
+#if 0 // ###FIXME: No QScriptContext
+ void importExtension();
+ void infiniteRecursion();
+#endif
+#if 0 // FIXME: No support for default prototypes
+ void castWithPrototypeChain();
+#endif
+ void castWithMultipleInheritance();
+#if 0 // ###FIXME: ScriptOwnership
+ void collectGarbage();
+#endif
+#if 0 // ###FIXME: no reportAdditionalMemoryCost API
+ void reportAdditionalMemoryCost();
+#endif
+ void gcWithNestedDataStructure();
+#if 0 // ###FIXME: No processEvents handling
+ void processEventsWhileRunning();
+ void processEventsWhileRunning_function();
+ void throwErrorFromProcessEvents_data();
+ void throwErrorFromProcessEvents();
+ void disableProcessEventsInterval();
+#endif
+#if 0 // ###FIXME: No QScriptValueIterator API
+ void stacktrace();
+#endif
+ void numberParsing_data();
+ void numberParsing();
+ void automaticSemicolonInsertion();
+#if 0 // ###FIXME: no abortEvaluation API
+ void abortEvaluation_notEvaluating();
+ void abortEvaluation_data();
+ void abortEvaluation();
+ void abortEvaluation_tryCatch();
+ void abortEvaluation_fromNative();
+ void abortEvaluation_QTBUG9433();
+#endif
+#if 0 // ###FIXME: no QScriptEngine::isEvaluating
+ void isEvaluating_notEvaluating();
+ void isEvaluating_fromNative();
+ void isEvaluating_fromEvent();
+#endif
+#if 0 // ###FIXME: depracated
+ void printFunctionWithCustomHandler();
+ void printThrowsException();
+#endif
+ void errorConstructors();
+ void argumentsProperty_globalContext();
+ void argumentsProperty_JS();
+#if 0 // ###FIXME: no QScriptContext API
+ void argumentsProperty_evaluateInNativeFunction();
+#endif
+ void jsNumberClass();
+ void jsForInStatement_simple();
+ void jsForInStatement_prototypeProperties();
+ void jsForInStatement_mutateWhileIterating();
+ void jsForInStatement_arrays();
+ void jsForInStatement_nullAndUndefined();
+ void jsFunctionDeclarationAsStatement();
+ void stringObjects();
+ void jsStringPrototypeReplaceBugs();
+ void getterSetterThisObject_global();
+ void getterSetterThisObject_plain();
+ void getterSetterThisObject_prototypeChain();
+#if 0 // ###FIXME: no QScriptContext API
+ void getterSetterThisObject_activation();
+#endif
+ void jsContinueInSwitch();
+ void jsShadowReadOnlyPrototypeProperty();
+ void toObject();
+ void jsReservedWords_data();
+ void jsReservedWords();
+ void jsFutureReservedWords_data();
+ void jsFutureReservedWords();
+ void jsThrowInsideWithStatement();
+#if 0 // ###FIXME: No QScriptEngineAgent API
+ void getSetAgent_ownership();
+ void getSetAgent_deleteAgent();
+ void getSetAgent_differentEngine();
+#endif
+#if 0 // ###FIXME: No QScriptString API
+ void reentrancy_stringHandles();
+#endif
+#if 0 // ###FIXME: No processEventsInterval API
+ void reentrancy_processEventsInterval();
+#endif
+#if 0 // FIXME: No support for custom types
+ void reentrancy_typeConversion();
+#endif
+ void reentrancy_globalObjectProperties();
+ void reentrancy_Array();
+ void reentrancy_objectCreation();
+ void jsIncDecNonObjectProperty();
+#if 0 // ###FIXME: no installTranslatorFunctions API
+ void installTranslatorFunctions();
+ void translateScript_data();
+ void translateScript();
+ void translateScript_crossScript();
+ void translateScript_callQsTrFromNative();
+ void translateScript_trNoOp();
+ void translateScript_callQsTrFromCpp();
+ void translateWithInvalidArgs_data();
+ void translateWithInvalidArgs();
+ void translationContext_data();
+ void translationContext();
+ void translateScriptIdBased();
+ void translateScriptUnicode_data();
+ void translateScriptUnicode();
+ void translateScriptUnicodeIdBased_data();
+ void translateScriptUnicodeIdBased();
+ void translateFromBuiltinCallback();
+#endif
+#if 0 // ###FIXME: No QScriptValue::scope API
+ void functionScopes();
+#endif
+#if 0 // ###FIXME: No QScriptContext API
+ void nativeFunctionScopes();
+#endif
+#if 0 // ###FIXME: No QScriptProgram API
+ void evaluateProgram();
+ void evaluateProgram_customScope();
+ void evaluateProgram_closure();
+ void evaluateProgram_executeLater();
+ void evaluateProgram_multipleEngines();
+ void evaluateProgram_empty();
+#endif
+#if 0 // ###FIXME: No QScriptContext API
+ void collectGarbageAfterConnect();
+ void collectGarbageAfterNativeArguments();
+ void promoteThisObjectToQObjectInConstructor();
+#endif
+#if 0 // ###FIXME: No QScript MetaObject API
+ void scriptValueFromQMetaObject();
+#endif
+
+ void qRegExpInport_data();
+ void qRegExpInport();
+#if 0 // ###FIXME: No QScriptContext API
+ void reentrency();
+#endif
+#if 0 // ###FIXME: No QSCriptDeclarativeClass API
+ void newFixedStaticScopeObject();
+ void newGrowingStaticScopeObject();
+#endif
+ void dateRoundtripJSQtJS();
+ void dateRoundtripQtJSQt();
+ void dateConversionJSQt();
+ void dateConversionQtJS();
+};
+
+tst_QJSEngine::tst_QJSEngine()
+{
+}
+
+tst_QJSEngine::~tst_QJSEngine()
+{
+}
+
+void tst_QJSEngine::constructWithParent()
+{
+ QPointer<QJSEngine> ptr;
+ {
+ QObject obj;
+ QJSEngine *engine = new QJSEngine(&obj);
+ ptr = engine;
+ }
+ QVERIFY(ptr == 0);
+}
+
+#if 0 // FIXME: no QScriptContext
+void tst_QJSEngine::currentContext()
+{
+ QScriptEngine eng;
+ QScriptContext *globalCtx = eng.currentContext();
+ QVERIFY(globalCtx != 0);
+ QVERIFY(globalCtx->parentContext() == 0);
+ QCOMPARE(globalCtx->engine(), &eng);
+ QCOMPARE(globalCtx->argumentCount(), 0);
+ QCOMPARE(globalCtx->backtrace().size(), 1);
+ QVERIFY(!globalCtx->isCalledAsConstructor());
+ QVERIFY(!globalCtx->callee().isValid());
+ QCOMPARE(globalCtx->state(), QScriptContext::NormalState);
+ QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject()));
+ QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject()));
+ QVERIFY(globalCtx->argumentsObject().isObject());
+}
+
+void tst_QJSEngine::pushPopContext()
+{
+ QScriptEngine eng;
+ QScriptContext *globalCtx = eng.currentContext();
+ QScriptContext *ctx = eng.pushContext();
+ QVERIFY(ctx != 0);
+ QCOMPARE(ctx->parentContext(), globalCtx);
+ QVERIFY(!ctx->isCalledAsConstructor());
+ QVERIFY(!ctx->callee().isValid());
+ QVERIFY(ctx->thisObject().strictlyEquals(eng.globalObject()));
+ QCOMPARE(ctx->argumentCount(), 0);
+ QCOMPARE(ctx->backtrace().size(), 2);
+ QCOMPARE(ctx->engine(), &eng);
+ QCOMPARE(ctx->state(), QScriptContext::NormalState);
+ QVERIFY(ctx->activationObject().isObject());
+ QVERIFY(ctx->argumentsObject().isObject());
+
+ QScriptContext *ctx2 = eng.pushContext();
+ QVERIFY(ctx2 != 0);
+ QCOMPARE(ctx2->parentContext(), ctx);
+ QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject()));
+ QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject()));
+
+ eng.popContext();
+ eng.popContext();
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
+ eng.popContext(); // ignored
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
+ eng.popContext(); // ignored
+}
+
+static QScriptValue myFunction(QScriptContext *, QScriptEngine *eng)
+{
+ return eng->nullValue();
+}
+
+static QScriptValue myFunctionWithVoidArg(QScriptContext *, QScriptEngine *eng, void *)
+{
+ return eng->nullValue();
+}
+
+static QScriptValue myThrowingFunction(QScriptContext *ctx, QScriptEngine *)
+{
+ return ctx->throwError("foo");
+}
+
+static QScriptValue myFunctionThatReturns(QScriptContext *, QScriptEngine *eng)
+{
+ return QScriptValue(eng, 42);
+}
+
+static QScriptValue myFunctionThatReturnsWithoutEngine(QScriptContext *, QScriptEngine *)
+{
+ return QScriptValue(1024);
+}
+
+static QScriptValue myFunctionThatReturnsWrongEngine(QScriptContext *, QScriptEngine *, void *arg)
+{
+ QScriptEngine* wrongEngine = reinterpret_cast<QScriptEngine*>(arg);
+ return QScriptValue(wrongEngine, 42);
+}
+
+static QScriptValue sumFunction(QScriptContext *context, QScriptEngine *engine)
+{
+ int sum = 0;
+
+ for (int i = 0; i < context->argumentCount(); i++) {
+ QScriptValue n = context->argument(i);
+ if (n.isNumber())
+ sum += n.toInteger();
+ }
+
+ return QScriptValue(engine, sum);
+}
+
+void tst_QJSEngine::newFunction()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+}
+
+void tst_QJSEngine::newFunctionWithArg()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(myFunctionWithVoidArg, (void*)this);
+ QVERIFY(fun.isFunction());
+ QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+}
+
+void tst_QJSEngine::newFunctionWithProto()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue proto = eng.newObject();
+ QScriptValue fun = eng.newFunction(myFunction, proto);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ // internal prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+ // public prototype should be the one we passed
+ QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
+ QCOMPARE(proto.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+ // whether the return value is correct
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturns);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 42);
+ }
+ // whether the return value is assigned to the correct engine
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWithoutEngine);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.engine(), &eng);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 1024);
+ }
+ // whether the return value is undefined when returning a value with wrong engine
+ {
+ QScriptEngine wrongEngine;
+
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWrongEngine, reinterpret_cast<void *>(&wrongEngine));
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::call(): Value from different engine returned from native function, returning undefined value instead.");
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isValid(), true);
+ QCOMPARE(result.isUndefined(), true);
+ }
+ // checking if arguments are passed correctly
+ {
+ QScriptEngine wrongEngine;
+
+ QScriptValue fun = eng.newFunction(sumFunction);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 0);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 1);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1 << 2 << 3);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 6);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1 << 2 << 3 << 4);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 10);
+ }
+}
+#endif
+
+void tst_QJSEngine::newObject()
+{
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.isValid(), true);
+ QCOMPARE(object.isObject(), true);
+ QCOMPARE(object.isFunction(), false);
+// ###FIXME: No QScriptClass QCOMPARE(object.scriptClass(), (QScriptClass*)0);
+ // prototype should be Object.prototype
+ QCOMPARE(object.prototype().isValid(), true);
+ QCOMPARE(object.prototype().isObject(), true);
+ QCOMPARE(object.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
+}
+
+void tst_QJSEngine::newArray()
+{
+ QJSEngine eng;
+ QJSValue array = eng.newArray();
+ QCOMPARE(array.isValid(), true);
+ QCOMPARE(array.isArray(), true);
+ QCOMPARE(array.isObject(), true);
+ QVERIFY(!array.isFunction());
+// ###FIXME: No QScriptClass QCOMPARE(array.scriptClass(), (QScriptClass*)0);
+ // prototype should be Array.prototype
+ QCOMPARE(array.prototype().isValid(), true);
+ QCOMPARE(array.prototype().isArray(), true);
+ QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true);
+}
+
+void tst_QJSEngine::newArray_HooliganTask218092()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("[].splice(0, 0, 'a')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 0);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+}
+
+void tst_QJSEngine::newArray_HooliganTask233836()
+{
+ QJSEngine eng;
+ {
+ // According to ECMA-262, this should cause a RangeError.
+ QJSValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')");
+ QVERIFY(ret.isError() && ret.toString().contains(QLatin1String("RangeError")));
+ }
+ {
+ QJSValue ret = eng.newArray(0xFFFFFFFF);
+ QEXPECT_FAIL("", "The maximum length of arrays is defined by v8 currently and differs from QtScript", Abort);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ ret.setProperty(0xFFFFFFFF, 123);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ QVERIFY(ret.property(0xFFFFFFFF).isNumber());
+ QCOMPARE(ret.property(0xFFFFFFFF).toInt32(), 123);
+ ret.setProperty(123, 456);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ QVERIFY(ret.property(123).isNumber());
+ QCOMPARE(ret.property(123).toInt32(), 456);
+ }
+}
+
+void tst_QJSEngine::newVariant()
+{
+ QJSEngine eng;
+ {
+ QJSValue opaque = eng.newVariant(QVariant());
+ QCOMPARE(opaque.isValid(), true);
+ QCOMPARE(opaque.isVariant(), true);
+ QVERIFY(!opaque.isFunction());
+ QCOMPARE(opaque.isObject(), true);
+ QCOMPARE(opaque.prototype().isValid(), true);
+ QEXPECT_FAIL("", "FIXME: newly created QObject's prototype is an JS Object", Continue);
+ QCOMPARE(opaque.prototype().isVariant(), true);
+ QVERIFY(opaque.property("valueOf").call(opaque).isUndefined());
+ }
+}
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::newVariant_defaultPrototype()
+{
+ // default prototype should be set automatically
+ QScriptEngine eng;
+ {
+ QScriptValue proto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<QString>(), proto);
+ QScriptValue ret = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QVERIFY(ret.isVariant());
+// ###FIXME: No QScriptClass QCOMPARE(ret.scriptClass(), (QScriptClass*)0);
+ QVERIFY(ret.prototype().strictlyEquals(proto));
+ eng.setDefaultPrototype(qMetaTypeId<QString>(), QScriptValue());
+ QScriptValue ret2 = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QVERIFY(ret2.isVariant());
+ QVERIFY(!ret2.prototype().strictlyEquals(proto));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QVariant object promotion API
+void tst_QJSEngine::newVariant_promoteObject()
+{
+ // "promote" plain object to variant
+ QScriptEngine eng;
+ {
+ QScriptValue object = eng.newObject();
+ object.setProperty("foo", eng.newObject());
+ object.setProperty("bar", object.property("foo"));
+ QVERIFY(object.property("foo").isObject());
+ QVERIFY(!object.property("foo").isVariant());
+ QScriptValue originalProto = object.property("foo").prototype();
+ QSKIP("It is not possible to promote plain object to a wrapper", SkipAll);
+ QScriptValue ret = eng.newVariant(object.property("foo"), QVariant(123));
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.strictlyEquals(object.property("foo")));
+ QVERIFY(ret.isVariant());
+ QVERIFY(object.property("foo").isVariant());
+ QVERIFY(object.property("bar").isVariant());
+ QCOMPARE(ret.toVariant(), QVariant(123));
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+}
+
+void tst_QJSEngine::newVariant_replaceValue()
+{
+ // replace value of existing object
+ QScriptEngine eng;
+ {
+ QScriptValue object = eng.newVariant(QVariant(123));
+ for (int x = 0; x < 2; ++x) {
+ QScriptValue ret = eng.newVariant(object, QVariant(456));
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.strictlyEquals(object));
+ QVERIFY(ret.isVariant());
+ QCOMPARE(ret.toVariant(), QVariant(456));
+ }
+ }
+}
+#endif
+
+void tst_QJSEngine::newVariant_valueOfToString()
+{
+ // valueOf() and toString()
+ QJSEngine eng;
+ {
+ QJSValue object = eng.newVariant(QVariant(123));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isNumber());
+ QCOMPARE(value.toInt32(), 123);
+ QCOMPARE(object.toString(), QString::fromLatin1("123"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isString());
+ QCOMPARE(value.toString(), QString::fromLatin1("hello"));
+ QCOMPARE(object.toString(), QString::fromLatin1("hello"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(false));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isBoolean());
+ QCOMPARE(value.toBoolean(), false);
+ QCOMPARE(object.toString(), QString::fromLatin1("false"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(QPoint(10, 20)));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isObject());
+ QVERIFY(value.strictlyEquals(object));
+ QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint)"));
+ }
+}
+
+#if 0 // ###FIXME: No QVariant object promotion API
+void tst_QJSEngine::newVariant_promoteNonObject()
+{
+ QScriptEngine eng;
+ {
+ QVariant var(456);
+ QScriptValue ret = eng.newVariant(123, var);
+ QVERIFY(ret.isVariant());
+ QCOMPARE(ret.toVariant(), var);
+ }
+}
+
+void tst_QJSEngine::newVariant_promoteNonQScriptObject()
+{
+ QSKIP("This test relay on limitation of QtScript JSC implementation", SkipAll);
+ QScriptEngine eng;
+ {
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
+ QScriptValue ret = eng.newVariant(eng.newArray(), 123);
+ QVERIFY(!ret.isValid());
+ }
+}
+#endif
+
+void tst_QJSEngine::newRegExp()
+{
+ QJSEngine eng;
+ for (int x = 0; x < 2; ++x) {
+ QJSValue rexp;
+ if (x == 0)
+ rexp = eng.newRegExp("foo", "bar");
+ else
+ rexp = eng.newRegExp(QRegExp("foo"));
+ QCOMPARE(rexp.isValid(), true);
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isObject(), true);
+ QVERIFY(rexp.isFunction()); // in JSC, RegExp objects are callable
+ // prototype should be RegExp.prototype
+ QCOMPARE(rexp.prototype().isValid(), true);
+ QCOMPARE(rexp.prototype().isObject(), true);
+ QCOMPARE(rexp.prototype().isRegExp(), false);
+ QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
+
+ QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern());
+ }
+}
+
+void tst_QJSEngine::jsRegExp()
+{
+ // See ECMA-262 Section 15.10, "RegExp Objects".
+ // These should really be JS-only tests, as they test the implementation's
+ // ECMA-compliance, not the C++ API. Compliance should already be covered
+ // by the Mozilla tests (qscriptjstestsuite).
+ // We can consider updating the expected results of this test if the
+ // RegExp implementation changes.
+
+ QJSEngine eng;
+ QJSValue r = eng.evaluate("/foo/gim");
+ QVERIFY(r.isRegExp());
+ QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
+
+ QJSValue rxCtor = eng.globalObject().property("RegExp");
+ QJSValue r2 = rxCtor.call(QJSValue(), QJSValueList() << r);
+ QVERIFY(r2.isRegExp());
+ QVERIFY(r2.strictlyEquals(r));
+
+ QJSValue r3 = rxCtor.call(QJSValue(), QJSValueList() << r << "gim");
+ QVERIFY(r3.isError());
+ QVERIFY(r3.toString().contains(QString::fromLatin1("TypeError"))); // Cannot supply flags when constructing one RegExp from another
+
+ QJSValue r4 = rxCtor.call(QJSValue(), QJSValueList() << "foo" << "gim");
+ QVERIFY(r4.isRegExp());
+
+ QJSValue r5 = rxCtor.construct(QJSValueList() << r);
+ QVERIFY(r5.isRegExp());
+ QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
+ // In JSC, constructing a RegExp from another produces the same identical object.
+ // This is different from SpiderMonkey and old back-end.
+ QVERIFY(!r5.strictlyEquals(r));
+
+ QEXPECT_FAIL("", "V8 and jsc ignores invalid flags", Continue); //https://bugs.webkit.org/show_bug.cgi?id=41614
+ QJSValue r6 = rxCtor.construct(QJSValueList() << "foo" << "bar");
+ QVERIFY(r6.isError());
+ // QVERIFY(r6.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
+
+
+ QJSValue r7 = eng.evaluate("/foo/gimp");
+ /* v8 and jsc ignores invalid flags
+ QVERIFY(r7.isError());
+ QVERIFY(r7.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
+ */
+
+ // JSC doesn't complain about duplicate flags.
+ QJSValue r8 = eng.evaluate("/foo/migmigmig");
+ QVERIFY(r8.isRegExp());
+ QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
+
+ QJSValue r9 = rxCtor.construct();
+ QVERIFY(r9.isRegExp());
+ QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
+
+ QJSValue r10 = rxCtor.construct(QJSValueList() << "" << "gim");
+ QVERIFY(r10.isRegExp());
+ QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
+
+ QJSValue r11 = rxCtor.construct(QJSValueList() << "{1.*}" << "g");
+ QVERIFY(r11.isRegExp());
+ QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
+}
+
+void tst_QJSEngine::newDate()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue date = eng.newDate(0);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ QVERIFY(!date.isFunction());
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+ }
+
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime);
+ QJSValue date = eng.newDate(dt);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+
+ QCOMPARE(date.toDateTime(), dt);
+ }
+
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC);
+ QJSValue date = eng.newDate(dt);
+ // toDateTime() result should be in local time
+ QCOMPARE(date.toDateTime(), dt.toLocalTime());
+ }
+}
+
+void tst_QJSEngine::jsParseDate()
+{
+ QJSEngine eng;
+ // Date.parse() should return NaN when it fails
+ {
+ QJSValue ret = eng.evaluate("Date.parse()");
+ QVERIFY(ret.isNumber());
+ QVERIFY(qIsNaN(ret.toNumber()));
+ }
+
+ // Date.parse() should be able to parse the output of Date().toString()
+#ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed
+ {
+ QJSValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
+ QVERIFY(ret.isBoolean());
+ QCOMPARE(ret.toBoolean(), true);
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue qobject = eng.newQObject(0);
+ QCOMPARE(qobject.isValid(), true);
+ QCOMPARE(qobject.isNull(), true);
+ QCOMPARE(qobject.isObject(), false);
+ QCOMPARE(qobject.toQObject(), (QObject *)0);
+ }
+ {
+ QJSValue qobject = eng.newQObject(this);
+ QCOMPARE(qobject.isValid(), true);
+ QCOMPARE(qobject.isQObject(), true);
+ QCOMPARE(qobject.isObject(), true);
+ QCOMPARE(qobject.toQObject(), (QObject *)this);
+ QVERIFY(!qobject.isFunction());
+ // prototype should be QObject.prototype
+ QCOMPARE(qobject.prototype().isValid(), true);
+ QEXPECT_FAIL("", "FIXME: newly created QObject's prototype is an JS Object", Continue);
+ QCOMPARE(qobject.prototype().isQObject(), true);
+// ###FIXME: No QScriptClass QCOMPARE(qobject.scriptClass(), (QScriptClass*)0);
+ }
+}
+
+void tst_QJSEngine::newQObject_ownership()
+{
+#if 0 // FIXME: ownership tests need to be revivewed
+ QScriptEngine eng;
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
+ }
+ eng.evaluate("gc()");
+ if (ptr)
+ QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
+ QVERIFY(ptr == 0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::QtOwnership);
+ }
+ QObject *before = ptr;
+ eng.evaluate("gc()");
+ QVERIFY(ptr == before);
+ delete ptr;
+ }
+ {
+ QObject *parent = new QObject();
+ QObject *child = new QObject(parent);
+ QScriptValue v = eng.newQObject(child, QScriptEngine::QtOwnership);
+ QCOMPARE(v.toQObject(), child);
+ delete parent;
+ QCOMPARE(v.toQObject(), (QObject *)0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::AutoOwnership);
+ }
+ eng.evaluate("gc()");
+ // no parent, so it should be like ScriptOwnership
+ if (ptr)
+ QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
+ QVERIFY(ptr == 0);
+ }
+ {
+ QObject *parent = new QObject();
+ QPointer<QObject> child = new QObject(parent);
+ QVERIFY(child != 0);
+ {
+ QScriptValue v = eng.newQObject(child, QScriptEngine::AutoOwnership);
+ }
+ eng.evaluate("gc()");
+ // has parent, so it should be like QtOwnership
+ QVERIFY(child != 0);
+ delete parent;
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_promoteObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QScriptEngine eng;
+ // "promote" plain object to QObject
+ {
+ QScriptValue obj = eng.newObject();
+ QScriptValue originalProto = obj.prototype();
+ QScriptValue ret = eng.newQObject(obj, this);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ QVERIFY(obj.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject *)this);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ QScriptValue val = ret.property("objectName");
+ QVERIFY(val.isString());
+ }
+ // "promote" variant object to QObject
+ {
+ QScriptValue obj = eng.newVariant(123);
+ QVERIFY(obj.isVariant());
+ QScriptValue originalProto = obj.prototype();
+ QScriptValue ret = eng.newQObject(obj, this);
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ QVERIFY(obj.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject *)this);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+ // replace QObject* of existing object
+ {
+ QScriptValue object = eng.newVariant(123);
+ QScriptValue originalProto = object.prototype();
+ QObject otherQObject;
+ for (int x = 0; x < 2; ++x) {
+ QScriptValue ret = eng.newQObject(object, &otherQObject);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(object));
+ QCOMPARE(ret.toQObject(), (QObject *)&otherQObject);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_sameQObject()
+{
+#if 0 // ###FIXME: No QObjectWrapOptions API
+ QSKIP("This test stongly relay on strictlyEquals feature that would change in near future", SkipAll);
+ QScriptEngine eng;
+ // calling newQObject() several times with same object
+ for (int x = 0; x < 2; ++x) {
+ QObject qobj;
+ // the default is to create a new wrapper object
+ QScriptValue obj1 = eng.newQObject(&qobj);
+ QScriptValue obj2 = eng.newQObject(&qobj);
+ QVERIFY(!obj2.strictlyEquals(obj1));
+
+ QScriptEngine::QObjectWrapOptions opt = 0;
+ bool preferExisting = (x != 0);
+ if (preferExisting)
+ opt |= QScriptEngine::PreferExistingWrapperObject;
+
+ QScriptValue obj3 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
+ QVERIFY(!obj3.strictlyEquals(obj2));
+ QScriptValue obj4 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
+ QCOMPARE(obj4.strictlyEquals(obj3), preferExisting);
+
+ QScriptValue obj5 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
+ QVERIFY(!obj5.strictlyEquals(obj4));
+ QScriptValue obj6 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
+ QCOMPARE(obj6.strictlyEquals(obj5), preferExisting);
+
+ QScriptValue obj7 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
+ QScriptEngine::ExcludeSuperClassMethods | opt);
+ QVERIFY(!obj7.strictlyEquals(obj6));
+ QScriptValue obj8 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
+ QScriptEngine::ExcludeSuperClassMethods | opt);
+ QCOMPARE(obj8.strictlyEquals(obj7), preferExisting);
+ }
+#endif
+}
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::newQObject_defaultPrototype()
+{
+ QScriptEngine eng;
+ // newQObject() should set the default prototype, if one has been registered
+ {
+ QScriptValue oldQObjectProto = eng.defaultPrototype(qMetaTypeId<QObject*>());
+
+ QScriptValue qobjectProto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<QObject*>(), qobjectProto);
+ {
+ QScriptValue ret = eng.newQObject(this);
+ QVERIFY(ret.prototype().equals(qobjectProto));
+ }
+ QScriptValue tstProto = eng.newObject();
+ int typeId = qRegisterMetaType<tst_QJSEngine*>("tst_QJSEngine*");
+ eng.setDefaultPrototype(typeId, tstProto);
+ {
+ QScriptValue ret = eng.newQObject(this);
+ QVERIFY(ret.prototype().equals(tstProto));
+ }
+
+ eng.setDefaultPrototype(qMetaTypeId<QObject*>(), oldQObjectProto);
+ eng.setDefaultPrototype(typeId, QScriptValue());
+ }
+}
+#endif
+
+void tst_QJSEngine::newQObject_promoteNonObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QScriptEngine eng;
+ {
+ QScriptValue ret = eng.newQObject(123, this);
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), this);
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_promoteNonQScriptObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QSKIP("Promotion of non QScriptObjects kind of works (there is not difference between Object and Array, look at comments in newQObject implementation).", SkipAll);
+ QScriptEngine eng;
+ {
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
+ QScriptValue ret = eng.newQObject(eng.newArray(), this);
+ QVERIFY(!ret.isValid());
+ }
+#endif
+}
+
+#if 0 // ### FIXME: No QScript Metaobject support right now
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
+Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget, QWidget*)
+QT_END_NAMESPACE
+
+static QScriptValue myConstructor(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue obj;
+ if (ctx->isCalledAsConstructor()) {
+ obj = ctx->thisObject();
+ } else {
+ obj = eng->newObject();
+ obj.setPrototype(ctx->callee().property("prototype"));
+ }
+ obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
+ return obj;
+}
+
+static QScriptValue instanceofJS(const QScriptValue &inst, const QScriptValue &ctor)
+{
+ return inst.engine()->evaluate("(function(inst, ctor) { return inst instanceof ctor; })")
+ .call(QScriptValue(), QScriptValueList() << inst << ctor);
+}
+
+void tst_QJSEngine::newQMetaObject()
+{
+ QScriptEngine eng;
+#if 0
+ QScriptValue qclass = eng.newQMetaObject<QObject>();
+ QScriptValue qclass2 = eng.newQMetaObject<QWidget>();
+#else
+ QScriptValue qclass = qScriptValueFromQMetaObject<QObject>(&eng);
+ QScriptValue qclass2 = qScriptValueFromQMetaObject<QWidget>(&eng);
+#endif
+ QCOMPARE(qclass.isValid(), true);
+ QCOMPARE(qclass.isQMetaObject(), true);
+ QCOMPARE(qclass.toQMetaObject(), &QObject::staticMetaObject);
+ QCOMPARE(qclass.isFunction(), true);
+ QVERIFY(qclass.property("prototype").isObject());
+
+ QCOMPARE(qclass2.isValid(), true);
+ QCOMPARE(qclass2.isQMetaObject(), true);
+ QCOMPARE(qclass2.toQMetaObject(), &QWidget::staticMetaObject);
+ QCOMPARE(qclass2.isFunction(), true);
+ QVERIFY(qclass2.property("prototype").isObject());
+
+ // prototype should be QMetaObject.prototype
+ QCOMPARE(qclass.prototype().isObject(), true);
+ QCOMPARE(qclass2.prototype().isObject(), true);
+
+ QScriptValue instance = qclass.construct();
+ QCOMPARE(instance.isQObject(), true);
+ QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
+ QEXPECT_FAIL("", "FIXME: newQMetaObject not implemented properly yet", Abort);
+ QVERIFY(instance.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance, qclass).strictlyEquals(true));
+
+ QScriptValue instance2 = qclass2.construct();
+ QCOMPARE(instance2.isQObject(), true);
+ QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
+ QVERIFY(instance2.instanceOf(qclass2));
+ QVERIFY(instanceofJS(instance2, qclass2).strictlyEquals(true));
+ QVERIFY(!instance2.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance2, qclass).strictlyEquals(false));
+
+ QScriptValueList args;
+ args << instance;
+ QScriptValue instance3 = qclass.construct(args);
+ QCOMPARE(instance3.isQObject(), true);
+ QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
+ QVERIFY(instance3.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance3, qclass).strictlyEquals(true));
+ QVERIFY(!instance3.instanceOf(qclass2));
+ QVERIFY(instanceofJS(instance3, qclass2).strictlyEquals(false));
+ args.clear();
+
+ QPointer<QObject> qpointer1 = instance.toQObject();
+ QPointer<QObject> qpointer2 = instance2.toQObject();
+ QPointer<QObject> qpointer3 = instance3.toQObject();
+
+ QVERIFY(qpointer1);
+ QVERIFY(qpointer2);
+ QVERIFY(qpointer3);
+
+ // verify that AutoOwnership is in effect
+ instance = QScriptValue();
+ collectGarbage_helper(eng);
+
+ QVERIFY(!qpointer1);
+ QVERIFY(qpointer2);
+ QVERIFY(!qpointer3); // was child of instance
+
+ QVERIFY(instance.toQObject() == 0);
+ QVERIFY(instance3.toQObject() == 0); // was child of instance
+ QVERIFY(instance2.toQObject() != 0);
+ instance2 = QScriptValue();
+ collectGarbage_helper(eng);
+ QVERIFY(instance2.toQObject() == 0);
+
+ // with custom constructor
+ QScriptValue ctor = eng.newFunction(myConstructor);
+ QScriptValue qclass3 = eng.newQMetaObject(&QObject::staticMetaObject, ctor);
+ QVERIFY(qclass3.property("prototype").equals(ctor.property("prototype")));
+ {
+ QScriptValue ret = qclass3.call();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
+ QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
+ QVERIFY(ret.instanceOf(qclass3));
+ QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
+ QVERIFY(!ret.instanceOf(qclass));
+ QVERIFY(instanceofJS(ret, qclass).strictlyEquals(false));
+ }
+ {
+ QScriptValue ret = qclass3.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
+ QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
+ QVERIFY(ret.instanceOf(qclass3));
+ QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
+ QVERIFY(!ret.instanceOf(qclass2));
+ QVERIFY(instanceofJS(ret, qclass2).strictlyEquals(false));
+ }
+
+ // subclassing
+ qclass2.setProperty("prototype", qclass.construct());
+ QVERIFY(qclass2.construct().instanceOf(qclass));
+ QVERIFY(instanceofJS(qclass2.construct(), qclass).strictlyEquals(true));
+
+ // with meta-constructor
+ QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
+ {
+ QScriptValue inst = qclass4.construct();
+ QVERIFY(inst.isQObject());
+ QVERIFY(inst.toQObject() != 0);
+ QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
+ QVERIFY(inst.instanceOf(qclass4));
+ QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
+ QVERIFY(!inst.instanceOf(qclass3));
+ QVERIFY(instanceofJS(inst, qclass3).strictlyEquals(false));
+ }
+ {
+ QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
+ QVERIFY(inst.isQObject());
+ QVERIFY(inst.toQObject() != 0);
+ QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
+ QVERIFY(inst.instanceOf(qclass4));
+ QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
+ QVERIFY(!inst.instanceOf(qclass2));
+ QVERIFY(instanceofJS(inst, qclass2).strictlyEquals(false));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No activation object support
+void tst_QJSEngine::newActivationObject()
+{
+ QSKIP("internal function not implemented in JSC-based back-end", SkipAll);
+ QScriptEngine eng;
+ QScriptValue act = eng.newActivationObject();
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.isValid(), true);
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.isObject(), true);
+ QVERIFY(!act.isFunction());
+ QScriptValue v(&eng, 123);
+ act.setProperty("prop", v);
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.property("prop").strictlyEquals(v), true);
+ QCOMPARE(act.scope().isValid(), false);
+ QEXPECT_FAIL("", "", Continue);
+ QVERIFY(act.prototype().isNull());
+}
+#endif
+
+#if 0 // ###FIXME: No setGlobalObject support - yay
+void tst_QJSEngine::getSetGlobalObjectSimple()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", 123);
+ engine.evaluate("var bar = 100");
+ engine.setGlobalObject(object);
+ engine.evaluate("rab = 100");
+ QVERIFY(engine.globalObject().property("rab").isValid());
+ QVERIFY(engine.globalObject().property("foo").isValid());
+ QVERIFY(!engine.globalObject().property("bar").isValid());
+}
+
+void tst_QJSEngine::getSetGlobalObject()
+{
+ QScriptEngine eng;
+ QScriptValue glob = eng.globalObject();
+ glob = QScriptValue(); // kill reference to old global object
+ collectGarbage_helper(eng);
+
+ glob = eng.globalObject();
+ QCOMPARE(glob.isValid(), true);
+ QCOMPARE(glob.isObject(), true);
+ QVERIFY(!glob.isFunction());
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob));
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(glob.toString(), QString::fromLatin1("[object global]"));
+ // prototype should be Object.prototype
+ QCOMPARE(glob.prototype().isValid(), true);
+ QCOMPARE(glob.prototype().isObject(), true);
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(glob.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
+
+ eng.setGlobalObject(glob);
+ QVERIFY(eng.globalObject().equals(glob));
+ eng.setGlobalObject(123);
+ QVERIFY(eng.globalObject().equals(glob));
+
+ QScriptValue obj = eng.newObject();
+ eng.setGlobalObject(obj);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+ QVERIFY(eng.evaluate("this").strictlyEquals(obj));
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object global]"));
+
+ collectGarbage_helper(eng);
+ glob = QScriptValue(); // kill reference to old global object
+ collectGarbage_helper(eng);
+ obj = eng.newObject();
+ eng.setGlobalObject(obj);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+
+ collectGarbage_helper(eng);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+
+ QVERIFY(!obj.property("foo").isValid());
+ eng.evaluate("var foo = 123");
+ {
+ QScriptValue ret = obj.property("foo");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+
+ QVERIFY(!obj.property("bar").isValid());
+ eng.evaluate("bar = 456");
+ {
+ QScriptValue ret = obj.property("bar");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ }
+
+ QVERIFY(!obj.property("baz").isValid());
+ eng.evaluate("this['baz'] = 789");
+ {
+ QScriptValue ret = obj.property("baz");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 789);
+ }
+
+ {
+ QScriptValue ret = eng.evaluate("(function() { return this; })()");
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+
+ // Delete property.
+ {
+ QScriptValue ret = eng.evaluate("delete foo");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ QVERIFY(!obj.property("foo").isValid());
+ }
+
+ // Getter/setter property.
+ //the custom global object have an interceptor
+ QVERIFY(eng.evaluate("this.__defineGetter__('oof', function() { return this.bar; })").isUndefined());
+ QVERIFY(eng.evaluate("this.__defineSetter__('oof', function(v) { this.bar = v; })").isUndefined());
+ QVERIFY(eng.evaluate("this.__lookupGetter__('oof')").isFunction());
+ QVERIFY(eng.evaluate("this.__lookupSetter__('oof')").isFunction());
+ eng.evaluate("oof = 123");
+ QVERIFY(eng.evaluate("oof").equals(obj.property("bar")));
+
+ // Enumeration.
+ {
+ QScriptValue ret = eng.evaluate("a = []; for (var p in this) a.push(p); a");
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar,baz,oof,p,a"));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: no c-style callbacks
+static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() > 0)
+ ctx->thisObject().setProperty("foo", ctx->argument(0));
+ return ctx->thisObject().property("foo");
+}
+#endif
+
+void tst_QJSEngine::globalObjectProperties()
+{
+ // See ECMA-262 Section 15.1, "The Global Object".
+
+ QJSEngine eng;
+ QJSValue global = eng.globalObject();
+
+ QVERIFY(global.property("NaN").isNumber());
+ QVERIFY(qIsNaN(global.property("NaN").toNumber()));
+ QCOMPARE(global.propertyFlags("NaN"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("Infinity").isNumber());
+ QVERIFY(qIsInf(global.property("Infinity").toNumber()));
+ QCOMPARE(global.propertyFlags("NaN"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("undefined").isUndefined());
+ QCOMPARE(global.propertyFlags("undefined"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("eval").isFunction());
+ QCOMPARE(global.propertyFlags("eval"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("parseInt").isFunction());
+ QCOMPARE(global.propertyFlags("parseInt"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("parseFloat").isFunction());
+ QCOMPARE(global.propertyFlags("parseFloat"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("isNaN").isFunction());
+ QCOMPARE(global.propertyFlags("isNaN"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("isFinite").isFunction());
+ QCOMPARE(global.propertyFlags("isFinite"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("decodeURI").isFunction());
+ QCOMPARE(global.propertyFlags("decodeURI"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("decodeURIComponent").isFunction());
+ QCOMPARE(global.propertyFlags("decodeURIComponent"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("encodeURI").isFunction());
+ QCOMPARE(global.propertyFlags("encodeURI"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("encodeURIComponent").isFunction());
+ QCOMPARE(global.propertyFlags("encodeURIComponent"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("Object").isFunction());
+ QCOMPARE(global.propertyFlags("Object"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Function").isFunction());
+ QCOMPARE(global.propertyFlags("Function"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Array").isFunction());
+ QCOMPARE(global.propertyFlags("Array"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("String").isFunction());
+ QCOMPARE(global.propertyFlags("String"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Boolean").isFunction());
+ QCOMPARE(global.propertyFlags("Boolean"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Number").isFunction());
+ QCOMPARE(global.propertyFlags("Number"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Date").isFunction());
+ QCOMPARE(global.propertyFlags("Date"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("RegExp").isFunction());
+ QCOMPARE(global.propertyFlags("RegExp"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Error").isFunction());
+ QCOMPARE(global.propertyFlags("Error"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("EvalError").isFunction());
+ QCOMPARE(global.propertyFlags("EvalError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("RangeError").isFunction());
+ QCOMPARE(global.propertyFlags("RangeError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("ReferenceError").isFunction());
+ QCOMPARE(global.propertyFlags("ReferenceError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("SyntaxError").isFunction());
+ QCOMPARE(global.propertyFlags("SyntaxError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("TypeError").isFunction());
+ QCOMPARE(global.propertyFlags("TypeError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("URIError").isFunction());
+ QCOMPARE(global.propertyFlags("URIError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Math").isObject());
+ QVERIFY(!global.property("Math").isFunction());
+ QCOMPARE(global.propertyFlags("Math"), QJSValue::SkipInEnumeration);
+}
+
+void tst_QJSEngine::globalObjectEquals()
+{
+ QJSEngine eng;
+ QJSValue o = eng.globalObject();
+ QVERIFY(o.strictlyEquals(eng.globalObject()));
+ QVERIFY(o.equals(eng.globalObject()));
+}
+
+#if 0 // ###FIXME: No QScriptValueIterator API
+void tst_QJSEngine::globalObjectProperties_enumerate()
+{
+ QScriptEngine eng;
+ QScriptValue global = eng.globalObject();
+
+ QSet<QString> expectedNames;
+ expectedNames
+ << "isNaN"
+ << "parseFloat"
+ << "String"
+ << "EvalError"
+ << "URIError"
+ << "Math"
+ << "encodeURIComponent"
+ << "RangeError"
+ << "eval"
+ << "isFinite"
+ << "ReferenceError"
+ << "Infinity"
+ << "Function"
+ << "RegExp"
+ << "Number"
+ << "parseInt"
+ << "Object"
+ << "decodeURI"
+ << "TypeError"
+ << "Boolean"
+ << "encodeURI"
+ << "NaN"
+ << "Error"
+ << "decodeURIComponent"
+ << "Date"
+ << "Array"
+ << "escape"
+ << "unescape"
+ << "SyntaxError"
+ << "undefined"
+ // non-standard
+ << "gc"
+ << "version"
+ << "print"
+ // JavaScriptCore
+ << "JSON"
+ // V8
+ << "execScript" //execScript for IE compatibility.
+ ;
+ QSet<QString> actualNames;
+ {
+ QScriptValueIterator it(global);
+ while (it.hasNext()) {
+ it.next();
+ actualNames.insert(it.name());
+ }
+ }
+
+ QSet<QString> remainingNames = actualNames;
+ {
+ QSet<QString>::const_iterator it;
+ for (it = expectedNames.constBegin(); it != expectedNames.constEnd(); ++it) {
+ QString name = *it;
+ QVERIFY(actualNames.contains(name));
+ remainingNames.remove(name);
+ }
+ }
+ QVERIFY(remainingNames.isEmpty());
+}
+#endif
+
+void tst_QJSEngine::createGlobalObjectProperty()
+{
+ QJSEngine eng;
+ QJSValue global = eng.globalObject();
+ // create property with no attributes
+ {
+ QString name = QString::fromLatin1("foo");
+ QVERIFY(!global.property(name).isValid());
+ QJSValue val(123);
+ global.setProperty(name, val);
+ QVERIFY(global.property(name).equals(val));
+ QVERIFY(global.propertyFlags(name) == 0);
+ global.setProperty(name, QJSValue());
+ QVERIFY(!global.property(name).isValid());
+ }
+ // create property with attributes
+#if 0 // ###FIXME: setProperty with flags is not supported
+ {
+ QString name = QString::fromLatin1("bar");
+ QVERIFY(!global.property(name).isValid());
+ QScriptValue val(QString::fromLatin1("ciao"));
+ QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
+ global.setProperty(name, val, flags);
+ QVERIFY(global.property(name).equals(val));
+ //QEXPECT_FAIL("", "QTBUG-6134: custom Global Object properties don't retain attributes", Continue);
+ QCOMPARE(global.propertyFlags(name), flags);
+ global.setProperty(name, QScriptValue());
+ QVERIFY(!global.property(name).isValid());
+ }
+#endif
+}
+
+void tst_QJSEngine::globalObjectGetterSetterProperty()
+{
+#if 0 // ###FIXME: No c-style callbacks
+ QScriptEngine engine;
+ QScriptValue global = engine.globalObject();
+ global.setProperty("bar", engine.newFunction(getSetFoo),
+ QScriptValue::PropertySetter | QScriptValue::PropertyGetter);
+ global.setProperty("foo", 123);
+ QVERIFY(global.property("bar").equals(global.property("foo")));
+ QVERIFY(engine.evaluate("bar").equals(global.property("foo")));
+ global.setProperty("bar", 456);
+ QVERIFY(global.property("bar").equals(global.property("foo")));
+
+ engine.evaluate("__defineGetter__('baz', function() { return 789; })");
+ QVERIFY(engine.evaluate("baz").equals(789));
+ QVERIFY(global.property("baz").equals(789));
+#endif
+}
+
+#if 0 // ###FIXME: No support for setting the global object
+void tst_QJSEngine::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());
+ if (x) QEXPECT_FAIL("", "Why?", Continue);
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.hasOwnProperty('print')");
+ QVERIFY(ret.isBool());
+ if (x) QEXPECT_FAIL("", "Why?", Continue);
+ 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: print is not defined"));
+ }
+ {
+ 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());
+ QVERIFY(ret.toString().startsWith("ReferenceError: "));
+ }
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(global.property("print")));
+ }
+ QVERIFY(!anotherProto.property("print").isValid());
+ }
+}
+#endif
+
+void tst_QJSEngine::globalObjectWithCustomPrototype()
+{
+ QJSEngine engine;
+ QJSValue proto = engine.newObject();
+ proto.setProperty("protoProperty", 123);
+ QJSValue global = engine.globalObject();
+ QJSValue originalProto = global.prototype();
+ global.setPrototype(proto);
+ {
+ QJSValue ret = engine.evaluate("protoProperty");
+ QEXPECT_FAIL("", "Replacing the prototype of the global object is currently unsupported (see also v8 issue 1078)", Abort);
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QJSValue ret = engine.evaluate("this.protoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QJSValue ret = engine.evaluate("hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QJSValue ret = engine.evaluate("this.hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+
+ // Custom prototype set from JS
+ {
+ QJSValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("a")));
+ }
+}
+
+void tst_QJSEngine::builtinFunctionNames_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedName");
+
+ // See ECMA-262 Chapter 15, "Standard Built-in ECMAScript Objects".
+
+ QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt");
+ QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat");
+ QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN");
+ QTest::newRow("isFinite") << QString("isFinite") << QString("isFinite");
+ QTest::newRow("decodeURI") << QString("decodeURI") << QString("decodeURI");
+ QTest::newRow("decodeURIComponent") << QString("decodeURIComponent") << QString("decodeURIComponent");
+ QTest::newRow("encodeURI") << QString("encodeURI") << QString("encodeURI");
+ QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent");
+ QTest::newRow("escape") << QString("escape") << QString("escape");
+ QTest::newRow("unescape") << QString("unescape") << QString("unescape");
+
+ QTest::newRow("Array") << QString("Array") << QString("Array");
+ QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString");
+ QTest::newRow("Array.prototype.toLocaleString") << QString("Array.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Array.prototype.concat") << QString("Array.prototype.concat") << QString("concat");
+ QTest::newRow("Array.prototype.join") << QString("Array.prototype.join") << QString("join");
+ QTest::newRow("Array.prototype.pop") << QString("Array.prototype.pop") << QString("pop");
+ QTest::newRow("Array.prototype.push") << QString("Array.prototype.push") << QString("push");
+ QTest::newRow("Array.prototype.reverse") << QString("Array.prototype.reverse") << QString("reverse");
+ QTest::newRow("Array.prototype.shift") << QString("Array.prototype.shift") << QString("shift");
+ QTest::newRow("Array.prototype.slice") << QString("Array.prototype.slice") << QString("slice");
+ QTest::newRow("Array.prototype.sort") << QString("Array.prototype.sort") << QString("sort");
+ QTest::newRow("Array.prototype.splice") << QString("Array.prototype.splice") << QString("splice");
+ QTest::newRow("Array.prototype.unshift") << QString("Array.prototype.unshift") << QString("unshift");
+
+ QTest::newRow("Boolean") << QString("Boolean") << QString("Boolean");
+ QTest::newRow("Boolean.prototype.toString") << QString("Boolean.prototype.toString") << QString("toString");
+
+ QTest::newRow("Date") << QString("Date") << QString("Date");
+ QTest::newRow("Date.prototype.toString") << QString("Date.prototype.toString") << QString("toString");
+ QTest::newRow("Date.prototype.toDateString") << QString("Date.prototype.toDateString") << QString("toDateString");
+ QTest::newRow("Date.prototype.toTimeString") << QString("Date.prototype.toTimeString") << QString("toTimeString");
+ QTest::newRow("Date.prototype.toLocaleString") << QString("Date.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Date.prototype.toLocaleDateString") << QString("Date.prototype.toLocaleDateString") << QString("toLocaleDateString");
+ QTest::newRow("Date.prototype.toLocaleTimeString") << QString("Date.prototype.toLocaleTimeString") << QString("toLocaleTimeString");
+ QTest::newRow("Date.prototype.valueOf") << QString("Date.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Date.prototype.getTime") << QString("Date.prototype.getTime") << QString("getTime");
+ QTest::newRow("Date.prototype.getYear") << QString("Date.prototype.getYear") << QString("getYear");
+ QTest::newRow("Date.prototype.getFullYear") << QString("Date.prototype.getFullYear") << QString("getFullYear");
+ QTest::newRow("Date.prototype.getUTCFullYear") << QString("Date.prototype.getUTCFullYear") << QString("getUTCFullYear");
+ QTest::newRow("Date.prototype.getMonth") << QString("Date.prototype.getMonth") << QString("getMonth");
+ QTest::newRow("Date.prototype.getUTCMonth") << QString("Date.prototype.getUTCMonth") << QString("getUTCMonth");
+ QTest::newRow("Date.prototype.getDate") << QString("Date.prototype.getDate") << QString("getDate");
+ QTest::newRow("Date.prototype.getUTCDate") << QString("Date.prototype.getUTCDate") << QString("getUTCDate");
+ QTest::newRow("Date.prototype.getDay") << QString("Date.prototype.getDay") << QString("getDay");
+ QTest::newRow("Date.prototype.getUTCDay") << QString("Date.prototype.getUTCDay") << QString("getUTCDay");
+ QTest::newRow("Date.prototype.getHours") << QString("Date.prototype.getHours") << QString("getHours");
+ QTest::newRow("Date.prototype.getUTCHours") << QString("Date.prototype.getUTCHours") << QString("getUTCHours");
+ QTest::newRow("Date.prototype.getMinutes") << QString("Date.prototype.getMinutes") << QString("getMinutes");
+ QTest::newRow("Date.prototype.getUTCMinutes") << QString("Date.prototype.getUTCMinutes") << QString("getUTCMinutes");
+ QTest::newRow("Date.prototype.getSeconds") << QString("Date.prototype.getSeconds") << QString("getSeconds");
+ QTest::newRow("Date.prototype.getUTCSeconds") << QString("Date.prototype.getUTCSeconds") << QString("getUTCSeconds");
+ QTest::newRow("Date.prototype.getMilliseconds") << QString("Date.prototype.getMilliseconds") << QString("getMilliseconds");
+ QTest::newRow("Date.prototype.getUTCMilliseconds") << QString("Date.prototype.getUTCMilliseconds") << QString("getUTCMilliseconds");
+ QTest::newRow("Date.prototype.getTimezoneOffset") << QString("Date.prototype.getTimezoneOffset") << QString("getTimezoneOffset");
+ QTest::newRow("Date.prototype.setTime") << QString("Date.prototype.setTime") << QString("setTime");
+ QTest::newRow("Date.prototype.setMilliseconds") << QString("Date.prototype.setMilliseconds") << QString("setMilliseconds");
+ QTest::newRow("Date.prototype.setUTCMilliseconds") << QString("Date.prototype.setUTCMilliseconds") << QString("setUTCMilliseconds");
+ QTest::newRow("Date.prototype.setSeconds") << QString("Date.prototype.setSeconds") << QString("setSeconds");
+ QTest::newRow("Date.prototype.setUTCSeconds") << QString("Date.prototype.setUTCSeconds") << QString("setUTCSeconds");
+ QTest::newRow("Date.prototype.setMinutes") << QString("Date.prototype.setMinutes") << QString("setMinutes");
+ QTest::newRow("Date.prototype.setUTCMinutes") << QString("Date.prototype.setUTCMinutes") << QString("setUTCMinutes");
+ QTest::newRow("Date.prototype.setHours") << QString("Date.prototype.setHours") << QString("setHours");
+ QTest::newRow("Date.prototype.setUTCHours") << QString("Date.prototype.setUTCHours") << QString("setUTCHours");
+ QTest::newRow("Date.prototype.setDate") << QString("Date.prototype.setDate") << QString("setDate");
+ QTest::newRow("Date.prototype.setUTCDate") << QString("Date.prototype.setUTCDate") << QString("setUTCDate");
+ QTest::newRow("Date.prototype.setMonth") << QString("Date.prototype.setMonth") << QString("setMonth");
+ QTest::newRow("Date.prototype.setUTCMonth") << QString("Date.prototype.setUTCMonth") << QString("setUTCMonth");
+ QTest::newRow("Date.prototype.setYear") << QString("Date.prototype.setYear") << QString("setYear");
+ QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear");
+ QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear");
+ QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString");
+ QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString");
+
+ QTest::newRow("Error") << QString("Error") << QString("Error");
+// QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace");
+ QTest::newRow("Error.prototype.toString") << QString("Error.prototype.toString") << QString("toString");
+
+ QTest::newRow("EvalError") << QString("EvalError") << QString("EvalError");
+ QTest::newRow("RangeError") << QString("RangeError") << QString("RangeError");
+ QTest::newRow("ReferenceError") << QString("ReferenceError") << QString("ReferenceError");
+ QTest::newRow("SyntaxError") << QString("SyntaxError") << QString("SyntaxError");
+ QTest::newRow("TypeError") << QString("TypeError") << QString("TypeError");
+ QTest::newRow("URIError") << QString("URIError") << QString("URIError");
+
+ QTest::newRow("Function") << QString("Function") << QString("Function");
+ QTest::newRow("Function.prototype.toString") << QString("Function.prototype.toString") << QString("toString");
+ QTest::newRow("Function.prototype.apply") << QString("Function.prototype.apply") << QString("apply");
+ QTest::newRow("Function.prototype.call") << QString("Function.prototype.call") << QString("call");
+/* In V8, those function are only there for signals
+ QTest::newRow("Function.prototype.connect") << QString("Function.prototype.connect") << QString("connect");
+ QTest::newRow("Function.prototype.disconnect") << QString("Function.prototype.disconnect") << QString("disconnect");*/
+
+ QTest::newRow("Math.abs") << QString("Math.abs") << QString("abs");
+ QTest::newRow("Math.acos") << QString("Math.acos") << QString("acos");
+ QTest::newRow("Math.asin") << QString("Math.asin") << QString("asin");
+ QTest::newRow("Math.atan") << QString("Math.atan") << QString("atan");
+ QTest::newRow("Math.atan2") << QString("Math.atan2") << QString("atan2");
+ QTest::newRow("Math.ceil") << QString("Math.ceil") << QString("ceil");
+ QTest::newRow("Math.cos") << QString("Math.cos") << QString("cos");
+ QTest::newRow("Math.exp") << QString("Math.exp") << QString("exp");
+ QTest::newRow("Math.floor") << QString("Math.floor") << QString("floor");
+ QTest::newRow("Math.log") << QString("Math.log") << QString("log");
+ QTest::newRow("Math.max") << QString("Math.max") << QString("max");
+ QTest::newRow("Math.min") << QString("Math.min") << QString("min");
+ QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow");
+ QTest::newRow("Math.random") << QString("Math.random") << QString("random");
+ QTest::newRow("Math.round") << QString("Math.round") << QString("round");
+ QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin");
+ QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt");
+ QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan");
+
+ QTest::newRow("Number") << QString("Number") << QString("Number");
+ QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString");
+ QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Number.prototype.toFixed") << QString("Number.prototype.toFixed") << QString("toFixed");
+ QTest::newRow("Number.prototype.toExponential") << QString("Number.prototype.toExponential") << QString("toExponential");
+ QTest::newRow("Number.prototype.toPrecision") << QString("Number.prototype.toPrecision") << QString("toPrecision");
+
+ QTest::newRow("Object") << QString("Object") << QString("Object");
+ QTest::newRow("Object.prototype.toString") << QString("Object.prototype.toString") << QString("toString");
+ QTest::newRow("Object.prototype.toLocaleString") << QString("Object.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Object.prototype.valueOf") << QString("Object.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Object.prototype.hasOwnProperty") << QString("Object.prototype.hasOwnProperty") << QString("hasOwnProperty");
+ QTest::newRow("Object.prototype.isPrototypeOf") << QString("Object.prototype.isPrototypeOf") << QString("isPrototypeOf");
+ QTest::newRow("Object.prototype.propertyIsEnumerable") << QString("Object.prototype.propertyIsEnumerable") << QString("propertyIsEnumerable");
+ QTest::newRow("Object.prototype.__defineGetter__") << QString("Object.prototype.__defineGetter__") << QString("__defineGetter__");
+ QTest::newRow("Object.prototype.__defineSetter__") << QString("Object.prototype.__defineSetter__") << QString("__defineSetter__");
+
+ QTest::newRow("RegExp") << QString("RegExp") << QString("RegExp");
+ QTest::newRow("RegExp.prototype.exec") << QString("RegExp.prototype.exec") << QString("exec");
+ QTest::newRow("RegExp.prototype.test") << QString("RegExp.prototype.test") << QString("test");
+ QTest::newRow("RegExp.prototype.toString") << QString("RegExp.prototype.toString") << QString("toString");
+
+ QTest::newRow("String") << QString("String") << QString("String");
+ QTest::newRow("String.prototype.toString") << QString("String.prototype.toString") << QString("toString");
+ QTest::newRow("String.prototype.valueOf") << QString("String.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt");
+ QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt");
+ QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat");
+ QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf");
+ QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf");
+ QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare");
+ QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match");
+ QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace");
+ QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search");
+ QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice");
+ QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split");
+ QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring");
+ QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase");
+ QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase");
+ QTest::newRow("String.prototype.toUpperCase") << QString("String.prototype.toUpperCase") << QString("toUpperCase");
+ QTest::newRow("String.prototype.toLocaleUpperCase") << QString("String.prototype.toLocaleUpperCase") << QString("toLocaleUpperCase");
+}
+
+void tst_QJSEngine::builtinFunctionNames()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedName);
+ QJSEngine eng;
+ // The "name" property is actually non-standard, but JSC supports it.
+ QJSValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression));
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), expectedName);
+}
+
+#if 0 // ###FIXME: No syntax checking result
+void tst_QJSEngine::checkSyntax_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<int>("expectedState");
+ QTest::addColumn<int>("errorLineNumber");
+ QTest::addColumn<int>("errorColumnNumber");
+ QTest::addColumn<QString>("errorMessage");
+
+ QTest::newRow("0")
+ << QString("0") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+ QTest::newRow("if (")
+ << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
+ << 0 << -1 << "Uncaught SyntaxError: Unexpected end of input";
+ QTest::newRow("if else")
+ << QString("\nif else") << int(QScriptSyntaxCheckResult::Error)
+ << 2 << 3 << "Uncaught SyntaxError: Unexpected token else";
+ QTest::newRow("foo[")
+ << QString("foo[") << int(QScriptSyntaxCheckResult::Intermediate)
+ << 1 << 4 << "Uncaught SyntaxError: Unexpected end of input";
+ QTest::newRow("foo['bar']")
+ << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+
+ QTest::newRow("/*")
+ << QString("/*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 0 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("/*\nMy comment")
+ << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 0 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("/*\nMy comment */\nfoo = 10")
+ << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+ QTest::newRow("foo = 10 /*")
+ << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 9 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("foo = 10; /*")
+ << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 10 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("foo = 10 /* My comment */")
+ << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+
+ QTest::newRow("/=/")
+ << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/=/g")
+ << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/a/")
+ << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/a/g")
+ << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+}
+
+void tst_QJSEngine::checkSyntax()
+{
+ QFETCH(QString, code);
+ QFETCH(int, expectedState);
+ QFETCH(int, errorLineNumber);
+ QFETCH(int, errorColumnNumber);
+ QFETCH(QString, errorMessage);
+
+ QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
+ QCOMPARE(int(result.state()), expectedState);
+ QCOMPARE(result.errorLineNumber(), errorLineNumber);
+ QCOMPARE(result.errorColumnNumber(), errorColumnNumber);
+ QCOMPARE(result.errorMessage(), errorMessage);
+
+ // assignment
+ {
+ QScriptSyntaxCheckResult copy = result;
+ QCOMPARE(copy.state(), result.state());
+ QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
+ QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
+ QCOMPARE(copy.errorMessage(), result.errorMessage());
+ }
+ {
+ QScriptSyntaxCheckResult copy(result);
+ QCOMPARE(copy.state(), result.state());
+ QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
+ QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
+ QCOMPARE(copy.errorMessage(), result.errorMessage());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No support for canEvaluate
+void tst_QJSEngine::canEvaluate_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<bool>("expectSuccess");
+
+ QTest::newRow("") << QString("") << true;
+ QTest::newRow("0") << QString("0") << true;
+ QTest::newRow("!") << QString("!\n") << false;
+ QTest::newRow("if (") << QString("if (\n") << false;
+ QTest::newRow("if (10) //") << QString("if (10) //\n") << false;
+ QTest::newRow("a = 1; if (") << QString("a = 1;\nif (\n") << false;
+ QTest::newRow("./test.js") << QString("./test.js\n") << true;
+ QTest::newRow("if (0) print(1)") << QString("if (0)\nprint(1)\n") << true;
+ QTest::newRow("0 = ") << QString("0 = \n") << false;
+ QTest::newRow("0 = 0") << QString("0 = 0\n") << true;
+ QTest::newRow("foo[") << QString("foo[") << false;
+ QTest::newRow("foo[") << QString("foo[\n") << false;
+ QTest::newRow("foo['bar']") << QString("foo['bar']") << true;
+
+ //v8 does thinks unterminated comments are error rather than unfinished
+// QTest::newRow("/*") << QString("/*") << false;
+// QTest::newRow("/*\nMy comment") << QString("/*\nMy comment") << false;
+ QTest::newRow("/*\nMy comment */\nfoo = 10") << QString("/*\nMy comment */\nfoo = 10") << true;
+// QTest::newRow("foo = 10 /*") << QString("foo = 10 /*") << false;
+// QTest::newRow("foo = 10; /*") << QString("foo = 10; /*") << false;
+ QTest::newRow("foo = 10 /* My comment */") << QString("foo = 10 /* My comment */") << true;
+
+ QTest::newRow("/=/") << QString("/=/") << true;
+ QTest::newRow("/=/g") << QString("/=/g") << true;
+ QTest::newRow("/a/") << QString("/a/") << true;
+ QTest::newRow("/a/g") << QString("/a/g") << true;
+}
+
+void tst_QJSEngine::canEvaluate()
+{
+ QFETCH(QString, code);
+ QFETCH(bool, expectSuccess);
+
+ QScriptEngine eng;
+ QCOMPARE(eng.canEvaluate(code), expectSuccess);
+}
+#endif
+
+void tst_QJSEngine::evaluate_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<int>("lineNumber");
+ QTest::addColumn<bool>("expectHadError");
+ QTest::addColumn<int>("expectErrorLineNumber");
+
+ QTest::newRow("(newline)") << QString("\n") << -1 << false << -1;
+ QTest::newRow("0 //") << QString("0 //") << -1 << false << -1;
+ QTest::newRow("/* */") << QString("/* */") << -1 << false << -1;
+ QTest::newRow("//") << QString("//") << -1 << false << -1;
+ QTest::newRow("(spaces)") << QString(" ") << -1 << false << -1;
+ QTest::newRow("(empty)") << QString("") << -1 << false << -1;
+ QTest::newRow("0") << QString("0") << -1 << false << -1;
+ QTest::newRow("0=1") << QString("\n0=1;\n") << -1 << true << 2;
+ QTest::newRow("a=1") << QString("a=1\n") << -1 << false << -1;
+ QTest::newRow("a=1;K") << QString("a=1;\nK") << -1 << true << 2;
+
+ QTest::newRow("f()") << QString("function f()\n"
+ "{\n"
+ " var a;\n"
+ " var b=\";\n" // here's the error
+ "}\n"
+ "f();\n")
+ << -1 << true << 4;
+
+ QTest::newRow("0") << QString("0") << 10 << false << -1;
+ QTest::newRow("0=1") << QString("\n\n0=1\n") << 10 << true << 12;
+ QTest::newRow("a=1") << QString("a=1\n") << 10 << false << -1;
+ QTest::newRow("a=1;K") << QString("a=1;\n\nK") << 10 << true << 12;
+
+ QTest::newRow("f()") << QString("function f()\n"
+ "{\n"
+ " var a;\n"
+ "\n\n"
+ " var b=\";\n" // here's the error
+ "}\n"
+ "f();\n")
+ << 10 << true << 15;
+ QTest::newRow("functionThatDoesntExist()")
+ << QString(";\n;\n;\nfunctionThatDoesntExist()")
+ << -1 << true << 4;
+ QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }")
+ << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }")
+ << 4 << true << 5;
+ QTest::newRow("duplicateLabel: { duplicateLabel: ; }")
+ << QString("duplicateLabel: { duplicateLabel: ; }")
+ << 12 << true << 12;
+
+ QTest::newRow("/=/") << QString("/=/") << -1 << false << -1;
+ QTest::newRow("/=/g") << QString("/=/g") << -1 << false << -1;
+ QTest::newRow("/a/") << QString("/a/") << -1 << false << -1;
+ QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1;
+ QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1;
+ QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1;
+}
+
+void tst_QJSEngine::evaluate()
+{
+ QFETCH(QString, code);
+ QFETCH(int, lineNumber);
+ QFETCH(bool, expectHadError);
+ QFETCH(int, expectErrorLineNumber);
+
+ QJSEngine eng;
+ QJSValue ret;
+ if (lineNumber != -1)
+ ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber);
+ else
+ ret = eng.evaluate(code);
+ QEXPECT_FAIL("/a/gimp", "v8 ignore invalid flags", Abort);
+ QCOMPARE(eng.hasUncaughtException(), expectHadError);
+#if 0 // ###FIXME: No support for the line number of an uncaught exception
+ QEXPECT_FAIL("f()", "SyntaxError do not report line number", Continue);
+ QEXPECT_FAIL("duplicateLabel: { duplicateLabel: ; }", "SyntaxError do not report line number", Continue);
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), expectErrorLineNumber);
+#endif
+ if (eng.hasUncaughtException() && ret.isError()) {
+ QEXPECT_FAIL("", "we have no more lineNumber property ", Continue);
+ QVERIFY(ret.property("lineNumber").strictlyEquals(QJSValue(&eng, expectErrorLineNumber)));
+ } else {
+#if 0 // ###FIXME: No support for the backtrace of an uncaught exception
+ QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+#endif
+ }
+}
+
+#if 0 // ###FIXME: no support for c-style callbacks
+static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue result = eng->newObject();
+ eng->evaluate("var bar = 'local';");
+ result.setProperty("thisObjectIdBefore", ctx->thisObject().property("id"));
+ QScriptValue evaluatedThisObject = eng->evaluate("this");
+ result.setProperty("thisObjectIdAfter", ctx->thisObject().property("id"));
+ result.setProperty("evaluatedThisObjectId", evaluatedThisObject.property("id"));
+ result.setProperty("local_bar", eng->evaluate("bar"));
+
+ return result;
+}
+
+// Tests that nested evaluate uses the "this" that was passed.
+void tst_QJSEngine::nestedEvaluate()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(eval_nested);
+ eng.globalObject().setProperty("fun", fun);
+ // From JS function call
+ {
+ QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()");
+ QCOMPARE(result.property("local_bar").toString(), QString("local"));
+ QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
+ QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
+ QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
+ QScriptValue bar = eng.evaluate("bar"); // Was introduced in local scope.
+ QVERIFY(bar.isError());
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ // From QScriptValue::call()
+ {
+ QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() );
+ QCOMPARE(result.property("local_bar").toString(), QString("local"));
+ QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
+ QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
+ QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
+ QScriptValue bar = eng.evaluate("bar");
+ QVERIFY(bar.isError());
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+}
+#endif
+
+#if 0 // ### FIXME: No c-style callbacks
+void tst_QJSEngine::uncaughtException()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunction);
+ QScriptValue throwFun = eng.newFunction(myThrowingFunction);
+ for (int x = -1; x < 2; ++x) {
+ {
+ QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", /*fileName=*/QString(), /*lineNumber=*/x);
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ (void)ret.toString();
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ QVERIFY(fun.call().isNull());
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), -1);
+ QVERIFY(!eng.uncaughtException().isValid());
+
+ eng.evaluate("2 = 3");
+ QVERIFY(eng.hasUncaughtException());
+ QScriptValue ret2 = throwFun.call();
+ QVERIFY(ret2.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret2));
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 0);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ eng.evaluate("1 + 2");
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptValue ret = eng.evaluate("a = 10");
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!eng.uncaughtException().isValid());
+ }
+ {
+ QScriptValue ret = eng.evaluate("1 = 2");
+ QVERIFY(eng.hasUncaughtException());
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ eng.globalObject().setProperty("throwFun", throwFun);
+ eng.evaluate("1;\nthrowFun();");
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 2);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ }
+}
+#endif
+
+void tst_QJSEngine::errorMessage_QT679()
+{
+ QJSEngine engine;
+ engine.globalObject().setProperty("foo", 15);
+ QJSValue error = engine.evaluate("'hello world';\nfoo.bar.blah");
+ QVERIFY(error.isError());
+ QVERIFY(error.toString().startsWith(QString::fromLatin1("TypeError: ")));
+}
+
+struct Foo {
+public:
+ int x, y;
+ Foo() : x(-1), y(-1) { }
+};
+
+Q_DECLARE_METATYPE(Foo)
+Q_DECLARE_METATYPE(Foo*)
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::getSetDefaultPrototype_int()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<int>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(int(123));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
+
+ eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(int(123));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
+}
+
+void tst_QJSEngine::getSetDefaultPrototype_customType()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
+
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
+}
+#endif
+
+static QJSValue fooToScriptValue(QJSEngine *eng, const Foo &foo)
+{
+ QJSValue obj = eng->newObject();
+ obj.setProperty("x", QJSValue(eng, foo.x));
+ obj.setProperty("y", QJSValue(eng, foo.y));
+ return obj;
+}
+
+static void fooFromScriptValue(const QJSValue &value, Foo &foo)
+{
+ foo.x = value.property("x").toInt32();
+ foo.y = value.property("y").toInt32();
+}
+
+static QJSValue fooToScriptValueV2(QJSEngine *eng, const Foo &foo)
+{
+ return QJSValue(eng, foo.x);
+}
+
+static void fooFromScriptValueV2(const QJSValue &value, Foo &foo)
+{
+ foo.x = value.toInt32();
+}
+
+Q_DECLARE_METATYPE(QLinkedList<QString>)
+Q_DECLARE_METATYPE(QList<Foo>)
+Q_DECLARE_METATYPE(QVector<QChar>)
+Q_DECLARE_METATYPE(QStack<int>)
+Q_DECLARE_METATYPE(QQueue<char>)
+Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
+
+void tst_QJSEngine::valueConversion_basic()
+{
+ QJSEngine eng;
+ {
+ QJSValue num = eng.toScriptValue(123);
+ QCOMPARE(num.isNumber(), true);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123)), true);
+
+ int inum = eng.fromScriptValue<int>(num);
+ QCOMPARE(inum, 123);
+
+ QString snum = eng.fromScriptValue<QString>(num);
+ QCOMPARE(snum, QLatin1String("123"));
+ }
+ {
+ QJSValue num = eng.toScriptValue(123);
+ QCOMPARE(num.isNumber(), true);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123)), true);
+
+ int inum = eng.fromScriptValue<int>(num);
+ QCOMPARE(inum, 123);
+
+ QString snum = eng.fromScriptValue<QString>(num);
+ QCOMPARE(snum, QLatin1String("123"));
+ }
+ {
+ QJSValue num(&eng, 123);
+ QCOMPARE(eng.fromScriptValue<char>(num), char(123));
+ QCOMPARE(eng.fromScriptValue<unsigned char>(num), (unsigned char)(123));
+ QCOMPARE(eng.fromScriptValue<short>(num), short(123));
+ QCOMPARE(eng.fromScriptValue<unsigned short>(num), (unsigned short)(123));
+ QCOMPARE(eng.fromScriptValue<float>(num), float(123));
+ QCOMPARE(eng.fromScriptValue<double>(num), double(123));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), qlonglong(123));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), qulonglong(123));
+ }
+ {
+ QJSValue num(123);
+ QCOMPARE(eng.fromScriptValue<char>(num), char(123));
+ QCOMPARE(eng.fromScriptValue<unsigned char>(num), (unsigned char)(123));
+ QCOMPARE(eng.fromScriptValue<short>(num), short(123));
+ QCOMPARE(eng.fromScriptValue<unsigned short>(num), (unsigned short)(123));
+ QCOMPARE(eng.fromScriptValue<float>(num), float(123));
+ QCOMPARE(eng.fromScriptValue<double>(num), double(123));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), qlonglong(123));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), qulonglong(123));
+ }
+
+ {
+ QJSValue num = eng.toScriptValue(Q_INT64_C(0x100000000));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), Q_INT64_C(0x100000000));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), Q_UINT64_C(0x100000000));
+ }
+
+ {
+ QChar c = QLatin1Char('c');
+ QJSValue str = QJSValue(&eng, QLatin1String("ciao"));
+ QCOMPARE(eng.fromScriptValue<QChar>(str), c);
+ QJSValue code = QJSValue(&eng, c.unicode());
+ QCOMPARE(eng.fromScriptValue<QChar>(code), c);
+ QCOMPARE(eng.fromScriptValue<QChar>(eng.toScriptValue(c)), c);
+ }
+}
+
+#if 0 // FIXME: No API for custom types
+void tst_QJSEngine::valueConversion_customType()
+{
+ QScriptEngine eng;
+ {
+ // a type that we don't have built-in conversion of
+ // (it's stored as a variant)
+ QTime tm(1, 2, 3, 4);
+ QScriptValue val = eng.toScriptValue(tm);
+ QCOMPARE(eng.fromScriptValue<QTime>(val), tm);
+ }
+
+ {
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ QScriptValue fooVal = eng.toScriptValue(foo);
+ QCOMPARE(fooVal.isVariant(), true);
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, foo.x);
+ QCOMPARE(foo2.y, foo.y);
+ }
+
+ qScriptRegisterMetaType<Foo>(&eng, fooToScriptValue, fooFromScriptValue);
+
+ {
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ QScriptValue fooVal = eng.toScriptValue(foo);
+ QCOMPARE(fooVal.isObject(), true);
+ QVERIFY(fooVal.prototype().strictlyEquals(eng.evaluate("Object.prototype")));
+ QCOMPARE(fooVal.property("x").strictlyEquals(QScriptValue(&eng, 12)), true);
+ QCOMPARE(fooVal.property("y").strictlyEquals(QScriptValue(&eng, 34)), true);
+ fooVal.setProperty("x", QScriptValue(&eng, 56));
+ fooVal.setProperty("y", QScriptValue(&eng, 78));
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 56);
+ QCOMPARE(foo2.y, 78);
+
+ QScriptValue fooProto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), fooProto);
+ QScriptValue fooVal2 = eng.toScriptValue(foo2);
+ QVERIFY(fooVal2.prototype().strictlyEquals(fooProto));
+ QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56)));
+ QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78)));
+ }
+}
+
+void tst_QJSEngine::valueConversion_sequence()
+{
+ QScriptEngine eng;
+ qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng);
+
+ {
+ QLinkedList<QString> lst;
+ lst << QLatin1String("foo") << QLatin1String("bar");
+ QScriptValue lstVal = eng.toScriptValue(lst);
+ QCOMPARE(lstVal.isArray(), true);
+ QCOMPARE(lstVal.property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").isString(), true);
+ QCOMPARE(lstVal.property("0").toString(), QLatin1String("foo"));
+ QCOMPARE(lstVal.property("1").isString(), true);
+ QCOMPARE(lstVal.property("1").toString(), QLatin1String("bar"));
+ }
+
+ qScriptRegisterSequenceMetaType<QList<Foo> >(&eng);
+ qScriptRegisterSequenceMetaType<QStack<int> >(&eng);
+ qScriptRegisterSequenceMetaType<QVector<QChar> >(&eng);
+ qScriptRegisterSequenceMetaType<QQueue<char> >(&eng);
+ qScriptRegisterSequenceMetaType<QLinkedList<QStack<int> > >(&eng);
+
+ {
+ QLinkedList<QStack<int> > lst;
+ QStack<int> first; first << 13 << 49; lst << first;
+ QStack<int> second; second << 99999;lst << second;
+ QScriptValue lstVal = eng.toScriptValue(lst);
+ QCOMPARE(lstVal.isArray(), true);
+ QCOMPARE(lstVal.property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").isArray(), true);
+ QCOMPARE(lstVal.property("0").property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").property("0").toInt32(), first.at(0));
+ QCOMPARE(lstVal.property("0").property("1").toInt32(), first.at(1));
+ QCOMPARE(lstVal.property("1").isArray(), true);
+ QCOMPARE(lstVal.property("1").property("length").toInt32(), 1);
+ QCOMPARE(lstVal.property("1").property("0").toInt32(), second.at(0));
+ QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("0")), first);
+ QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("1")), second);
+ QCOMPARE(qscriptvalue_cast<QLinkedList<QStack<int> > >(lstVal), lst);
+ }
+
+ // pointers
+ {
+ Foo foo;
+ {
+ QScriptValue v = eng.toScriptValue(&foo);
+ Foo *pfoo = qscriptvalue_cast<Foo*>(v);
+ QCOMPARE(pfoo, &foo);
+ }
+ {
+ Foo *pfoo = 0;
+ QScriptValue v = eng.toScriptValue(pfoo);
+ QCOMPARE(v.isNull(), true);
+ QVERIFY(qscriptvalue_cast<Foo*>(v) == 0);
+ }
+ }
+
+ // QList<int> and QObjectList should be converted from/to arrays by default
+ {
+ QList<int> lst;
+ lst << 1 << 2 << 3;
+ QScriptValue val = eng.toScriptValue(lst);
+ QVERIFY(val.isArray());
+ QCOMPARE(val.property("length").toInt32(), lst.size());
+ QCOMPARE(val.property(0).toInt32(), lst.at(0));
+ QCOMPARE(val.property(1).toInt32(), lst.at(1));
+ QCOMPARE(val.property(2).toInt32(), lst.at(2));
+
+ QCOMPARE(qscriptvalue_cast<QList<int> >(val), lst);
+ }
+ {
+ QObjectList lst;
+ lst << this;
+ QScriptValue val = eng.toScriptValue(lst);
+ QVERIFY(val.isArray());
+ QCOMPARE(val.property("length").toInt32(), lst.size());
+ QCOMPARE(val.property(0).toQObject(), (QObject *)this);
+
+ QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst);
+ }
+}
+#endif
+
+void tst_QJSEngine::valueConversion_QVariant()
+{
+ QJSEngine eng;
+ // qScriptValueFromValue() should be "smart" when the argument is a QVariant
+ {
+ QJSValue val = eng.toScriptValue(QVariant());
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isUndefined());
+ }
+ // Checking nested QVariants
+ {
+ QVariant tmp1;
+ QVariant tmp2(QMetaType::QVariant, &tmp1);
+ QVERIFY(QMetaType::Type(tmp2.type()) == QMetaType::QVariant);
+
+ QJSValue val1 = eng.toScriptValue(tmp1);
+ QJSValue val2 = eng.toScriptValue(tmp2);
+ QVERIFY(val1.isValid());
+ QVERIFY(val2.isValid());
+ QVERIFY(val1.isUndefined());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(!val2.isUndefined());
+ QVERIFY(!val1.isVariant());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val2.isVariant());
+ }
+ {
+ QVariant tmp1(123);
+ QVariant tmp2(QMetaType::QVariant, &tmp1);
+ QVariant tmp3(QMetaType::QVariant, &tmp2);
+ QVERIFY(QMetaType::Type(tmp1.type()) == QMetaType::Int);
+ QVERIFY(QMetaType::Type(tmp2.type()) == QMetaType::QVariant);
+ QVERIFY(QMetaType::Type(tmp3.type()) == QMetaType::QVariant);
+
+ QJSValue val1 = eng.toScriptValue(tmp2);
+ QJSValue val2 = eng.toScriptValue(tmp3);
+ QVERIFY(val1.isValid());
+ QVERIFY(val2.isValid());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val1.isVariant());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val2.isVariant());
+ QVERIFY(val1.toVariant().toInt() == 123);
+ QVERIFY(eng.toScriptValue(val2.toVariant()).toVariant().toInt() == 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(true));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isBoolean());
+ QCOMPARE(val.toBoolean(), true);
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(int(123)));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toNumber(), qreal(123));
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(qreal(1.25)));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toNumber(), qreal(1.25));
+ }
+ {
+ QString str = QString::fromLatin1("ciao");
+ QJSValue val = eng.toScriptValue(QVariant(str));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), str);
+ }
+ {
+ QJSValue val = eng.toScriptValue(qVariantFromValue((QObject*)this));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isQObject());
+ QCOMPARE(val.toQObject(), (QObject*)this);
+ }
+ {
+ QVariant var = qVariantFromValue(QPoint(123, 456));
+ QJSValue val = eng.toScriptValue(var);
+ QVERIFY(val.isVariant());
+ QCOMPARE(val.toVariant(), var);
+ }
+
+ QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123));
+}
+
+#if 0 // FIXME: No support for custom types
+void tst_QJSEngine::valueConversion_hooliganTask248802()
+{
+ QScriptEngine eng;
+ qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2);
+ {
+ QScriptValue num(&eng, 123);
+ Foo foo = eng.fromScriptValue<Foo>(num);
+ QCOMPARE(foo.x, 123);
+ }
+ {
+ QScriptValue num(123);
+ Foo foo = eng.fromScriptValue<Foo>(num);
+ QCOMPARE(foo.x, -1);
+ }
+ {
+ QScriptValue str(&eng, QLatin1String("123"));
+ Foo foo = eng.fromScriptValue<Foo>(str);
+ QCOMPARE(foo.x, 123);
+ }
+
+}
+#endif
+
+void tst_QJSEngine::valueConversion_basic2()
+{
+ QJSEngine eng;
+ // more built-in types
+ {
+ QJSValue val = eng.toScriptValue(uint(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(qulonglong(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(float(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(short(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(ushort(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(char(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(uchar(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+}
+
+void tst_QJSEngine::valueConversion_dateTime()
+{
+ QJSEngine eng;
+ {
+ QDateTime in = QDateTime::currentDateTime();
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isDate());
+ QCOMPARE(val.toDateTime(), in);
+ }
+ {
+ QDate in = QDate::currentDate();
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isDate());
+ QCOMPARE(val.toDateTime().date(), in);
+ }
+}
+
+void tst_QJSEngine::valueConversion_regExp()
+{
+ QJSEngine eng;
+ {
+ QRegExp in = QRegExp("foo");
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QRegExp out = val.toRegExp();
+ QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
+ QCOMPARE(out.patternSyntax(), in.patternSyntax());
+ QCOMPARE(out.pattern(), in.pattern());
+ QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
+ QCOMPARE(out.isMinimal(), in.isMinimal());
+ }
+ {
+ QRegExp in = QRegExp("foo", Qt::CaseSensitive, QRegExp::RegExp2);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QCOMPARE(val.toRegExp(), in);
+ }
+ {
+ QRegExp in = QRegExp("foo");
+ in.setMinimal(true);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
+ QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
+ }
+}
+
+#if 0 // FIXME: No qScriptValueFromValue
+void tst_QJSEngine::qScriptValueFromValue_noEngine()
+{
+ QVERIFY(!qScriptValueFromValue(0, 123).isValid());
+ QVERIFY(!qScriptValueFromValue(0, QVariant(123)).isValid());
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext
+static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
+{
+ return eng->importExtension(ctx->argument(0).toString());
+}
+
+void tst_QJSEngine::importExtension()
+{
+ QStringList libPaths = QCoreApplication::instance()->libraryPaths();
+ QCoreApplication::instance()->setLibraryPaths(QStringList() << SRCDIR);
+
+ QStringList availableExtensions;
+ {
+ QScriptEngine eng;
+ QVERIFY(eng.importedExtensions().isEmpty());
+ QStringList ret = eng.availableExtensions();
+ QCOMPARE(ret.size(), 4);
+ QCOMPARE(ret.at(0), QString::fromLatin1("com"));
+ QCOMPARE(ret.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(ret.at(2), QString::fromLatin1("com.trolltech.recursive"));
+ QCOMPARE(ret.at(3), QString::fromLatin1("com.trolltech.syntaxerror"));
+ availableExtensions = ret;
+ }
+
+ // try to import something that doesn't exist
+ {
+ QScriptEngine eng;
+ QScriptValue ret = eng.importExtension("this.extension.does.not.exist");
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: Unable to import this.extension.does.not.exist: no such extension"));
+ }
+
+ {
+ QScriptEngine eng;
+ for (int x = 0; x < 2; ++x) {
+ QCOMPARE(eng.globalObject().property("com").isValid(), x == 1);
+ QScriptValue ret = eng.importExtension("com.trolltech");
+ QCOMPARE(eng.hasUncaughtException(), false);
+ QCOMPARE(ret.isUndefined(), true);
+
+ QScriptValue com = eng.globalObject().property("com");
+ QCOMPARE(com.isObject(), true);
+ QCOMPARE(com.property("wasDefinedAlready")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+ QCOMPARE(com.property("name")
+ .strictlyEquals(QScriptValue(&eng, "com")), true);
+ QCOMPARE(com.property("level")
+ .strictlyEquals(QScriptValue(&eng, 1)), true);
+ QVERIFY(com.property("originalPostInit").isUndefined());
+ QVERIFY(com.property("postInitCallCount").strictlyEquals(1));
+
+ QScriptValue trolltech = com.property("trolltech");
+ QCOMPARE(trolltech.isObject(), true);
+ QCOMPARE(trolltech.property("wasDefinedAlready")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+ QCOMPARE(trolltech.property("name")
+ .strictlyEquals(QScriptValue(&eng, "com.trolltech")), true);
+ QCOMPARE(trolltech.property("level")
+ .strictlyEquals(QScriptValue(&eng, 2)), true);
+ QVERIFY(trolltech.property("originalPostInit").isUndefined());
+ QVERIFY(trolltech.property("postInitCallCount").strictlyEquals(1));
+ }
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ // recursive import should throw an error
+ {
+ QScriptEngine eng;
+ QVERIFY(eng.importedExtensions().isEmpty());
+ eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
+ QScriptValue ret = eng.importExtension("com.trolltech.recursive");
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: recursive import of com.trolltech.recursive"));
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
+ for (int x = 0; x < 2; ++x) {
+ if (x == 0)
+ QVERIFY(eng.importedExtensions().isEmpty());
+ QScriptValue ret = eng.importExtension("com.trolltech.syntaxerror");
+ QVERIFY(eng.hasUncaughtException());
+ QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue);
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 4);
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QLatin1String("SyntaxError")));
+ }
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ QCoreApplication::instance()->setLibraryPaths(libPaths);
+}
+
+static QScriptValue recurse(QScriptContext *ctx, QScriptEngine *eng)
+{
+ Q_UNUSED(eng);
+ return ctx->callee().call();
+}
+
+static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng)
+{
+ Q_UNUSED(eng);
+ return ctx->callee().construct();
+}
+
+void tst_QJSEngine::infiniteRecursion()
+{
+ // Infinite recursion in JS should cause the VM to throw an error
+ // when the JS stack is exhausted.
+ // The exact error is back-end specific and subject to change.
+ const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded");
+ QScriptEngine eng;
+ {
+ QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();");
+ QCOMPARE(ret.isError(), true);
+ QVERIFY(ret.toString().startsWith(stackOverflowError));
+ }
+#if 0 //The native C++ stack overflow before the JS stack
+ {
+ QScriptValue fun = eng.newFunction(recurse);
+ QScriptValue ret = fun.call();
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), stackOverflowError);
+ }
+ {
+ QScriptValue fun = eng.newFunction(recurse2);
+ QScriptValue ret = fun.construct();
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), stackOverflowError);
+ }
+#endif
+}
+#endif
+
+struct Bar {
+ int a;
+};
+
+struct Baz : public Bar {
+ int b;
+};
+
+Q_DECLARE_METATYPE(Bar*)
+Q_DECLARE_METATYPE(Baz*)
+
+Q_DECLARE_METATYPE(QGradient)
+Q_DECLARE_METATYPE(QGradient*)
+Q_DECLARE_METATYPE(QLinearGradient)
+
+#if 0 // FIXME: No support for default prototypes
+class Zoo : public QObject
+{
+ Q_OBJECT
+public:
+ Zoo() { }
+public slots:
+ Baz *toBaz(Bar *b) { return reinterpret_cast<Baz*>(b); }
+};
+
+void tst_QJSEngine::castWithPrototypeChain()
+{
+ QScriptEngine eng;
+ Bar bar;
+ Baz baz;
+ QScriptValue barProto = eng.toScriptValue(&bar);
+ QScriptValue bazProto = eng.toScriptValue(&baz);
+ eng.setDefaultPrototype(qMetaTypeId<Bar*>(), barProto);
+ eng.setDefaultPrototype(qMetaTypeId<Baz*>(), bazProto);
+
+ Baz baz2;
+ baz2.a = 123;
+ baz2.b = 456;
+ QScriptValue baz2Value = eng.toScriptValue(&baz2);
+ {
+ // qscriptvalue_cast() does magic; if the QScriptValue contains
+ // t of type T, and the target type is T*, &t is returned.
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ QCOMPARE(pbaz->b, baz2.b);
+
+ Zoo zoo;
+ QScriptValue scriptZoo = eng.newQObject(&zoo);
+ QScriptValue toBaz = scriptZoo.property("toBaz");
+ QVERIFY(toBaz.isFunction());
+
+ // no relation between Bar and Baz's proto --> casting fails
+ {
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ {
+ QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to toBaz(); candidates were\n toBaz(Bar*)"));
+ }
+
+ // establish chain -- now casting should work
+ // Why? because qscriptvalue_cast() does magic again.
+ // It the instance itself is not of type T, qscriptvalue_cast()
+ // searches the prototype chain for T, and if it finds one, it infers
+ // that the instance can also be casted to that type. This cast is
+ // _not_ safe and thus relies on the developer doing the right thing.
+ // This is an undocumented feature to enable qscriptvalue_cast() to
+ // be used by prototype functions to cast the JS this-object to C++.
+ bazProto.setPrototype(barProto);
+
+ {
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar != 0);
+ QCOMPARE(pbar->a, baz2.a);
+ }
+
+ {
+ QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
+ QEXPECT_FAIL("", "Cannot convert Baz* to Bar*", Continue);
+ QVERIFY(!ret.isError());
+ QEXPECT_FAIL("", "Cannot convert Baz* to Bar*", Continue);
+ QCOMPARE(qscriptvalue_cast<Baz*>(ret), pbaz);
+ }
+ }
+
+ bazProto.setPrototype(barProto.prototype()); // kill chain
+ {
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ // should not work anymore
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ bazProto.setPrototype(eng.newQObject(this));
+ {
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ // should not work now either
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ {
+ QScriptValue b = eng.toScriptValue(QBrush());
+ b.setPrototype(barProto);
+ // this shows that a "wrong" cast is possible, if you
+ // don't play by the rules (the pointer is actually a QBrush*)...
+ Bar *pbar = qscriptvalue_cast<Bar*>(b);
+ QVERIFY(pbar != 0);
+ }
+
+ {
+ QScriptValue gradientProto = eng.toScriptValue(QGradient());
+ QScriptValue linearGradientProto = eng.toScriptValue(QLinearGradient());
+ linearGradientProto.setPrototype(gradientProto);
+ QLinearGradient lg(10, 20, 30, 40);
+ QScriptValue linearGradient = eng.toScriptValue(lg);
+ {
+ QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
+ QVERIFY(pgrad == 0);
+ }
+ linearGradient.setPrototype(linearGradientProto);
+ {
+ QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
+ QVERIFY(pgrad != 0);
+ QCOMPARE(pgrad->type(), QGradient::LinearGradient);
+ QLinearGradient *plingrad = static_cast<QLinearGradient*>(pgrad);
+ QCOMPARE(plingrad->start(), lg.start());
+ QCOMPARE(plingrad->finalStop(), lg.finalStop());
+ }
+ }
+}
+#endif
+
+class Klazz : public QWidget,
+ public QStandardItem,
+ public QGraphicsItem
+{
+ Q_OBJECT
+public:
+ Klazz(QWidget *parent = 0) : QWidget(parent) { }
+ virtual QRectF boundingRect() const { return QRectF(); }
+ virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
+};
+
+Q_DECLARE_METATYPE(Klazz*)
+Q_DECLARE_METATYPE(QStandardItem*)
+
+void tst_QJSEngine::castWithMultipleInheritance()
+{
+ QJSEngine eng;
+ Klazz klz;
+ QJSValue v = eng.newQObject(&klz);
+
+ QCOMPARE(qjsvalue_cast<Klazz*>(v), &klz);
+ QCOMPARE(qjsvalue_cast<QWidget*>(v), (QWidget *)&klz);
+ QCOMPARE(qjsvalue_cast<QObject*>(v), (QObject *)&klz);
+ QCOMPARE(qjsvalue_cast<QStandardItem*>(v), (QStandardItem *)&klz);
+ QCOMPARE(qjsvalue_cast<QGraphicsItem*>(v), (QGraphicsItem *)&klz);
+}
+
+#if 0 // ###FIXME: ScriptOwnership
+void tst_QJSEngine::collectGarbage()
+{
+ QScriptEngine eng;
+ eng.evaluate("a = new Object(); a = new Object(); a = new Object()");
+ QScriptValue a = eng.newObject();
+ a = eng.newObject();
+ a = eng.newObject();
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ (void)eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
+ collectGarbage_helper(eng);
+ QVERIFY(ptr == 0);
+}
+#endif
+
+#if 0 // ###FIXME: no reportAdditionalMemoryCost API
+void tst_QJSEngine::reportAdditionalMemoryCost()
+{
+ QScriptEngine eng;
+ // There isn't any reliable way to test whether calling
+ // this function affects garbage collection responsiveness;
+ // the best we can do is call it with a few different values.
+ for (int x = 0; x < 100; ++x) {
+ eng.reportAdditionalMemoryCost(0);
+ eng.reportAdditionalMemoryCost(10);
+ eng.reportAdditionalMemoryCost(1000);
+ eng.reportAdditionalMemoryCost(10000);
+ eng.reportAdditionalMemoryCost(100000);
+ eng.reportAdditionalMemoryCost(1000000);
+ eng.reportAdditionalMemoryCost(10000000);
+ eng.reportAdditionalMemoryCost(-1);
+ eng.reportAdditionalMemoryCost(-1000);
+ QScriptValue obj = eng.newObject();
+ eng.collectGarbage();
+ }
+}
+#endif
+
+void tst_QJSEngine::gcWithNestedDataStructure()
+{
+ // The GC must be able to traverse deeply nested objects, otherwise this
+ // test would crash.
+ QJSEngine eng;
+ eng.evaluate(
+ "function makeList(size)"
+ "{"
+ " var head = { };"
+ " var l = head;"
+ " for (var i = 0; i < size; ++i) {"
+ " l.data = i + \"\";"
+ " l.next = { }; l = l.next;"
+ " }"
+ " l.next = null;"
+ " return head;"
+ "}");
+ QCOMPARE(eng.hasUncaughtException(), false);
+ const int size = 200;
+ QJSValue head = eng.evaluate(QString::fromLatin1("makeList(%0)").arg(size));
+ QCOMPARE(eng.hasUncaughtException(), false);
+ for (int x = 0; x < 2; ++x) {
+ if (x == 1)
+ eng.evaluate("gc()");
+ QJSValue l = head;
+ // Make sure all the nodes are still alive.
+ for (int i = 0; i < 200; ++i) {
+ QCOMPARE(l.property("data").toString(), QString::number(i));
+ l = l.property("next");
+ }
+ }
+}
+
+#if 0 // ###FIXME: No processEvents handling
+class EventReceiver : public QObject
+{
+public:
+ EventReceiver() {
+ received = false;
+ }
+
+ bool event(QEvent *e) {
+ received |= (e->type() == QEvent::User + 1);
+ return QObject::event(e);
+ }
+
+ bool received;
+};
+
+void tst_QJSEngine::processEventsWhileRunning()
+{
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine eng;
+ if (x == 0)
+ eng.pushContext();
+
+ // This is running for a silly amount of time just to make sure
+ // the script doesn't finish before event processing is triggered.
+ QString script = QString::fromLatin1(
+ "var end = Number(new Date()) + 2000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "}");
+
+ EventReceiver receiver;
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ eng.evaluate(script);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!receiver.received);
+
+ QCOMPARE(eng.processEventsInterval(), -1);
+ eng.setProcessEventsInterval(100);
+ eng.evaluate(script);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(receiver.received);
+
+ if (x == 0)
+ eng.popContext();
+ }
+}
+
+void tst_QJSEngine::processEventsWhileRunning_function()
+{
+ QScriptEngine eng;
+ QScriptValue script = eng.evaluate(QString::fromLatin1(
+ "(function() { var end = Number(new Date()) + 2000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "} })"));
+
+ eng.setProcessEventsInterval(100);
+
+ for (int x = 0; x < 2; ++x) {
+ EventReceiver receiver;
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!receiver.received);
+ QCOMPARE(eng.processEventsInterval(), 100);
+
+ if (x) script.call();
+ else script.construct();
+
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(receiver.received);
+ }
+}
+
+
+class EventReceiver2 : public QObject
+{
+public:
+ EventReceiver2(QScriptEngine *eng) {
+ engine = eng;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ engine->currentContext()->throwError("Killed");
+ }
+ return QObject::event(e);
+ }
+
+ QScriptEngine *engine;
+};
+
+void tst_QJSEngine::throwErrorFromProcessEvents_data()
+{
+ QTest::addColumn<QString>("script");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("while (1)")
+ << QString::fromLatin1("while (1) { }")
+ << QString::fromLatin1("Error: Killed");
+ QTest::newRow("while (1) i++")
+ << QString::fromLatin1("i = 0; while (1) { i++; }")
+ << QString::fromLatin1("Error: Killed");
+ // Unlike abortEvaluation(), scripts should be able to catch the
+ // exception.
+ QTest::newRow("try catch")
+ << QString::fromLatin1("try {"
+ " while (1) { }"
+ "} catch(e) {"
+ " throw new Error('Caught');"
+ "}")
+ << QString::fromLatin1("Error: Caught");
+}
+
+void tst_QJSEngine::throwErrorFromProcessEvents()
+{
+ QFETCH(QString, script);
+ QFETCH(QString, error);
+
+ QScriptEngine eng;
+
+ EventReceiver2 receiver(&eng);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ eng.setProcessEventsInterval(100);
+ QScriptValue ret = eng.evaluate(script);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), error);
+}
+
+void tst_QJSEngine::disableProcessEventsInterval()
+{
+ QScriptEngine eng;
+ eng.setProcessEventsInterval(100);
+ QCOMPARE(eng.processEventsInterval(), 100);
+ eng.setProcessEventsInterval(0);
+ QCOMPARE(eng.processEventsInterval(), 0);
+ eng.setProcessEventsInterval(-1);
+ QCOMPARE(eng.processEventsInterval(), -1);
+ eng.setProcessEventsInterval(-100);
+ QCOMPARE(eng.processEventsInterval(), -100);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptValueIterator API
+void tst_QJSEngine::stacktrace()
+{
+ QString script = QString::fromLatin1(
+ "function foo(counter) {\n"
+ " switch (counter) {\n"
+ " case 0: foo(counter+1); break;\n"
+ " case 1: foo(counter+1); break;\n"
+ " case 2: foo(counter+1); break;\n"
+ " case 3: foo(counter+1); break;\n"
+ " case 4: foo(counter+1); break;\n"
+ " default:\n"
+ " throw new Error('blah');\n"
+ " }\n"
+ "}\n"
+ "foo(0);");
+
+ const QString fileName("testfile");
+
+ QStringList backtrace;
+ backtrace << "foo(5)@testfile:9"
+ << "foo(4)@testfile:7"
+ << "foo(3)@testfile:6"
+ << "foo(2)@testfile:5"
+ << "foo(1)@testfile:4"
+ << "foo(0)@testfile:3"
+ << "<global>()@testfile:12";
+
+ QScriptEngine eng;
+ QScriptValue result = eng.evaluate(script, fileName);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(result.isError());
+
+ QEXPECT_FAIL("", "QTBUG-6139: uncaughtExceptionBacktrace() doesn't give the full backtrace", Abort);
+ // ###FIXME: no uncahgutExceptionBacktrace: QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(result.strictlyEquals(eng.uncaughtException()));
+
+ QCOMPARE(result.property("fileName").toString(), fileName);
+ QCOMPARE(result.property("lineNumber").toInt32(), 9);
+
+ QScriptValue stack = result.property("stack");
+ QVERIFY(stack.isArray());
+
+ QCOMPARE(stack.property("length").toInt32(), 7);
+
+ QScriptValueIterator it(stack);
+ int counter = 5;
+ while (it.hasNext()) {
+ it.next();
+ QScriptValue obj = it.value();
+ QScriptValue frame = obj.property("frame");
+
+ QCOMPARE(obj.property("fileName").toString(), fileName);
+ if (counter >= 0) {
+ QScriptValue callee = frame.property("arguments").property("callee");
+ QVERIFY(callee.strictlyEquals(eng.globalObject().property("foo")));
+ QCOMPARE(obj.property("functionName").toString(), QString("foo"));
+ int line = obj.property("lineNumber").toInt32();
+ if (counter == 5)
+ QCOMPARE(line, 9);
+ else
+ QCOMPARE(line, 3 + counter);
+ } else {
+ QVERIFY(frame.strictlyEquals(eng.globalObject()));
+ QVERIFY(obj.property("functionName").toString().isEmpty());
+ }
+
+ --counter;
+ }
+
+ {
+ QScriptValue bt = result.property("backtrace").call(result);
+ QCOMPARE(qscriptvalue_cast<QStringList>(bt), backtrace);
+ }
+
+ // throw something that isn't an Error object
+ eng.clearExceptions();
+ // ###FIXME: No uncaughtExceptionBacktrace: QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+ QString script2 = QString::fromLatin1(
+ "function foo(counter) {\n"
+ " switch (counter) {\n"
+ " case 0: foo(counter+1); break;\n"
+ " case 1: foo(counter+1); break;\n"
+ " case 2: foo(counter+1); break;\n"
+ " case 3: foo(counter+1); break;\n"
+ " case 4: foo(counter+1); break;\n"
+ " default:\n"
+ " throw 'just a string';\n"
+ " }\n"
+ "}\n"
+ "foo(0);");
+
+ QScriptValue result2 = eng.evaluate(script2, fileName);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(!result2.isError());
+ QVERIFY(result2.isString());
+
+ // ###FIXME: No uncaughtExceptionBacktrace: QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
+ QVERIFY(eng.hasUncaughtException());
+
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ // ###FIXME: No uncaughtExceptionBacktrace: QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+}
+#endif
+
+void tst_QJSEngine::numberParsing_data()
+{
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<qreal>("expect");
+
+ QTest::newRow("decimal 0") << QString("0") << qreal(0);
+ QTest::newRow("octal 0") << QString("00") << qreal(00);
+ QTest::newRow("hex 0") << QString("0x0") << qreal(0x0);
+ QTest::newRow("decimal 100") << QString("100") << qreal(100);
+ QTest::newRow("hex 100") << QString("0x100") << qreal(0x100);
+ QTest::newRow("octal 100") << QString("0100") << qreal(0100);
+ QTest::newRow("decimal 4G") << QString("4294967296") << qreal(Q_UINT64_C(4294967296));
+ QTest::newRow("hex 4G") << QString("0x100000000") << qreal(Q_UINT64_C(0x100000000));
+ QTest::newRow("octal 4G") << QString("040000000000") << qreal(Q_UINT64_C(040000000000));
+ QTest::newRow("0.5") << QString("0.5") << qreal(0.5);
+ QTest::newRow("1.5") << QString("1.5") << qreal(1.5);
+ QTest::newRow("1e2") << QString("1e2") << qreal(100);
+}
+
+void tst_QJSEngine::numberParsing()
+{
+ QFETCH(QString, string);
+ QFETCH(qreal, expect);
+
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(string);
+ QVERIFY(ret.isNumber());
+ qreal actual = ret.toNumber();
+ QCOMPARE(actual, expect);
+}
+
+// see ECMA-262, section 7.9
+// This is testing ECMA compliance, not our C++ API, but it's important that
+// the back-end is conformant in this regard.
+void tst_QJSEngine::automaticSemicolonInsertion()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("{ 1 2 } 3");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("{ 1\n2 } 3");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("for (a; b\n)");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return\n1 + 2 })()");
+ QVERIFY(ret.isUndefined());
+ }
+ {
+ eng.evaluate("c = 2; b = 1");
+ QJSValue ret = eng.evaluate("a = b\n++c");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("if (a > b)\nelse c = d");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ eng.evaluate("function c() { return { foo: function() { return 5; } } }");
+ eng.evaluate("b = 1; d = 2; e = 3");
+ QJSValue ret = eng.evaluate("a = b + c\n(d + e).foo()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("throw\n1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = Number(1)\n++a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 2);
+ }
+
+ // "a semicolon is never inserted automatically if the semicolon
+ // would then be parsed as an empty statement"
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0)\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0)\n --a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if ((0))\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if ((0))\n --a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0\n)\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0\n ++a; a");
+ QVERIFY(ret.isError());
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0))\n ++a; a");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; for (i = 0; i < 10; ++i)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; for (i = 0; i < 10; ++i)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; for (var i = 0; i < 10; ++i)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; for (var i = 0; i < 10; ++i)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; i = 0; while (i++ < 10)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; i = 0; while (i++ < 10)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (i in o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (i in o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (var i in o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (var i in o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { n: 3 }; n = 5; with (o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 5);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { n: 3 }; n = 10; with (o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 5; i = 0; do\n ++n; while (++i < 10); n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 15);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 20; i = 0; do\n --n; while (++i < 10); n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+
+ {
+ QJSValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 2);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n--n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 0);
+ }
+
+ {
+ QJSValue ret = eng.evaluate("if (0)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("while (0)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("for (;;)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("for (p in this)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("do");
+ QVERIFY(ret.isError());
+ }
+}
+
+#if 0 // ###FIXME: no abortEvaluation API
+class EventReceiver3 : public QObject
+{
+public:
+ enum AbortionResult {
+ None = 0,
+ String = 1,
+ Error = 2,
+ Number = 3
+ };
+
+ EventReceiver3(QScriptEngine *eng) {
+ engine = eng;
+ resultType = None;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ switch (resultType) {
+ case None:
+ engine->abortEvaluation();
+ break;
+ case String:
+ engine->abortEvaluation(QScriptValue(engine, QString::fromLatin1("Aborted")));
+ break;
+ case Error:
+ engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError"));
+ break;
+ case Number:
+ engine->abortEvaluation(QScriptValue(1234));
+ }
+ }
+ return QObject::event(e);
+ }
+
+ AbortionResult resultType;
+ QScriptEngine *engine;
+};
+
+static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine *eng)
+{
+ eng->abortEvaluation();
+ return eng->nullValue(); // should be ignored
+}
+
+void tst_QJSEngine::abortEvaluation_notEvaluating()
+{
+ QScriptEngine eng;
+
+ eng.abortEvaluation();
+ QVERIFY(!eng.hasUncaughtException());
+
+ eng.abortEvaluation(123);
+ {
+ QScriptValue ret = eng.evaluate("'ciao'");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
+ }
+}
+
+void tst_QJSEngine::abortEvaluation_data()
+{
+ QTest::addColumn<QString>("script");
+
+ QTest::newRow("while (1)")
+ << QString::fromLatin1("while (1) { }");
+ QTest::newRow("while (1) i++")
+ << QString::fromLatin1("i = 0; while (1) { i++; }");
+ QTest::newRow("try catch")
+ << QString::fromLatin1("try {"
+ " while (1) { }"
+ "} catch(e) {"
+ " throw new Error('Caught');"
+ "}");
+}
+
+void tst_QJSEngine::abortEvaluation()
+{
+ QFETCH(QString, script);
+
+ QScriptEngine eng;
+ EventReceiver3 receiver(&eng);
+
+ eng.setProcessEventsInterval(100);
+ for (int x = 0; x < 4; ++x) {
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ receiver.resultType = EventReceiver3::AbortionResult(x);
+ QScriptValue ret = eng.evaluate(script);
+ switch (receiver.resultType) {
+ case EventReceiver3::None:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!ret.isValid());
+ break;
+ case EventReceiver3::Number:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1234);
+ break;
+ case EventReceiver3::String:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
+ break;
+ case EventReceiver3::Error:
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: AbortedWithError"));
+ break;
+ }
+ }
+
+}
+
+void tst_QJSEngine::abortEvaluation_tryCatch()
+{
+ QSKIP("It crashes", SkipAll);
+ QScriptEngine eng;
+ EventReceiver3 receiver(&eng);
+ eng.setProcessEventsInterval(100);
+ // scripts cannot intercept the abortion with try/catch
+ for (int y = 0; y < 4; ++y) {
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ receiver.resultType = EventReceiver3::AbortionResult(y);
+ QScriptValue ret = eng.evaluate(QString::fromLatin1(
+ "while (1) {\n"
+ " try {\n"
+ " (function() { while (1) { } })();\n"
+ " } catch (e) {\n"
+ " ;\n"
+ " }\n"
+ "}"));
+ switch (receiver.resultType) {
+ case EventReceiver3::None:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!ret.isValid());
+ break;
+ case EventReceiver3::Number:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1234);
+ break;
+ case EventReceiver3::String:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
+ break;
+ case EventReceiver3::Error:
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.isError());
+ break;
+ }
+ }
+}
+
+void tst_QJSEngine::abortEvaluation_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
+ eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
+ QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
+ QVERIFY(!ret.isValid());
+}
+
+class ThreadedEngine : public QThread {
+ Q_OBJECT;
+
+private:
+ QScriptEngine* m_engine;
+protected:
+ void run() {
+ m_engine = new QScriptEngine();
+ m_engine->setGlobalObject(m_engine->newQObject(this));
+ m_engine->evaluate("while (1) { sleep(); }");
+ delete m_engine;
+ }
+
+public slots:
+ void sleep()
+ {
+ QTest::qSleep(25);
+ m_engine->abortEvaluation();
+ }
+};
+
+void tst_QJSEngine::abortEvaluation_QTBUG9433()
+{
+ ThreadedEngine engine;
+ engine.start();
+ QVERIFY(engine.isRunning());
+ QTest::qSleep(50);
+ for (uint i = 0; i < 50; ++i) { // up to ~2500 ms
+ if (engine.isFinished())
+ return;
+ QTest::qSleep(50);
+ }
+ if (!engine.isFinished()) {
+ engine.terminate();
+ engine.wait(7000);
+ QFAIL("abortEvaluation doesn't work");
+ }
+
+}
+#endif
+
+#if 0 // ###FIXME: no QScriptEngine::isEvaluating
+static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng)
+{
+ return QScriptValue(eng, eng->isEvaluating());
+}
+
+class EventReceiver4 : public QObject
+{
+public:
+ EventReceiver4(QScriptEngine *eng) {
+ engine = eng;
+ wasEvaluating = false;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ wasEvaluating = engine->isEvaluating();
+ }
+ return QObject::event(e);
+ }
+
+ QScriptEngine *engine;
+ bool wasEvaluating;
+};
+
+void tst_QJSEngine::isEvaluating_notEvaluating()
+{
+ QScriptEngine eng;
+
+ QVERIFY(!eng.isEvaluating());
+
+ eng.evaluate("");
+ QVERIFY(!eng.isEvaluating());
+ eng.evaluate("123");
+ QVERIFY(!eng.isEvaluating());
+ eng.evaluate("0 = 0");
+ QVERIFY(!eng.isEvaluating());
+}
+
+void tst_QJSEngine::isEvaluating_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
+ eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
+ QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+ ret = fun.call();
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+ ret = myFunctionReturningIsEvaluating(eng.currentContext(), &eng);
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+}
+
+void tst_QJSEngine::isEvaluating_fromEvent()
+{
+ QScriptEngine eng;
+ EventReceiver4 receiver(&eng);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ QString script = QString::fromLatin1(
+ "var end = Number(new Date()) + 1000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "}");
+
+ eng.setProcessEventsInterval(100);
+ eng.evaluate(script);
+ QVERIFY(receiver.wasEvaluating);
+}
+#endif
+
+static QtMsgType theMessageType;
+static QString theMessage;
+
+static void myMsgHandler(QtMsgType type, const char *msg)
+{
+ theMessageType = type;
+ theMessage = QString::fromLatin1(msg);
+}
+
+#if 0
+void tst_QJSEngine::printFunctionWithCustomHandler()
+{
+ // The built-in print() function passes the output to Qt's message
+ // handler. By installing a custom message handler, the output can be
+ // redirected without changing the print() function itself.
+ // This behavior is not documented.
+ QJSEngine eng;
+ QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler);
+ QVERIFY(eng.globalObject().property("print").isFunction());
+
+ theMessageType = QtSystemMsg;
+ QVERIFY(theMessage.isEmpty());
+ QVERIFY(eng.evaluate("print('test')").isUndefined());
+ QCOMPARE(theMessageType, QtDebugMsg);
+ QCOMPARE(theMessage, QString::fromLatin1("test"));
+
+ theMessageType = QtSystemMsg;
+ theMessage.clear();
+ QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined());
+ QCOMPARE(theMessageType, QtDebugMsg);
+ QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs"));
+
+ qInstallMsgHandler(oldHandler);
+}
+
+void tst_QJSEngine::printThrowsException()
+{
+ // If an argument to print() causes an exception to be thrown when
+ // it's converted to a string, print() should propagate the exception.
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });");
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(QJSValue(&eng, QLatin1String("foo"))));
+}
+#endif
+
+void tst_QJSEngine::errorConstructors()
+{
+ QJSEngine eng;
+ QStringList prefixes;
+ prefixes << "" << "Eval" << "Range" << "Reference" << "Syntax" << "Type" << "URI";
+ for (int x = 0; x < 3; ++x) {
+ for (int i = 0; i < prefixes.size(); ++i) {
+ QString name = prefixes.at(i) + QLatin1String("Error");
+ QString code = QString(i+1, QLatin1Char('\n'));
+ if (x == 0)
+ code += QLatin1String("throw ");
+ else if (x == 1)
+ code += QLatin1String("new ");
+ code += name + QLatin1String("()");
+ QJSValue ret = eng.evaluate(code);
+ QVERIFY(ret.isError());
+ QCOMPARE(eng.hasUncaughtException(), x == 0);
+ eng.clearExceptions();
+ QVERIFY(ret.toString().startsWith(name));
+ //QTBUG-6138: JSC doesn't assign lineNumber when errors are not thrown
+ QEXPECT_FAIL("", "we have no more lineNumber property ", Continue);
+ QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
+ }
+ }
+}
+
+void tst_QJSEngine::argumentsProperty_globalContext()
+{
+ QJSEngine eng;
+ {
+ // Unlike function calls, the global context doesn't have an
+ // arguments property.
+ QJSValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ eng.evaluate("arguments = 10");
+ {
+ QJSValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ QVERIFY(eng.evaluate("delete arguments").toBoolean());
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+}
+
+void tst_QJSEngine::argumentsProperty_JS()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = { arguments: 123 }");
+ QJSValue ret = eng.evaluate("with (o) { arguments; }");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ QJSEngine eng;
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+ // This is testing ECMA-262 compliance. In function calls, "arguments"
+ // appears like a local variable, and it can be replaced.
+ QJSValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+ }
+}
+
+#if 0 // ###FIXME: no QScriptContext API
+static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
+{
+ // Since evaluate() is done in the current context, "arguments" should
+ // refer to currentContext()->argumentsObject().
+ // This is for consistency with the built-in JS eval() function.
+ eng->evaluate("var a = arguments[0];");
+ eng->evaluate("arguments[0] = 200;");
+ return eng->evaluate("a + arguments[0]");
+}
+
+void tst_QJSEngine::argumentsProperty_evaluateInNativeFunction()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(argumentsProperty_fun);
+ eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
+ QScriptValue result = eng.evaluate("fun(18)");
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toInt32(), 200+18);
+}
+#endif
+
+void tst_QJSEngine::jsNumberClass()
+{
+ // See ECMA-262 Section 15.7, "Number Objects".
+
+ QJSEngine eng;
+
+ QJSValue ctor = eng.globalObject().property("Number");
+ QVERIFY(ctor.property("length").isNumber());
+ QCOMPARE(ctor.property("length").toNumber(), qreal(1));
+ QJSValue proto = ctor.property("prototype");
+ QVERIFY(proto.isObject());
+ {
+ QJSValue::PropertyFlags flags = QJSValue::SkipInEnumeration
+ | QJSValue::Undeletable
+ | QJSValue::ReadOnly;
+ QCOMPARE(ctor.propertyFlags("prototype"), flags);
+ QVERIFY(ctor.property("MAX_VALUE").isNumber());
+ QCOMPARE(ctor.propertyFlags("MAX_VALUE"), flags);
+ QVERIFY(ctor.property("MIN_VALUE").isNumber());
+ QCOMPARE(ctor.propertyFlags("MIN_VALUE"), flags);
+ QVERIFY(ctor.property("NaN").isNumber());
+ QCOMPARE(ctor.propertyFlags("NaN"), flags);
+ QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber());
+ QCOMPARE(ctor.propertyFlags("NEGATIVE_INFINITY"), flags);
+ QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber());
+ QCOMPARE(ctor.propertyFlags("POSITIVE_INFINITY"), flags);
+ }
+ QVERIFY(proto.instanceOf(eng.globalObject().property("Object")));
+ QCOMPARE(proto.toNumber(), qreal(0));
+ QVERIFY(proto.property("constructor").strictlyEquals(ctor));
+
+ {
+ QJSValue ret = eng.evaluate("Number()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(0));
+ }
+ {
+ QJSValue ret = eng.evaluate("Number(123)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ {
+ QJSValue ret = eng.evaluate("Number('456')");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(456));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number()");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(0));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123)");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number('456')");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(456));
+ }
+
+ QVERIFY(proto.property("toString").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString(8)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("173"));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString(16)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("7b"));
+ }
+ QVERIFY(proto.property("toLocaleString").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toLocaleString()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ QVERIFY(proto.property("valueOf").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).valueOf()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ QVERIFY(proto.property("toExponential").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toExponential()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
+ }
+ QVERIFY(proto.property("toFixed").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toFixed()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ QVERIFY(proto.property("toPrecision").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toPrecision()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_simple()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("o = { }; r = []; for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QVERIFY(lst.isEmpty());
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("q"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_prototypeProperties()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { q: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("q"));
+ }
+ {
+ // shadowed property
+ QJSValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { p: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+}
+
+void tst_QJSEngine::jsForInStatement_mutateWhileIterating()
+{
+ QJSEngine eng;
+ // deleting property during enumeration
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) { r[r.length] = p; delete r[p]; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
+ "for (var p in o) { r[r.length] = p; delete o.q; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+ // adding property during enumeration
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) { r[r.length] = p; o.q = 456; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+}
+
+void tst_QJSEngine::jsForInStatement_arrays()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar'; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 3);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar';"
+ "b = [111, 222, 333]; b.bar = 'baz';"
+ "a.__proto__ = b; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 5);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
+ QCOMPARE(lst.at(3), QString::fromLatin1("2"));
+ QCOMPARE(lst.at(4), QString::fromLatin1("bar"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_nullAndUndefined()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
+ {
+ QJSValue ret = eng.evaluate("r = true; for (var p in null) r = false; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
+}
+
+void tst_QJSEngine::jsFunctionDeclarationAsStatement()
+{
+ // ECMA-262 does not allow function declarations to be used as statements,
+ // but several popular implementations (including JSC) do. See the NOTE
+ // at the beginning of chapter 12 in ECMA-262 5th edition, where it's
+ // recommended that implementations either disallow this usage or issue
+ // a warning.
+ // Since we had a bug report long ago about QtScript not supporting this
+ // "feature" (and thus deviating from other implementations), we still
+ // check this behavior.
+
+ QJSEngine eng;
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ eng.evaluate("function foo(arg) {\n"
+ " if (arg == 'bar')\n"
+ " function bar() { return 'bar'; }\n"
+ " else\n"
+ " function baz() { return 'baz'; }\n"
+ " return (arg == 'bar') ? bar : baz;\n"
+ "}");
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ QVERIFY(eng.evaluate("foo").isFunction());
+ {
+ QJSValue ret = eng.evaluate("foo('bar')");
+ QVERIFY(ret.isFunction());
+ QJSValue ret2 = ret.call(QJSValue());
+ QCOMPARE(ret2.toString(), QString::fromLatin1("bar"));
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ }
+ {
+ QJSValue ret = eng.evaluate("foo('baz')");
+ QVERIFY(ret.isFunction());
+ QJSValue ret2 = ret.call(QJSValue());
+ QCOMPARE(ret2.toString(), QString::fromLatin1("baz"));
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ }
+}
+
+void tst_QJSEngine::stringObjects()
+{
+ // See ECMA-262 Section 15.5, "String Objects".
+
+ QJSEngine eng;
+ QString str("ciao");
+ // in C++
+ {
+ QJSValue obj = QJSValue(&eng, str).toObject();
+ QCOMPARE(obj.property("length").toInt32(), str.length());
+ QCOMPARE(obj.propertyFlags("length"), QJSValue::PropertyFlags(QJSValue::Undeletable | QJSValue::SkipInEnumeration | QJSValue::ReadOnly));
+ for (int i = 0; i < str.length(); ++i) {
+ QString pname = QString::number(i);
+ QVERIFY(obj.property(pname).isString());
+ QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
+ QEXPECT_FAIL("", "FIXME: This is V8 issue 862. ECMA script standard 15.5.5.2 compliance.", Continue);
+ QCOMPARE(obj.propertyFlags(pname), QJSValue::PropertyFlags(QJSValue::Undeletable | QJSValue::ReadOnly));
+ obj.setProperty(pname, QJSValue());
+ obj.setProperty(pname, QJSValue(&eng, 123));
+ QVERIFY(obj.property(pname).isString());
+ QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
+ }
+ QVERIFY(!obj.property("-1").isValid());
+ QVERIFY(!obj.property(QString::number(str.length())).isValid());
+
+ QJSValue val(&eng, 123);
+ obj.setProperty("-1", val);
+ QVERIFY(obj.property("-1").strictlyEquals(val));
+ obj.setProperty("100", val);
+ QVERIFY(obj.property("100").strictlyEquals(val));
+ }
+
+ // in script
+ {
+ QJSValue ret = eng.evaluate("s = new String('ciao'); r = []; for (var p in s) r.push(p); r");
+ QVERIFY(ret.isArray());
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), str.length());
+ for (int i = 0; i < str.length(); ++i)
+ QCOMPARE(lst.at(i), QString::number(i));
+
+ QJSValue ret2 = eng.evaluate("s[0] = 123; s[0]");
+ QVERIFY(ret2.isString());
+ QCOMPARE(ret2.toString().length(), 1);
+ QCOMPARE(ret2.toString().at(0), str.at(0));
+
+ QJSValue ret3 = eng.evaluate("s[-1] = 123; s[-1]");
+ QVERIFY(ret3.isNumber());
+ QCOMPARE(ret3.toInt32(), 123);
+
+ QJSValue ret4 = eng.evaluate("s[s.length] = 456; s[s.length]");
+ QVERIFY(ret4.isNumber());
+ QCOMPARE(ret4.toInt32(), 456);
+
+ QJSValue ret5 = eng.evaluate("delete s[0]");
+ QVERIFY(ret5.isBoolean());
+ QEXPECT_FAIL("", "FIXME: This is V8 bug, please report it! ECMA script standard 15.5.5.2", Abort);
+ QVERIFY(!ret5.toBoolean());
+
+ QJSValue ret6 = eng.evaluate("delete s[-1]");
+ QVERIFY(ret6.isBoolean());
+ QVERIFY(ret6.toBoolean());
+
+ QJSValue ret7 = eng.evaluate("delete s[s.length]");
+ QVERIFY(ret7.isBoolean());
+ QVERIFY(ret7.toBoolean());
+ }
+}
+
+void tst_QJSEngine::jsStringPrototypeReplaceBugs()
+{
+ QJSEngine eng;
+ // task 212440
+ {
+ QJSValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args");
+ QVERIFY(ret.isArray());
+ int len = ret.property("length").toInt32();
+ QCOMPARE(len, 3);
+ for (int i = 0; i < len; ++i) {
+ QJSValue args = ret.property(i);
+ QCOMPARE(args.property("length").toInt32(), 4);
+ QCOMPARE(args.property(0).toString(), QString::fromLatin1("a")); // matched string
+ QCOMPARE(args.property(1).toString(), QString::fromLatin1("a")); // capture
+ QVERIFY(args.property(2).isNumber());
+ QCOMPARE(args.property(2).toInt32(), i*2); // index of match
+ QCOMPARE(args.property(3).toString(), QString::fromLatin1("a a a"));
+ }
+ }
+ // task 212501
+ {
+ QJSValue ret = eng.evaluate("\"foo\".replace(/a/g, function() {})");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_global()
+{
+ {
+ QJSEngine eng;
+ // read
+ eng.evaluate("__defineGetter__('x', function() { return this; });");
+ {
+ QJSValue ret = eng.evaluate("x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return x; })()");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this) x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("with ({}) x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { with ({}) return x; })()");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ // write
+ eng.evaluate("__defineSetter__('x', function() { return this; });");
+ {
+ QJSValue ret = eng.evaluate("x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return x = 'foo'; })()");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this) x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("with ({}) x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { with ({}) return x = 'foo'; })()");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_plain()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = {}");
+ // read
+ eng.evaluate("o.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("o.x === o").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
+ QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
+ eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
+ // write
+ eng.evaluate("o.__defineSetter__('x', function() { return this; });");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_prototypeChain()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = {}; p = {}; o.__proto__ = p");
+ // read
+ eng.evaluate("p.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("o.x === o").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
+ QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
+ eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
+ eng.evaluate("with (q) with (o) x").equals(eng.evaluate("o"));
+ // write
+ eng.evaluate("o.__defineSetter__('x', function() { return this; });");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
+ }
+}
+
+#if 0 // ###FIXME: no QScriptContext API
+void tst_QJSEngine::getterSetterThisObject_activation()
+{
+ {
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QVERIFY(ctx != 0);
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("act", act);
+ // read
+ eng.evaluate("act.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("x === act").toBoolean());
+ QEXPECT_FAIL("", "QTBUG-17605: Not possible to implement local variables as getter/setter properties", Abort);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(eng.evaluate("with (act) x").equals("foo"));
+ QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean());
+ eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act"));
+ eng.evaluate("with (q) with (act) x").equals(eng.evaluate("act"));
+ // write
+ eng.evaluate("act.__defineSetter__('x', function() { return this; });");
+ QVERIFY(eng.evaluate("(x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (act) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (act) with (q) x = 'foo'").equals("foo"));
+ eng.popContext();
+ }
+}
+#endif
+
+void tst_QJSEngine::jsContinueInSwitch()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ QJSEngine eng;
+ // switch - continue
+ {
+ QJSValue ret = eng.evaluate("switch (1) { default: continue; }");
+ QVERIFY(ret.isError());
+ }
+ // for - switch - case - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " case 100: ++j; continue;\n"
+ " case 1000: ++j; continue;\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ // for - switch - case - default - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " case 100: ++j; continue;\n"
+ " case 1000: ++j; continue;\n"
+ " default: if (i < 50000) break; else continue;\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ // switch - for - continue
+ {
+ QJSValue ret = eng.evaluate("j = 123; switch (j) {\n"
+ " case 123:\n"
+ " for (i = 0; i < 100000; ++i) {\n"
+ " continue;\n"
+ " }\n"
+ "}; i\n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 100000);
+ }
+ // switch - switch - continue
+ {
+ QJSValue ret = eng.evaluate("i = 1; switch (i) { default: switch (i) { case 1: continue; } }");
+ QVERIFY(ret.isError());
+ }
+ // for - switch - switch - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1:\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " }\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1);
+ }
+ // switch - for - switch - continue
+ {
+ QJSValue ret = eng.evaluate("j = 123; switch (j) {\n"
+ " case 123:\n"
+ " for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1:\n"
+ " ++j; continue;\n"
+ " }\n"
+ " }\n"
+ "}; i\n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 100000);
+ }
+}
+
+void tst_QJSEngine::jsShadowReadOnlyPrototypeProperty()
+{
+ // SpiderMonkey has different behavior than JSC and V8; it disallows
+ // creating a property on the instance if there's a property with the
+ // same name in the prototype, and that property is read-only. We
+ // adopted that behavior in the old (4.5) QtScript back-end, but it
+ // just seems weird -- and non-compliant. Adopt the JSC behavior instead.
+ QJSEngine eng;
+ QVERIFY(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").isNumber());
+ QCOMPARE(eng.evaluate("o.length = 123; o.length").toInt32(), 123);
+ QVERIFY(eng.evaluate("o.hasOwnProperty('length')").toBoolean());
+}
+
+void tst_QJSEngine::toObject()
+{
+ QJSEngine eng;
+
+ QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
+
+ QVERIFY(!eng.toObject(eng.nullValue()).isValid());
+
+ QJSValue falskt(false);
+ {
+ QJSValue tmp = eng.toObject(falskt);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), falskt.toNumber());
+ }
+ QVERIFY(falskt.isBool());
+
+ QJSValue sant(true);
+ {
+ QJSValue tmp = eng.toObject(sant);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), sant.toNumber());
+ }
+ QVERIFY(sant.isBool());
+
+ QJSValue number(123.0);
+ {
+ QJSValue tmp = eng.toObject(number);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), number.toNumber());
+ }
+ QVERIFY(number.isNumber());
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ {
+ QJSValue tmp = eng.toObject(str);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toString(), str.toString());
+ }
+ QVERIFY(str.isString());
+
+ QJSValue object = eng.newObject();
+ {
+ QJSValue tmp = eng.toObject(object);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.strictlyEquals(object));
+ }
+
+ QJSValue qobject = eng.newQObject(this);
+ QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
+
+ QVERIFY(!eng.toObject(QJSValue()).isValid());
+
+ // v1 constructors
+
+ QJSValue boolValue(&eng, true);
+ {
+ QJSValue ret = eng.toObject(boolValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toBool(), boolValue.toBool());
+ }
+ QVERIFY(boolValue.isBool());
+
+ QJSValue numberValue(&eng, 123.0);
+ {
+ QJSValue ret = eng.toObject(numberValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), numberValue.toNumber());
+ }
+ QVERIFY(numberValue.isNumber());
+
+ QJSValue stringValue(&eng, QString::fromLatin1("foo"));
+ {
+ QJSValue ret = eng.toObject(stringValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toString(), stringValue.toString());
+ }
+ QVERIFY(stringValue.isString());
+}
+
+void tst_QJSEngine::jsReservedWords_data()
+{
+ QTest::addColumn<QString>("word");
+ QTest::newRow("break") << QString("break");
+ QTest::newRow("case") << QString("case");
+ QTest::newRow("catch") << QString("catch");
+ QTest::newRow("continue") << QString("continue");
+ QTest::newRow("default") << QString("default");
+ QTest::newRow("delete") << QString("delete");
+ QTest::newRow("do") << QString("do");
+ QTest::newRow("else") << QString("else");
+ QTest::newRow("false") << QString("false");
+ QTest::newRow("finally") << QString("finally");
+ QTest::newRow("for") << QString("for");
+ QTest::newRow("function") << QString("function");
+ QTest::newRow("if") << QString("if");
+ QTest::newRow("in") << QString("in");
+ QTest::newRow("instanceof") << QString("instanceof");
+ QTest::newRow("new") << QString("new");
+ QTest::newRow("null") << QString("null");
+ QTest::newRow("return") << QString("return");
+ QTest::newRow("switch") << QString("switch");
+ QTest::newRow("this") << QString("this");
+ QTest::newRow("throw") << QString("throw");
+ QTest::newRow("true") << QString("true");
+ QTest::newRow("try") << QString("try");
+ QTest::newRow("typeof") << QString("typeof");
+ QTest::newRow("var") << QString("var");
+ QTest::newRow("void") << QString("void");
+ QTest::newRow("while") << QString("while");
+ QTest::newRow("with") << QString("with");
+}
+
+void tst_QJSEngine::jsReservedWords()
+{
+ // See ECMA-262 Section 7.6.1, "Reserved Words".
+ // We prefer that the implementation is less strict than the spec; e.g.
+ // it's good to allow reserved words as identifiers in object literals,
+ // and when accessing properties using dot notation.
+
+ QFETCH(QString, word);
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(word + " = 123");
+ QVERIFY(ret.isError());
+ QString str = ret.toString();
+ QVERIFY(str.startsWith("SyntaxError") || str.startsWith("ReferenceError"));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("var " + word + " = 123");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().startsWith("SyntaxError"));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = {}; o." + word + " = 123");
+ // in the old back-end, in SpiderMonkey and in v8, this is allowed, but not in JSC
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.strictlyEquals(eng.evaluate("o." + word)));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = { " + word + ": 123 }");
+ // in the old back-end, in SpiderMonkey and in v8, this is allowed, but not in JSC
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.property(word).isNumber());
+ }
+ {
+ // SpiderMonkey allows this, but we don't
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("function " + word + "() {}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().startsWith("SyntaxError"));
+ }
+}
+
+void tst_QJSEngine::jsFutureReservedWords_data()
+{
+ QTest::addColumn<QString>("word");
+ QTest::addColumn<bool>("allowed");
+ QTest::newRow("abstract") << QString("abstract") << true;
+ QTest::newRow("boolean") << QString("boolean") << true;
+ QTest::newRow("byte") << QString("byte") << true;
+ QTest::newRow("char") << QString("char") << true;
+ QTest::newRow("class") << QString("class") << false;
+ QTest::newRow("const") << QString("const") << false;
+ QTest::newRow("debugger") << QString("debugger") << false;
+ QTest::newRow("double") << QString("double") << true;
+ QTest::newRow("enum") << QString("enum") << false;
+ QTest::newRow("export") << QString("export") << false;
+ QTest::newRow("extends") << QString("extends") << false;
+ QTest::newRow("final") << QString("final") << true;
+ QTest::newRow("float") << QString("float") << true;
+ QTest::newRow("goto") << QString("goto") << true;
+ QTest::newRow("implements") << QString("implements") << true;
+ QTest::newRow("import") << QString("import") << false;
+ QTest::newRow("int") << QString("int") << true;
+ QTest::newRow("interface") << QString("interface") << true;
+ QTest::newRow("long") << QString("long") << true;
+ QTest::newRow("native") << QString("native") << true;
+ QTest::newRow("package") << QString("package") << true;
+ QTest::newRow("private") << QString("private") << true;
+ QTest::newRow("protected") << QString("protected") << true;
+ QTest::newRow("public") << QString("public") << true;
+ QTest::newRow("short") << QString("short") << true;
+ QTest::newRow("static") << QString("static") << true;
+ QTest::newRow("super") << QString("super") << false;
+ QTest::newRow("synchronized") << QString("synchronized") << true;
+ QTest::newRow("throws") << QString("throws") << true;
+ QTest::newRow("transient") << QString("transient") << true;
+ QTest::newRow("volatile") << QString("volatile") << true;
+}
+
+void tst_QJSEngine::jsFutureReservedWords()
+{
+ QSKIP("Fails", SkipAll);
+ // See ECMA-262 Section 7.6.1.2, "Future Reserved Words".
+ // In real-world implementations, most of these words are
+ // actually allowed as normal identifiers.
+
+ QFETCH(QString, word);
+ QFETCH(bool, allowed);
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(word + " = 123");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("var " + word + " = 123");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ // this should probably be allowed (see task 162567)
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = {}; o." + word + " = 123");
+ QCOMPARE(ret.isNumber(), allowed);
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ // this should probably be allowed (see task 162567)
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = { " + word + ": 123 }");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+}
+
+void tst_QJSEngine::jsThrowInsideWithStatement()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ // task 209988
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate(
+ "try {"
+ " o = { bad : \"bug\" };"
+ " with (o) {"
+ " throw 123;"
+ " }"
+ "} catch (e) {"
+ " bad;"
+ "}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ {
+ QJSValue ret = eng.evaluate(
+ "try {"
+ " o = { bad : \"bug\" };"
+ " with (o) {"
+ " throw 123;"
+ " }"
+ "} finally {"
+ " bad;"
+ "}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ {
+ eng.clearExceptions();
+ QJSValue ret = eng.evaluate(
+ "o = { bug : \"no bug\" };"
+ "with (o) {"
+ " try {"
+ " throw 123;"
+ " } finally {"
+ " bug;"
+ " }"
+ "}");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QVERIFY(eng.hasUncaughtException());
+ }
+ {
+ eng.clearExceptions();
+ QJSValue ret = eng.evaluate(
+ "o = { bug : \"no bug\" };"
+ "with (o) {"
+ " throw 123;"
+ "}");
+ QVERIFY(ret.isNumber());
+ QJSValue ret2 = eng.evaluate("bug");
+ QVERIFY(ret2.isError());
+ QVERIFY(ret2.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+}
+
+#if 0 // ###FIXME: No QScriptEngineAgent API
+class TestAgent : public QScriptEngineAgent
+{
+public:
+ TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {}
+};
+
+void tst_QJSEngine::getSetAgent_ownership()
+{
+ // engine deleted before agent --> agent deleted too
+ QScriptEngine *eng = new QScriptEngine;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ eng->setAgent(0); // the engine maintains ownership of the old agent
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ delete eng;
+}
+
+void tst_QJSEngine::getSetAgent_deleteAgent()
+{
+ // agent deleted before engine --> engine's agent should become 0
+ QScriptEngine *eng = new QScriptEngine;
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ delete agent;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ eng->evaluate("(function(){ return 123; })()");
+ delete eng;
+}
+
+void tst_QJSEngine::getSetAgent_differentEngine()
+{
+ QScriptEngine eng;
+ QScriptEngine eng2;
+ TestAgent *agent = new TestAgent(&eng);
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
+ eng2.setAgent(agent);
+ QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptString API
+void tst_QJSEngine::reentrancy_stringHandles()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ QScriptString s1 = eng1.toStringHandle("foo");
+ QScriptString s2 = eng2.toStringHandle("foo");
+ QVERIFY(s1 != s2);
+}
+#endif
+
+#if 0 // ###FIXME: No processEventsInterval API
+void tst_QJSEngine::reentrancy_processEventsInterval()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ eng1.setProcessEventsInterval(123);
+ QCOMPARE(eng2.processEventsInterval(), -1);
+ eng2.setProcessEventsInterval(456);
+ QCOMPARE(eng1.processEventsInterval(), 123);
+}
+#endif
+
+#if 0 // FIXME: No support for custom types
+void tst_QJSEngine::reentrancy_typeConversion()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ {
+ QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
+ QVERIFY(fooVal.isObject());
+ QVERIFY(!fooVal.isVariant());
+ QCOMPARE(fooVal.property("x").toInt32(), 12);
+ QCOMPARE(fooVal.property("y").toInt32(), 34);
+ fooVal.setProperty("x", 56);
+ fooVal.setProperty("y", 78);
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 56);
+ QCOMPARE(foo2.y, 78);
+ }
+ {
+ QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
+ QVERIFY(fooVal.isVariant());
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 12);
+ QCOMPARE(foo2.y, 34);
+ }
+ QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto1 = eng1.newObject();
+ eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto2 = eng2.newObject();
+ eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
+ QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
+}
+#endif
+
+void tst_QJSEngine::reentrancy_globalObjectProperties()
+{
+ QJSEngine eng1;
+ QJSEngine eng2;
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng1.evaluate("a = 10");
+ QVERIFY(eng1.globalObject().property("a").isNumber());
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng2.evaluate("a = 20");
+ QVERIFY(eng2.globalObject().property("a").isNumber());
+ QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
+}
+
+void tst_QJSEngine::reentrancy_Array()
+{
+ // weird bug with JSC backend
+ {
+ QJSEngine eng;
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ eng.evaluate("Array.prototype.toString");
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ }
+ {
+ QJSEngine eng;
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ }
+}
+
+void tst_QJSEngine::reentrancy_objectCreation()
+{
+ QJSEngine eng1;
+ QJSEngine eng2;
+ {
+ QJSValue d1 = eng1.newDate(0);
+ QJSValue d2 = eng2.newDate(0);
+ QCOMPARE(d1.toDateTime(), d2.toDateTime());
+ QCOMPARE(d2.toDateTime(), d1.toDateTime());
+ }
+ {
+ QJSValue r1 = eng1.newRegExp("foo", "gim");
+ QJSValue r2 = eng2.newRegExp("foo", "gim");
+ QCOMPARE(r1.toRegExp(), r2.toRegExp());
+ QCOMPARE(r2.toRegExp(), r1.toRegExp());
+ }
+ {
+ QJSValue o1 = eng1.newQObject(this);
+ QJSValue o2 = eng2.newQObject(this);
+ QCOMPARE(o1.toQObject(), o2.toQObject());
+ QCOMPARE(o2.toQObject(), o1.toQObject());
+ }
+#if 0 // ###FIXME: No QScriptEngine::newQMetaObject API
+ {
+ QScriptValue mo1 = eng1.newQMetaObject(&staticMetaObject);
+ QScriptValue mo2 = eng2.newQMetaObject(&staticMetaObject);
+ QCOMPARE(mo1.toQMetaObject(), mo2.toQMetaObject());
+ QCOMPARE(mo2.toQMetaObject(), mo1.toQMetaObject());
+ }
+#endif
+}
+
+void tst_QJSEngine::jsIncDecNonObjectProperty()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("var a; a.n++");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n--");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = null; a.n++");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = null; a.n--");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; ++a.n");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; --a.n");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n += 1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n -= 1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; a.length++");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 4);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; a.length--");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 4);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; ++a.length");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 5);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; --a.length");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+}
+
+#if 0 // ###FIXME: no installTranslatorFunctions API
+void tst_QJSEngine::installTranslatorFunctions()
+{
+ QScriptEngine eng;
+ QScriptValue global = eng.globalObject();
+ QVERIFY(!global.property("qsTranslate").isValid());
+ QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid());
+ QVERIFY(!global.property("qsTr").isValid());
+ QVERIFY(!global.property("QT_TR_NOOP").isValid());
+ QVERIFY(!global.property("qsTrId").isValid());
+ QVERIFY(!global.property("QT_TRID_NOOP").isValid());
+ QVERIFY(!global.property("String").property("prototype").property("arg").isValid());
+
+ eng.installTranslatorFunctions();
+ QVERIFY(global.property("qsTranslate").isFunction());
+ QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction());
+ QVERIFY(global.property("qsTr").isFunction());
+ QVERIFY(global.property("QT_TR_NOOP").isFunction());
+ QVERIFY(global.property("qsTrId").isFunction());
+ QVERIFY(global.property("QT_TRID_NOOP").isFunction());
+ QVERIFY(global.property("String").property("prototype").property("arg").isFunction());
+
+ {
+ QScriptValue ret = eng.evaluate("qsTr('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("qsTranslate('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TR_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("'foo%0'.arg('bar')");
+ QEXPECT_FAIL("Custom global object", "FIXME: why we expect that String prototype exists?", Abort);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("'foo%0'.arg(123)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo123"));
+ }
+ {
+ // Maybe this should throw an error?
+ QScriptValue ret = eng.evaluate("'foo%0'.arg()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString());
+ }
+
+ {
+ QScriptValue ret = eng.evaluate("qsTrId('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TRID_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ QVERIFY(eng.evaluate("QT_TRID_NOOP()").isUndefined());
+}
+
+class TranslationScope
+{
+public:
+ TranslationScope(const QString &fileName)
+ {
+ translator.load(fileName);
+ QCoreApplication::instance()->installTranslator(&translator);
+ }
+ ~TranslationScope()
+ {
+ QCoreApplication::instance()->removeTranslator(&translator);
+ }
+
+private:
+ QTranslator translator;
+};
+
+void tst_QJSEngine::translateScript_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ // Top-level
+ QTest::newRow("qsTr('One')@translatable.js")
+ << QString::fromLatin1("qsTr('One')") << fileName << QString::fromLatin1("En");
+ QTest::newRow("qsTr('Hello')@translatable.js")
+ << QString::fromLatin1("qsTr('Hello')") << fileName << QString::fromLatin1("Hallo");
+ // From function
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName << QString::fromLatin1("En");
+ QTest::newRow("(function() { return qsTr('Hello'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('Hello'); })()") << fileName << QString::fromLatin1("Hallo");
+ // From eval
+ QTest::newRow("eval('qsTr(\\'One\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTr(\\'One\\')')") << fileName << QString::fromLatin1("En");
+ QTest::newRow("eval('qsTr(\\'Hello\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTr(\\'Hello\\')')") << fileName << QString::fromLatin1("Hallo");
+ // Plural
+ QTest::newRow("qsTr('%n message(s) saved', '', 1)@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 1)") << fileName << QString::fromLatin1("1 melding lagret");
+ QTest::newRow("qsTr('%n message(s) saved', '', 3).arg@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 3)") << fileName << QString::fromLatin1("3 meldinger lagret");
+
+ // Top-level
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye')") << fileName << QString::fromLatin1("Farvel");
+ // From eval
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8')") << fileName << QString::fromLatin1("Farvel");
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'CodecForTr')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'CodecForTr')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8', 42)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8', 42)") << fileName << QString::fromLatin1("Goodbye");
+
+ QTest::newRow("qsTr('One', 'not the same one')@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one')") << fileName << QString::fromLatin1("Enda en");
+
+ QTest::newRow("qsTr('One', 'not the same one', 42)@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one', 42)") << fileName << QString::fromLatin1("One");
+
+ // Plural
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 1)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 1)") << fileName << QString::fromLatin1("1 fooaktig bar funnet");
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 2)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 2)") << fileName << QString::fromLatin1("2 fooaktige barer funnet");
+
+ // Don't exist in translation
+ QTest::newRow("qsTr('Three')@translatable.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName << QString::fromLatin1("Three");
+ QTest::newRow("qsTranslate('FooContext', 'So long')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'So long')") << fileName << QString::fromLatin1("So long");
+ QTest::newRow("qsTranslate('BarContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Goodbye')") << fileName << QString::fromLatin1("Goodbye");
+
+ // Translate strings from the second script (translatable2.js)
+
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ QTest::newRow("qsTr('Three')@translatable2.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName2 << QString::fromLatin1("Tre");
+ QTest::newRow("qsTr('Happy birthday!')@translatable2.js")
+ << QString::fromLatin1("qsTr('Happy birthday!')") << fileName2 << QString::fromLatin1("Gratulerer med dagen!");
+
+ // Not translated because translation is only in translatable.js
+ QTest::newRow("qsTr('One')@translatable2.js")
+ << QString::fromLatin1("qsTr('One')") << fileName2 << QString::fromLatin1("One");
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable2.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName2 << QString::fromLatin1("One");
+
+ // For qsTranslate() the filename shouldn't matter
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable2.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName2 << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('BarContext', 'Congratulations!')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Congratulations!')") << fileName << QString::fromLatin1("Gratulerer!");
+}
+
+void tst_QJSEngine::translateScript()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateScript_crossScript()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ // qsTr() should use the innermost filename as context
+ engine.evaluate("function foo(s) { return bar(s); }", fileName);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName2);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('Three')", fileName).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("One"));
+
+ engine.evaluate("function foo(s) { return bar(s); }", fileName2);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Three"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName).toString(), QString::fromLatin1("En"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("En"));
+}
+
+static QScriptValue callQsTr(QScriptContext *ctx, QScriptEngine *eng)
+{
+ return eng->globalObject().property("qsTr").call(ctx->thisObject(), ctx->argumentsObject());
+}
+
+void tst_QJSEngine::translateScript_callQsTrFromNative()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ // Calling qsTr() from a native function
+ engine.globalObject().setProperty("qsTrProxy", engine.newFunction(callQsTr));
+ QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName).toString(), QString::fromLatin1("En"));
+ QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName2).toString(), QString::fromLatin1("One"));
+ QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName).toString(), QString::fromLatin1("Three"));
+ QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
+}
+
+void tst_QJSEngine::translateScript_trNoOp()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One"));
+
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP()").isUndefined());
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP('FooContext')").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TRANSLATE_NOOP('FooContext', 'Two')").toString(), QString::fromLatin1("Two"));
+}
+
+void tst_QJSEngine::translateScript_callQsTrFromCpp()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ // There is no context, but it shouldn't crash
+ QCOMPARE(engine.globalObject().property("qsTr").call(
+ QScriptValue(), QScriptValueList() << "One").toString(), QString::fromLatin1("One"));
+}
+
+void tst_QJSEngine::translateWithInvalidArgs_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedError");
+
+ QTest::newRow("qsTr()") << "qsTr()" << "Error: qsTr() requires at least one argument";
+ QTest::newRow("qsTr(123)") << "qsTr(123)" << "Error: qsTr(): first argument (text) must be a string";
+ QTest::newRow("qsTr('foo', 123)") << "qsTr('foo', 123)" << "Error: qsTr(): second argument (comment) must be a string";
+ QTest::newRow("qsTr('foo', 'bar', 'baz')") << "qsTr('foo', 'bar', 'baz')" << "Error: qsTr(): third argument (n) must be a number";
+ QTest::newRow("qsTr('foo', 'bar', true)") << "qsTr('foo', 'bar', true)" << "Error: qsTr(): third argument (n) must be a number";
+
+ QTest::newRow("qsTranslate()") << "qsTranslate()" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate('foo')") << "qsTranslate('foo')" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate(123, 'foo')") << "qsTranslate(123, 'foo')" << "Error: qsTranslate(): first argument (context) must be a string";
+ QTest::newRow("qsTranslate('foo', 123)") << "qsTranslate('foo', 123)" << "Error: qsTranslate(): second argument (text) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 123)") << "qsTranslate('foo', 'bar', 123)" << "Error: qsTranslate(): third argument (comment) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 123)") << "qsTranslate('foo', 'bar', 'baz', 123)" << "Error: qsTranslate(): fourth argument (encoding) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')") << "qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')" << "Error: qsTranslate(): fifth argument (n) must be a number";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 123)") << "qsTranslate('foo', 'bar', 'baz', 'zab', 123)" << "Error: qsTranslate(): invalid encoding 'zab'";
+
+ QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument";
+ QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string";
+ QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number";
+}
+
+void tst_QJSEngine::translateWithInvalidArgs()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedError);
+ QScriptEngine engine;
+ engine.installTranslatorFunctions();
+ QScriptValue result = engine.evaluate(expression);
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), expectedError);
+}
+
+void tst_QJSEngine::translationContext_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("translatable.js") << "translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js") << "/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/translatable.js") << "/foo/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/bar/translatable.js") << "/foo/bar/translatable.js" << "One" << "En";
+ QTest::newRow("./translatable.js") << "./translatable.js" << "One" << "En";
+ QTest::newRow("../translatable.js") << "../translatable.js" << "One" << "En";
+ QTest::newRow("foo/translatable.js") << "foo/translatable.js" << "One" << "En";
+ QTest::newRow("file:///home/qt/translatable.js") << "file:///home/qt/translatable.js" << "One" << "En";
+ QTest::newRow(":/resources/translatable.js") << ":/resources/translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js.foo") << "/translatable.js.foo" << "One" << "En";
+ QTest::newRow("/translatable.txt") << "/translatable.txt" << "One" << "En";
+ QTest::newRow("translatable") << "translatable" << "One" << "En";
+ QTest::newRow("foo/translatable") << "foo/translatable" << "One" << "En";
+
+ QTest::newRow("native separators")
+ << (QDir::toNativeSeparators(QDir::currentPath()) + QDir::separator() + "translatable.js")
+ << "One" << "En";
+
+ QTest::newRow("translatable.js/") << "translatable.js/" << "One" << "One";
+ QTest::newRow("nosuchscript.js") << "" << "One" << "One";
+ QTest::newRow("(empty)") << "" << "One" << "One";
+}
+
+void tst_QJSEngine::translationContext()
+{
+ TranslationScope tranScope(":/translations/translatable_la");
+
+ QScriptEngine engine;
+ engine.installTranslatorFunctions();
+
+ QFETCH(QString, path);
+ QFETCH(QString, text);
+ QFETCH(QString, expectedTranslation);
+ QScriptValue ret = engine.evaluate(QString::fromLatin1("qsTr('%0')").arg(text), path);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateScriptIdBased()
+{
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("idtranslatable.js");
+
+ QHash<QString, QString> expectedTranslations;
+ expectedTranslations["qtn_foo_bar"] = "First string";
+ expectedTranslations["qtn_needle"] = "Second string";
+ expectedTranslations["qtn_haystack"] = "Third string";
+ expectedTranslations["qtn_bar_baz"] = "Fourth string";
+
+ QHash<QString, QString>::const_iterator it;
+ for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) {
+ for (int x = 0; x < 2; ++x) {
+ QString fn;
+ if (x)
+ fn = fileName;
+ // Top-level
+ QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ // From function
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ }
+ }
+
+ // Plural form
+ QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(),
+ QString::fromLatin1("10 fooish bar(s) found"));
+ QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(),
+ QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural
+}
+
+// How to add a new test row:
+// - Find a nice list of Unicode characters to choose from
+// - Write source string/context/comment in .js using Unicode escape sequences (\uABCD)
+// - Update corresponding .ts file (e.g. lupdate foo.js -ts foo.ts -codecfortr UTF-8)
+// - Enter translation in Linguist
+// - Update corresponding .qm file (e.g. lrelease foo.ts)
+// - Evaluate script that performs translation; make sure the correct result is returned
+// (e.g. by setting the resulting string as the text of a QLabel and visually verifying
+// that it looks the same as what you entered in Linguist :-) )
+// - Generate the expectedTranslation column data using toUtf8().toHex()
+void tst_QJSEngine::translateScriptUnicode_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable-unicode.js");
+ QTest::newRow("qsTr('H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << fileName << QString::fromUtf8("\xcd\xbb\xcd\xbc\xcd\xbd");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << fileName << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+ QTest::newRow("qsTr('\\u0391\\u0392\\u0393')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('\\u0391\\u0392\\u0393')") << fileName << QString::fromUtf8("\xd3\x9c\xd2\xb4\xd1\xbc");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')") << fileName << QString::fromUtf8("\xd8\xae\xd8\xb3\xd8\xb3");
+ QTest::newRow("qsTr('H\\u2082O', 'not the same H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O', 'not the same H\\u2082O')") << fileName << QString::fromUtf8("\xd4\xb6\xd5\x8a\xd5\x92");
+ QTest::newRow("qsTr('H\\u2082O')")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << QString() << QString::fromUtf8("\x48\xe2\x82\x82\x4f");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << QString() << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+}
+
+void tst_QJSEngine::translateScriptUnicode()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1'')")
+ << QString::fromLatin1("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1')") << QString::fromUtf8("\xc6\xa7\xc6\xb0\xc6\x88\xc8\xbc\xc8\x9d\xc8\xbf\xc8\x99");
+ QTest::newRow("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')")
+ << QString::fromLatin1("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')") << QString::fromUtf8("\xc7\xa0\xc8\xa1\xc8\x8b\xc8\x85\xc8\x95");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)") << QString::fromUtf8("\x31\x30\x20\xc6\x92\xc6\xa1\xc7\x92\x28\xc8\x99\x29");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')") << QString::fromUtf8("\xc6\x91\xc6\xb0\xc7\xb9");
+ QTest::newRow("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')")
+ << QString::fromLatin1("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')") << QString::fromUtf8("\xc7\x8d\xc6\x80\xc6\xa8\xc6\x90\xc6\x9e\xc6\xab");
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateFromBuiltinCallback()
+{
+ QScriptEngine eng;
+ eng.installTranslatorFunctions();
+
+ // Callback has no translation context.
+ eng.evaluate("function foo() { qsTr('foo'); }");
+
+ // Stack at translation time will be:
+ // qsTr, foo, forEach, global
+ // qsTr() needs to walk to the outer-most (global) frame before it finds
+ // a translation context, and this should not crash.
+ eng.evaluate("[10,20].forEach(foo)", "script.js");
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptValue::scope API
+void tst_QJSEngine::functionScopes()
+{
+ QScriptEngine eng;
+ {
+ // top-level functions have only the global object in their scope
+ QScriptValue fun = eng.evaluate("(function() {})");
+ QVERIFY(fun.isFunction());
+ QEXPECT_FAIL("", "QScriptValue::scope() is internal, not implemented", Abort);
+ QVERIFY(fun.scope().isObject());
+ QVERIFY(fun.scope().strictlyEquals(eng.globalObject()));
+ QVERIFY(!eng.globalObject().scope().isValid());
+ }
+ {
+ QScriptValue fun = eng.globalObject().property("Object");
+ QVERIFY(fun.isFunction());
+ // native built-in functions don't have scope
+ QVERIFY(!fun.scope().isValid());
+ }
+ {
+ // closure
+ QScriptValue fun = eng.evaluate("(function(arg) { var foo = arg; return function() { return foo; }; })(123)");
+ QVERIFY(fun.isFunction());
+ {
+ QScriptValue ret = fun.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ QScriptValue scope = fun.scope();
+ QVERIFY(scope.isObject());
+ {
+ QScriptValue ret = scope.property("foo");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable);
+ }
+ {
+ QScriptValue ret = scope.property("arg");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QCOMPARE(scope.propertyFlags("arg"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ }
+
+ scope.setProperty("foo", 456);
+ {
+ QScriptValue ret = fun.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ }
+
+ scope = scope.scope();
+ QVERIFY(scope.isObject());
+ QVERIFY(scope.strictlyEquals(eng.globalObject()));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext API
+static QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *)
+{
+ QScriptValue outerAct = ctx->callee().scope();
+ double count = outerAct.property("count").toNumber();
+ outerAct.setProperty("count", count+1);
+ return count;
+}
+
+static QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("count", ctx->argument(0).toInt32());
+ QScriptValue result = eng->newFunction(counter_inner);
+ result.setScope(act);
+ return result;
+}
+
+static QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("count", ctx->argument(0).toInt32());
+ return eng->evaluate("(function() { return count++; })");
+}
+
+void tst_QJSEngine::nativeFunctionScopes()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(counter);
+ QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
+ QVERIFY(cnt.isFunction());
+ {
+ QScriptValue ret = cnt.call();
+ QVERIFY(ret.isNumber());
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+ {
+ QScriptValue fun = eng.newFunction(counter_hybrid);
+ QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
+ QVERIFY(cnt.isFunction());
+ {
+ QScriptValue ret = cnt.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+
+ //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain
+ {
+ QScriptEngine eng;
+ eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n"
+ "var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptProgram API
+static QScriptValue createProgram(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QString code = ctx->argument(0).toString();
+ QScriptProgram result(code);
+ return qScriptValueFromValue(eng, result);
+}
+
+void tst_QJSEngine::evaluateProgram()
+{
+ QScriptEngine eng;
+
+ {
+ QString code("1 + 2");
+ QString fileName("hello.js");
+ int lineNumber(123);
+ QScriptProgram program(code, fileName, lineNumber);
+ QVERIFY(!program.isNull());
+ QCOMPARE(program.sourceCode(), code);
+ QCOMPARE(program.fileName(), fileName);
+ QCOMPARE(program.firstLineNumber(), lineNumber);
+
+ QScriptValue expected = eng.evaluate(code);
+ for (int x = 0; x < 10; ++x) {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.equals(expected));
+ }
+
+ // operator=
+ QScriptProgram sameProgram = program;
+ QVERIFY(sameProgram == program);
+ QVERIFY(eng.evaluate(sameProgram).equals(expected));
+
+ // copy constructor
+ QScriptProgram sameProgram2(program);
+ QVERIFY(sameProgram2 == program);
+ QVERIFY(eng.evaluate(sameProgram2).equals(expected));
+
+ QScriptProgram differentProgram("2 + 3");
+ QVERIFY(differentProgram != program);
+ QVERIFY(!eng.evaluate(differentProgram).equals(expected));
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_customScope()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program("a");
+ QVERIFY(!program.isNull());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: a is not defined"));
+ }
+
+ QScriptValue obj = eng.newObject();
+ obj.setProperty("a", 123);
+ QScriptContext *ctx = eng.currentContext();
+ ctx->pushScope(obj);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.equals(obj.property("a")));
+ }
+
+ obj.setProperty("a", QScriptValue());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ }
+
+ QScriptValue obj2 = eng.newObject();
+ obj2.setProperty("a", 456);
+ ctx->pushScope(obj2);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.equals(obj2.property("a")));
+ }
+
+ ctx->popScope();
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_closure()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })");
+ QVERIFY(!program.isNull());
+ QScriptValue createCounter = eng.evaluate(program);
+ QVERIFY(createCounter.isFunction());
+ QScriptValue counter = createCounter.call();
+ QVERIFY(counter.isFunction());
+ {
+ QScriptValue ret = counter.call();
+ QVERIFY(ret.isNumber());
+ }
+ QScriptValue counter2 = createCounter.call();
+ QVERIFY(counter2.isFunction());
+ QVERIFY(!counter2.equals(counter));
+ {
+ QScriptValue ret = counter2.call();
+ QVERIFY(ret.isNumber());
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_executeLater()
+{
+ QScriptEngine eng;
+ // Program created in a function call, then executed later
+ {
+ QScriptValue fun = eng.newFunction(createProgram);
+ QScriptProgram program = qscriptvalue_cast<QScriptProgram>(
+ fun.call(QScriptValue(), QScriptValueList() << "a + 1"));
+ QVERIFY(!program.isNull());
+ eng.globalObject().setProperty("a", QScriptValue());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: a is not defined"));
+ }
+ eng.globalObject().setProperty("a", 122);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_multipleEngines()
+{
+ QScriptEngine eng;
+ {
+ QString code("1 + 2");
+ QScriptProgram program(code);
+ QVERIFY(!program.isNull());
+ double expected = eng.evaluate(program).toNumber();
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine eng2;
+ for (int y = 0; y < 2; ++y) {
+ double ret = eng2.evaluate(program).toNumber();
+ QCOMPARE(ret, expected);
+ }
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_empty()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program;
+ QVERIFY(program.isNull());
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isValid());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No ScriptOwnership API
+void tst_QJSEngine::collectGarbageAfterConnect()
+{
+ // QTBUG-6366
+ QScriptEngine engine;
+ QPointer<QWidget> widget = new QWidget;
+ engine.globalObject().setProperty(
+ "widget", engine.newQObject(widget, QScriptEngine::ScriptOwnership));
+ QVERIFY(engine.evaluate("widget.customContextMenuRequested.connect(\n"
+ " function() { print('hello'); }\n"
+ ");")
+ .isUndefined());
+ QVERIFY(widget != 0);
+ engine.evaluate("widget = null;");
+ // The connection should not keep the widget alive.
+ collectGarbage_helper(engine);
+ QVERIFY(widget == 0);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext API
+void tst_QJSEngine::collectGarbageAfterNativeArguments()
+{
+ // QTBUG-17788
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QScriptValue arguments = ctx->argumentsObject();
+ // Shouldn't crash when marking the arguments object.
+ collectGarbage_helper(eng);
+}
+
+static QScriptValue constructQObjectFromThisObject(QScriptContext *ctx, QScriptEngine *eng)
+{
+ if (!ctx->isCalledAsConstructor()) {
+ qWarning("%s: ctx->isCalledAsConstructor() returned false", Q_FUNC_INFO);
+ return QScriptValue();
+ }
+ return eng->newQObject(ctx->thisObject(), new QObject, QScriptEngine::ScriptOwnership);
+}
+
+void tst_QJSEngine::promoteThisObjectToQObjectInConstructor()
+{
+ QScriptEngine engine;
+ QScriptValue ctor = engine.newFunction(constructQObjectFromThisObject);
+ engine.globalObject().setProperty("Ctor", ctor);
+ QScriptValue object = engine.evaluate("new Ctor");
+ QVERIFY(!object.isError());
+ QVERIFY(object.isQObject());
+ QVERIFY(object.toQObject() != 0);
+ QVERIFY(object.property("objectName").isString());
+ QVERIFY(object.property("deleteLater").isFunction());
+}
+#endif
+
+static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
+
+void tst_QJSEngine::qRegExpInport_data()
+{
+ QTest::addColumn<QRegExp>("rx");
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("matched");
+
+ QTest::newRow("normal") << QRegExp("(test|foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("normal2") << QRegExp("(Test|Foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive)") << QRegExp("(test|foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive2)") << QRegExp("(Test|Foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
+ QTest::newRow("b(a*)(b*)") << QRegExp("b(a*)(b*)", Qt::CaseInsensitive) << "aaabbBbaAabaAaababaaabbaaab";
+ QTest::newRow("greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp2) << "aaaabaaba";
+ // this one will fail because we do not support the QRegExp::RegExp in JSC
+ //QTest::newRow("not_greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp) << "aaaabaaba";
+ QTest::newRow("willcard") << QRegExp("*.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "file.txt";
+ QTest::newRow("willcard 2") << QRegExp("a?b.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "ab.txt abb.rtc acb.txt";
+ QTest::newRow("slash") << QRegExp("g/.*/s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string/string/string";
+ QTest::newRow("slash2") << QRegExp("g / .* / s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string / string / string";
+ QTest::newRow("fixed") << QRegExp("a*aa.a(ba)*a\\ba", Qt::CaseInsensitive, QRegExp::FixedString) << "aa*aa.a(ba)*a\\ba";
+ QTest::newRow("fixed insensitive") << QRegExp("A*A", Qt::CaseInsensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
+ QTest::newRow("fixed sensitive") << QRegExp("A*A", Qt::CaseSensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
+ QTest::newRow("html") << QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2) << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("html minimal") << minimal(QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2)) << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("aaa") << QRegExp("a{2,5}") << "aAaAaaaaaAa";
+ QTest::newRow("aaa minimal") << minimal(QRegExp("a{2,5}")) << "aAaAaaaaaAa";
+ QTest::newRow("minimal") << minimal(QRegExp(".*\\} [*8]")) << "}?} ?} *";
+ QTest::newRow(".? minimal") << minimal(QRegExp(".?")) << ".?";
+ QTest::newRow(".+ minimal") << minimal(QRegExp(".+")) << ".+";
+ QTest::newRow("[.?] minimal") << minimal(QRegExp("[.?]")) << ".?";
+ QTest::newRow("[.+] minimal") << minimal(QRegExp("[.+]")) << ".+";
+}
+
+void tst_QJSEngine::qRegExpInport()
+{
+ QFETCH(QRegExp, rx);
+ QFETCH(QString, string);
+
+ QJSEngine eng;
+ QJSValue rexp;
+ rexp = eng.newRegExp(rx);
+
+ QCOMPARE(rexp.isValid(), true);
+ QCOMPARE(rexp.isRegExp(), true);
+ QVERIFY(rexp.isFunction());
+
+ QJSValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
+ QJSValue result = func.call(QJSValue(), QJSValueList() << string << rexp);
+
+ rx.indexIn(string);
+ for (int i = 0; i <= rx.captureCount(); i++) {
+ QCOMPARE(result.property(i).toString(), rx.cap(i));
+ }
+}
+
+// QScriptValue::toDateTime() returns a local time, whereas JS dates
+// are always stored as UTC. QtScript must respect the current time
+// zone, and correctly adjust for daylight saving time that may be in
+// effect at a given date (QTBUG-9770).
+void tst_QJSEngine::dateRoundtripJSQtJS()
+{
+ uint secs = QDateTime(QDate(2009, 1, 1)).toUTC().toTime_t();
+ QJSEngine eng;
+ for (int i = 0; i < 8000; ++i) {
+ QJSValue jsDate = eng.evaluate(QString::fromLatin1("new Date(%0)").arg(secs * 1000.0));
+ QDateTime qtDate = jsDate.toDateTime();
+ QJSValue jsDate2 = eng.newDate(qtDate);
+ if (jsDate2.toNumber() != jsDate.toNumber())
+ QFAIL(qPrintable(jsDate.toString()));
+ secs += 2*60*60;
+ }
+}
+
+void tst_QJSEngine::dateRoundtripQtJSQt()
+{
+ QDateTime qtDate = QDateTime(QDate(2009, 1, 1));
+ QJSEngine eng;
+ for (int i = 0; i < 8000; ++i) {
+ QJSValue jsDate = eng.newDate(qtDate);
+ QDateTime qtDate2 = jsDate.toDateTime();
+ if (qtDate2 != qtDate)
+ QFAIL(qPrintable(qtDate.toString()));
+ qtDate = qtDate.addSecs(2*60*60);
+ }
+}
+
+void tst_QJSEngine::dateConversionJSQt()
+{
+ uint secs = QDateTime(QDate(2009, 1, 1)).toUTC().toTime_t();
+ QJSEngine eng;
+ for (int i = 0; i < 8000; ++i) {
+ QJSValue jsDate = eng.evaluate(QString::fromLatin1("new Date(%0)").arg(secs * 1000.0));
+ QDateTime qtDate = jsDate.toDateTime();
+ QString qtUTCDateStr = qtDate.toUTC().toString(Qt::ISODate);
+ QString jsUTCDateStr = jsDate.property("toISOString").call(jsDate).toString();
+ jsUTCDateStr.remove(jsUTCDateStr.length() - 5, 4); // get rid of milliseconds (".000")
+ if (qtUTCDateStr != jsUTCDateStr)
+ QFAIL(qPrintable(jsDate.toString()));
+ secs += 2*60*60;
+ }
+}
+
+void tst_QJSEngine::dateConversionQtJS()
+{
+ QDateTime qtDate = QDateTime(QDate(2009, 1, 1));
+ QJSEngine eng;
+ for (int i = 0; i < 8000; ++i) {
+ QJSValue jsDate = eng.newDate(qtDate);
+ QString jsUTCDateStr = jsDate.property("toISOString").call(jsDate).toString();
+ jsUTCDateStr.remove(jsUTCDateStr.length() - 5, 4); // get rid of milliseconds (".000")
+ QString qtUTCDateStr = qtDate.toUTC().toString(Qt::ISODate);
+ if (jsUTCDateStr != qtUTCDateStr)
+ QFAIL(qPrintable(qtDate.toString()));
+ qtDate = qtDate.addSecs(2*60*60);
+ }
+}
+
+#if 0 // ###FIXME: No QScriptContext API
+static QScriptValue createAnotherEngine(QScriptContext *, QScriptEngine *)
+{
+ QScriptEngine eng;
+ eng.evaluate("function foo(x, y) { return x + y; }" );
+ eng.evaluate("hello = 5; world = 6" );
+ return eng.evaluate("foo(hello,world)").toInt32();
+}
+
+
+void tst_QJSEngine::reentrency()
+{
+ QScriptEngine eng;
+ eng.globalObject().setProperty("foo", eng.newFunction(createAnotherEngine));
+ eng.evaluate("function bar() { return foo(); } hello = 9; function getHello() { return hello; }");
+ QCOMPARE(eng.evaluate("foo() + getHello() + foo()").toInt32(), 5+6 + 9 + 5+6);
+ QCOMPARE(eng.evaluate("foo").call().toInt32(), 5+6);
+ QCOMPARE(eng.evaluate("hello").toInt32(), 9);
+ QCOMPARE(eng.evaluate("foo() + hello").toInt32(), 5+6+9);
+}
+#endif
+
+#if 0 // ###FIXME: No QSCriptDeclarativeClass API
+void tst_QJSEngine::newFixedStaticScopeObject()
+{
+ // "Static scope objects" is an optimization we do for QML.
+ // It enables the creation of JS objects that can guarantee to the
+ // compiler that no properties will be added or removed. This enables
+ // the compiler to generate a very simple (fast) property access, as
+ // opposed to a full virtual lookup. Due to the inherent use of scope
+ // chains in QML, this can make a huge difference (10x improvement for
+ // benchmark in QTBUG-8576).
+ // Ideally we would not need a special object type for this, and the
+ // VM would dynamically optimize it to be fast...
+ // See also QScriptEngine benchmark.
+
+ QScriptEngine eng;
+ static const int propertyCount = 4;
+ QString names[] = { "foo", "bar", "baz", "Math" };
+ QScriptValue values[] = { 123, "ciao", true, false };
+ QScriptValue::PropertyFlags flags[] = { QScriptValue::Undeletable,
+ QScriptValue::ReadOnly | QScriptValue::Undeletable,
+ QScriptValue::SkipInEnumeration | QScriptValue::Undeletable,
+ QScriptValue::Undeletable };
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(&eng, propertyCount, names, values, flags);
+
+ // Query property.
+ for (int i = 0; i < propertyCount; ++i) {
+ for (int x = 0; x < 2; ++x) {
+ if (x) {
+ // Properties can't be deleted.
+ scope.setProperty(names[i], QScriptValue());
+ }
+ QVERIFY(scope.property(names[i]).equals(values[i]));
+ QCOMPARE(scope.propertyFlags(names[i]), flags[i]);
+ }
+ }
+
+ // Property that doesn't exist.
+ QVERIFY(!scope.property("noSuchProperty").isValid());
+ QCOMPARE(scope.propertyFlags("noSuchProperty"), QScriptValue::PropertyFlags());
+
+ // Write to writable property.
+ {
+ QScriptValue oldValue = scope.property("foo");
+ QVERIFY(oldValue.isNumber());
+ QScriptValue newValue = oldValue.toNumber() * 2;
+ scope.setProperty("foo", newValue);
+ QVERIFY(scope.property("foo").equals(newValue));
+ scope.setProperty("foo", oldValue);
+ QVERIFY(scope.property("foo").equals(oldValue));
+ }
+
+ // Write to read-only property.
+ scope.setProperty("bar", 456);
+ QVERIFY(scope.property("bar").equals("ciao"));
+
+ // Iterate.
+ {
+ QScriptValueIterator it(scope);
+ QSet<QString> iteratedNames;
+ while (it.hasNext()) {
+ it.next();
+ iteratedNames.insert(it.name());
+ }
+ for (int i = 0; i < propertyCount; ++i)
+ QVERIFY(iteratedNames.contains(names[i]));
+ }
+
+ // Push it on the scope chain of a new context.
+ QScriptContext *ctx = eng.pushContext();
+ ctx->pushScope(scope);
+ QCOMPARE(ctx->scopeChain().size(), 3); // Global Object, native activation, custom scope
+ QEXPECT_FAIL("", "activationObject has not been implemented yet", Continue);
+ QVERIFY(ctx->activationObject().equals(scope));
+
+ // Read property from JS.
+ for (int i = 0; i < propertyCount; ++i) {
+ for (int x = 0; x < 2; ++x) {
+ if (x) {
+ // Property can't be deleted from JS.
+ QScriptValue ret = eng.evaluate(QString::fromLatin1("delete %0").arg(names[i]));
+ QVERIFY(ret.equals(false));
+ }
+ QVERIFY(eng.evaluate(names[i]).equals(values[i]));
+ }
+ }
+
+ // Property that doesn't exist.
+ QVERIFY(eng.evaluate("noSuchProperty").equals("ReferenceError: noSuchProperty is not defined"));
+
+ // Write property from JS.
+ {
+ QScriptValue oldValue = eng.evaluate("foo");
+ QVERIFY(oldValue.isNumber());
+ QScriptValue newValue = oldValue.toNumber() * 2;
+ QVERIFY(eng.evaluate("foo = foo * 2; foo").equals(newValue));
+ scope.setProperty("foo", oldValue);
+ QVERIFY(eng.evaluate("foo").equals(oldValue));
+ }
+
+ // Write to read-only property.
+ QVERIFY(eng.evaluate("bar = 456; bar").equals("ciao"));
+
+ // Create a closure and return properties from there.
+ {
+ QScriptValue props = eng.evaluate("(function() { var baz = 'shadow'; return [foo, bar, baz, Math, Array]; })()");
+ QVERIFY(props.isArray());
+ // "foo" and "bar" come from scope object.
+ QVERIFY(props.property(0).equals(scope.property("foo")));
+ QVERIFY(props.property(1).equals(scope.property("bar")));
+ // "baz" shadows property in scope object.
+ QVERIFY(props.property(2).equals("shadow"));
+ // "Math" comes from scope object, and shadows Global Object's "Math".
+ QVERIFY(props.property(3).equals(scope.property("Math")));
+ QVERIFY(!props.property(3).equals(eng.globalObject().property("Math")));
+ // "Array" comes from Global Object.
+ QVERIFY(props.property(4).equals(eng.globalObject().property("Array")));
+ }
+
+ // As with normal JS, assigning to an undefined variable will create
+ // the property on the Global Object, not the inner scope.
+ QVERIFY(!eng.globalObject().property("newProperty").isValid());
+ QVERIFY(eng.evaluate("(function() { newProperty = 789; })()").isUndefined());
+ QVERIFY(!scope.property("newProperty").isValid());
+ QVERIFY(eng.globalObject().property("newProperty").isNumber());
+
+ // Nested static scope.
+ {
+ static const int propertyCount2 = 2;
+ QString names2[] = { "foo", "hum" };
+ QScriptValue values2[] = { 321, "hello" };
+ QScriptValue::PropertyFlags flags2[] = { QScriptValue::Undeletable,
+ QScriptValue::ReadOnly | QScriptValue::Undeletable };
+ QScriptValue scope2 = QScriptDeclarativeClass::newStaticScopeObject(&eng, propertyCount2, names2, values2, flags2);
+ ctx->pushScope(scope2);
+
+ // "foo" shadows scope.foo.
+ QVERIFY(eng.evaluate("foo").equals(scope2.property("foo")));
+ QVERIFY(!eng.evaluate("foo").equals(scope.property("foo")));
+ // "hum" comes from scope2.
+ QVERIFY(eng.evaluate("hum").equals(scope2.property("hum")));
+ // "Array" comes from Global Object.
+ QVERIFY(eng.evaluate("Array").equals(eng.globalObject().property("Array")));
+
+ ctx->popScope();
+ }
+
+ QScriptValue fun = eng.evaluate("(function() { return foo; })");
+ QVERIFY(fun.isFunction());
+ eng.popContext();
+ // Function's scope chain persists after popContext().
+ QVERIFY(fun.call().equals(scope.property("foo")));
+}
+
+void tst_QJSEngine::newGrowingStaticScopeObject()
+{
+ // The main use case for a growing static scope object is to set it as
+ // the activation object of a QScriptContext, so that all JS variable
+ // declarations end up in that object. It needs to be "growable" since
+ // we don't know in advance how many variables a script will declare.
+
+ QScriptEngine eng;
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(&eng);
+
+ // Initially empty.
+ QVERIFY(!QScriptValueIterator(scope).hasNext());
+ QVERIFY(!scope.property("foo").isValid());
+
+ // Add a static property.
+ scope.setProperty("foo", 123);
+ QVERIFY(scope.property("foo").equals(123));
+ QEXPECT_FAIL("", "FIXME: newStaticScopeObject not properly implemented", Abort);
+ QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable);
+
+ // Modify existing property.
+ scope.setProperty("foo", 456);
+ QVERIFY(scope.property("foo").equals(456));
+
+ // Add a read-only property.
+ scope.setProperty("bar", "ciao", QScriptValue::ReadOnly);
+ QVERIFY(scope.property("bar").equals("ciao"));
+ QCOMPARE(scope.propertyFlags("bar"), QScriptValue::ReadOnly | QScriptValue::Undeletable);
+
+ // Attempt to modify read-only property.
+ scope.setProperty("bar", "hello");
+ QVERIFY(scope.property("bar").equals("ciao"));
+
+ // Properties can't be deleted.
+ scope.setProperty("foo", QScriptValue());
+ QVERIFY(scope.property("foo").equals(456));
+ scope.setProperty("bar", QScriptValue());
+ QVERIFY(scope.property("bar").equals("ciao"));
+
+ // Iterate.
+ {
+ QScriptValueIterator it(scope);
+ QSet<QString> iteratedNames;
+ while (it.hasNext()) {
+ it.next();
+ iteratedNames.insert(it.name());
+ }
+ QCOMPARE(iteratedNames.size(), 2);
+ QVERIFY(iteratedNames.contains("foo"));
+ QVERIFY(iteratedNames.contains("bar"));
+ }
+
+ // Push it on the scope chain of a new context.
+ QScriptContext *ctx = eng.pushContext();
+ ctx->pushScope(scope);
+ QCOMPARE(ctx->scopeChain().size(), 3); // Global Object, native activation, custom scope
+ QVERIFY(ctx->activationObject().equals(scope));
+
+ // Read property from JS.
+ QVERIFY(eng.evaluate("foo").equals(scope.property("foo")));
+ QVERIFY(eng.evaluate("bar").equals(scope.property("bar")));
+
+ // Write property from JS.
+ {
+ QScriptValue oldValue = eng.evaluate("foo");
+ QVERIFY(oldValue.isNumber());
+ QScriptValue newValue = oldValue.toNumber() * 2;
+ QVERIFY(eng.evaluate("foo = foo * 2; foo").equals(newValue));
+ scope.setProperty("foo", oldValue);
+ QVERIFY(eng.evaluate("foo").equals(oldValue));
+ }
+
+ // Write to read-only property.
+ QVERIFY(eng.evaluate("bar = 456; bar").equals("ciao"));
+
+ // Shadow property.
+ QVERIFY(eng.evaluate("Math").equals(eng.globalObject().property("Math")));
+ scope.setProperty("Math", "fake Math");
+ QVERIFY(eng.evaluate("Math").equals(scope.property("Math")));
+
+ // Variable declarations will create properties on the scope.
+ eng.evaluate("var baz = 456");
+ QVERIFY(scope.property("baz").equals(456));
+
+ // Function declarations will create properties on the scope.
+ eng.evaluate("function fun() { return baz; }");
+ QVERIFY(scope.property("fun").isFunction());
+ QVERIFY(scope.property("fun").call().equals(scope.property("baz")));
+
+ // Demonstrate the limitation of a growable static scope: Once a function that
+ // uses the scope has been compiled, it won't pick up properties that are added
+ // to the scope later.
+ {
+ QScriptValue fun = eng.evaluate("(function() { return futureProperty; })");
+ QVERIFY(fun.isFunction());
+ QVERIFY(fun.call().toString().contains(QString::fromLatin1("ReferenceError")));
+ scope.setProperty("futureProperty", "added after the function was compiled");
+ // If scope were dynamic, this would return the new property.
+ QVERIFY(fun.call().toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+
+ eng.popContext();
+}
+#endif
+
+#if 0 // ###FIXME: No QScript MetaObject API
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(QStandardItemModel, QObject*)
+QT_END_NAMESPACE
+
+void tst_QJSEngine::scriptValueFromQMetaObject()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue meta = eng.scriptValueFromQMetaObject<QScriptEngine>();
+ QVERIFY(meta.isQMetaObject());
+ QCOMPARE(meta.toQMetaObject(), &QScriptEngine::staticMetaObject);
+ // Because of missing Q_SCRIPT_DECLARE_QMETAOBJECT() for QScriptEngine.
+ QEXPECT_FAIL("", "FIXME: because construct never returns invalid values", Continue);
+ QVERIFY(!meta.construct().isValid());
+ }
+ {
+ QScriptValue meta = eng.scriptValueFromQMetaObject<QStandardItemModel>();
+ QVERIFY(meta.isQMetaObject());
+ QCOMPARE(meta.toQMetaObject(), &QStandardItemModel::staticMetaObject);
+ QScriptValue obj = meta.construct(QScriptValueList() << eng.newQObject(&eng));
+ QVERIFY(obj.isQObject());
+ QStandardItemModel *model = qobject_cast<QStandardItemModel*>(obj.toQObject());
+ QVERIFY(model != 0);
+ QCOMPARE(model->parent(), (QObject*)&eng);
+ }
+}
+#endif
+
+QTEST_MAIN(tst_QJSEngine)
+
+#include "tst_qjsengine.moc"
+
diff --git a/tests/auto/declarative/qjsvalue/qjsvalue.pro b/tests/auto/declarative/qjsvalue/qjsvalue.pro
new file mode 100644
index 0000000000..182196a3ed
--- /dev/null
+++ b/tests/auto/declarative/qjsvalue/qjsvalue.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT += declarative
+SOURCES += tst_qjsvalue.cpp
+HEADERS += tst_qjsvalue.h
+
+win32-msvc* {
+ # With -O2, MSVC takes up to 24 minutes to compile this test!
+ QMAKE_CXXFLAGS_RELEASE -= -O1 -O2
+ QMAKE_CXXFLAGS_RELEASE += -Od
+}
diff --git a/tests/auto/declarative/qjsvalue/tst_qjsvalue.cpp b/tests/auto/declarative/qjsvalue/tst_qjsvalue.cpp
new file mode 100644
index 0000000000..9f9e066003
--- /dev/null
+++ b/tests/auto/declarative/qjsvalue/tst_qjsvalue.cpp
@@ -0,0 +1,4109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tst_qjsvalue.h"
+#include <QtGui/QPushButton>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+QT_BEGIN_NAMESPACE
+extern bool qt_script_isJITEnabled();
+QT_END_NAMESPACE
+
+tst_QJSValue::tst_QJSValue()
+ : engine(0)
+{
+}
+
+tst_QJSValue::~tst_QJSValue()
+{
+ if (engine)
+ delete engine;
+}
+
+void tst_QJSValue::ctor_invalid()
+{
+ QJSEngine eng;
+ {
+ QJSValue v;
+ QCOMPARE(v.isValid(), false);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+}
+
+void tst_QJSValue::ctor_undefinedWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, QJSValue::UndefinedValue);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isUndefined(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_nullWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, QJSValue::NullValue);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNull(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_boolWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, false);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isBoolean(), true);
+ QCOMPARE(v.isBool(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toBoolean(), false);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_intWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, int(1));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_int()
+{
+ {
+ QJSValue v(int(0x43211234));
+ QVERIFY(v.isNumber());
+ QCOMPARE(v.toInt32(), 0x43211234);
+ }
+ {
+ QJSValue v(int(1));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+}
+
+void tst_QJSValue::ctor_uintWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, uint(1));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_uint()
+{
+ {
+ QJSValue v(uint(0x43211234));
+ QVERIFY(v.isNumber());
+ QCOMPARE(v.toUInt32(), uint(0x43211234));
+ }
+ {
+ QJSValue v(uint(1));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+}
+
+void tst_QJSValue::ctor_floatWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, 1.0);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_float()
+{
+ {
+ QJSValue v(12345678910.5);
+ QVERIFY(v.isNumber());
+ QCOMPARE(v.toNumber(), 12345678910.5);
+ }
+ {
+ QJSValue v(1.0);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNumber(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toNumber(), 1.0);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+}
+
+void tst_QJSValue::ctor_stringWithEngine()
+{
+ QJSEngine eng;
+ {
+ QJSValue v(&eng, QLatin1String("ciao"));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isString(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toString(), QLatin1String("ciao"));
+ QCOMPARE(v.engine(), &eng);
+ }
+}
+
+void tst_QJSValue::ctor_string()
+{
+ {
+ QJSValue v(QString("ciao"));
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isString(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toString(), QLatin1String("ciao"));
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+ {
+ QJSValue v("ciao");
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isString(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toString(), QLatin1String("ciao"));
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+ }
+}
+
+void tst_QJSValue::ctor_copyAndAssignWithEngine()
+{
+ QJSEngine eng;
+ // copy constructor, operator=
+ {
+ QJSValue v(&eng, 1.0);
+ QJSValue v2(v);
+ QCOMPARE(v2.strictlyEquals(v), true);
+ QCOMPARE(v2.engine(), &eng);
+
+ QJSValue v3(v);
+ QCOMPARE(v3.strictlyEquals(v), true);
+ QCOMPARE(v3.strictlyEquals(v2), true);
+ QCOMPARE(v3.engine(), &eng);
+
+ QJSValue v4(&eng, 2.0);
+ QCOMPARE(v4.strictlyEquals(v), false);
+ v3 = v4;
+ QCOMPARE(v3.strictlyEquals(v), false);
+ QCOMPARE(v3.strictlyEquals(v4), true);
+
+ v2 = QJSValue();
+ QCOMPARE(v2.strictlyEquals(v), false);
+ QCOMPARE(v.toNumber(), 1.0);
+
+ QJSValue v5(v);
+ QCOMPARE(v5.strictlyEquals(v), true);
+ v = QJSValue();
+ QCOMPARE(v5.strictlyEquals(v), false);
+ QCOMPARE(v5.toNumber(), 1.0);
+ }
+}
+
+void tst_QJSValue::ctor_undefined()
+{
+ QJSValue v(QJSValue::UndefinedValue);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isUndefined(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+}
+
+void tst_QJSValue::ctor_null()
+{
+ QJSValue v(QJSValue::NullValue);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isNull(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+}
+
+void tst_QJSValue::ctor_bool()
+{
+ QJSValue v(false);
+ QCOMPARE(v.isValid(), true);
+ QCOMPARE(v.isBoolean(), true);
+ QCOMPARE(v.isBool(), true);
+ QCOMPARE(v.isObject(), false);
+ QCOMPARE(v.toBoolean(), false);
+ QCOMPARE(v.engine(), (QJSEngine *)0);
+}
+
+void tst_QJSValue::ctor_copyAndAssign()
+{
+ QJSValue v(1.0);
+ QJSValue v2(v);
+ QCOMPARE(v2.strictlyEquals(v), true);
+ QCOMPARE(v2.engine(), (QJSEngine *)0);
+
+ QJSValue v3(v);
+ QCOMPARE(v3.strictlyEquals(v), true);
+ QCOMPARE(v3.strictlyEquals(v2), true);
+ QCOMPARE(v3.engine(), (QJSEngine *)0);
+
+ QJSValue v4(2.0);
+ QCOMPARE(v4.strictlyEquals(v), false);
+ v3 = v4;
+ QCOMPARE(v3.strictlyEquals(v), false);
+ QCOMPARE(v3.strictlyEquals(v4), true);
+
+ v2 = QJSValue();
+ QCOMPARE(v2.strictlyEquals(v), false);
+ QCOMPARE(v.toNumber(), 1.0);
+
+ QJSValue v5(v);
+ QCOMPARE(v5.strictlyEquals(v), true);
+ v = QJSValue();
+ QCOMPARE(v5.strictlyEquals(v), false);
+ QCOMPARE(v5.toNumber(), 1.0);
+}
+
+void tst_QJSValue::ctor_nullEngine()
+{
+ // 0 engine
+ QVERIFY(QJSValue(0, QJSValue::UndefinedValue).isUndefined());
+ QVERIFY(QJSValue(0, QJSValue::NullValue).isNull());
+ QVERIFY(QJSValue(0, false).isBool());
+ QVERIFY(QJSValue(0, int(1)).isNumber());
+ QVERIFY(QJSValue(0, uint(1)).isNumber());
+ QVERIFY(QJSValue(0, 1.0).isNumber());
+ QVERIFY(QJSValue(0, QString("ciao")).isString());
+}
+
+#if 0 // FIXME: No c-style callbacks currently
+static QJSValue myFunction(QScriptContext *, QScriptEngine *eng)
+{
+ return eng->undefinedValue();
+}
+#endif
+
+void tst_QJSValue::toString()
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toString(), QString("undefined"));
+ QCOMPARE(qjsvalue_cast<QString>(undefined), QString());
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toString(), QString("null"));
+ QCOMPARE(qjsvalue_cast<QString>(null), QString());
+
+ {
+ QJSValue falskt = QJSValue(&eng, false);
+ QCOMPARE(falskt.toString(), QString("false"));
+ QCOMPARE(qjsvalue_cast<QString>(falskt), QString("false"));
+
+ QJSValue sant = QJSValue(&eng, true);
+ QCOMPARE(sant.toString(), QString("true"));
+ QCOMPARE(qjsvalue_cast<QString>(sant), QString("true"));
+ }
+ {
+ QJSValue number = QJSValue(&eng, 123);
+ QCOMPARE(number.toString(), QString("123"));
+ QCOMPARE(qjsvalue_cast<QString>(number), QString("123"));
+ }
+ {
+ QJSValue number = QJSValue(&eng, 6.37e-8);
+ QCOMPARE(number.toString(), QString("6.37e-8"));
+ }
+ {
+ QJSValue number = QJSValue(&eng, -6.37e-8);
+ QCOMPARE(number.toString(), QString("-6.37e-8"));
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ QCOMPARE(str.toString(), QString("ciao"));
+ QCOMPARE(qjsvalue_cast<QString>(str), QString("ciao"));
+ }
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.toString(), QString("[object Object]"));
+ QCOMPARE(qjsvalue_cast<QString>(object), QString("[object Object]"));
+
+ // FIXME: No c-style callbacks currently
+#if 0
+ QJSValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.toString().simplified(), QString("function () { [native code] }"));
+ QCOMPARE(qscriptvalue_cast<QString>(fun).simplified(), QString("function () { [native code] }"));
+#endif
+
+ // toString() that throws exception
+ {
+ QJSValue objectObject = eng.evaluate(
+ "(function(){"
+ " o = { };"
+ " o.toString = function() { throw new Error('toString'); };"
+ " return o;"
+ "})()");
+ QCOMPARE(objectObject.toString(), QLatin1String("Error: toString"));
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: toString"));
+ }
+ {
+ eng.clearExceptions();
+ QJSValue objectObject = eng.evaluate(
+ "(function(){"
+ " var f = function() {};"
+ " f.prototype = Date;"
+ " return new f;"
+ "})()");
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(objectObject.isObject());
+ QCOMPARE(objectObject.toString(), QString::fromLatin1("TypeError: Function.prototype.toString is not generic"));
+ QVERIFY(eng.hasUncaughtException());
+ eng.clearExceptions();
+ }
+
+ QJSValue inv = QJSValue();
+ QCOMPARE(inv.toString(), QString());
+
+ // V2 constructors
+ {
+ QJSValue falskt = QJSValue(false);
+ QCOMPARE(falskt.toString(), QString("false"));
+ QCOMPARE(qjsvalue_cast<QString>(falskt), QString("false"));
+
+ QJSValue sant = QJSValue(true);
+ QCOMPARE(sant.toString(), QString("true"));
+ QCOMPARE(qjsvalue_cast<QString>(sant), QString("true"));
+
+ QJSValue number = QJSValue(123);
+ QCOMPARE(number.toString(), QString("123"));
+ QCOMPARE(qjsvalue_cast<QString>(number), QString("123"));
+
+ QJSValue number2(int(0x43211234));
+ QCOMPARE(number2.toString(), QString("1126240820"));
+
+ QJSValue str = QJSValue(QString("ciao"));
+ QCOMPARE(str.toString(), QString("ciao"));
+ QCOMPARE(qjsvalue_cast<QString>(str), QString("ciao"));
+ }
+
+ // variant should use internal valueOf(), then fall back to QVariant::toString(),
+ // then fall back to "QVariant(typename)"
+ QJSValue variant = eng.newVariant(123);
+ QVERIFY(variant.isVariant());
+ QCOMPARE(variant.toString(), QString::fromLatin1("123"));
+ variant = eng.newVariant(QByteArray("hello"));
+ QVERIFY(variant.isVariant());
+ QCOMPARE(variant.toString(), QString::fromLatin1("hello"));
+ variant = eng.newVariant(QVariant(QPoint(10, 20)));
+ QVERIFY(variant.isVariant());
+ QCOMPARE(variant.toString(), QString::fromLatin1("QVariant(QPoint)"));
+ variant = eng.newVariant(QUrl());
+ QVERIFY(variant.toString().isEmpty());
+}
+
+void tst_QJSValue::toNumber()
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(qIsNaN(undefined.toNumber()), true);
+ QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(undefined)), true);
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toNumber(), 0.0);
+ QCOMPARE(qjsvalue_cast<qreal>(null), 0.0);
+
+ {
+ QJSValue falskt = QJSValue(&eng, false);
+ QCOMPARE(falskt.toNumber(), 0.0);
+ QCOMPARE(qjsvalue_cast<qreal>(falskt), 0.0);
+
+ QJSValue sant = QJSValue(&eng, true);
+ QCOMPARE(sant.toNumber(), 1.0);
+ QCOMPARE(qjsvalue_cast<qreal>(sant), 1.0);
+
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toNumber(), 123.0);
+ QCOMPARE(qjsvalue_cast<qreal>(number), 123.0);
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ QCOMPARE(qIsNaN(str.toNumber()), true);
+ QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(str)), true);
+
+ QJSValue str2 = QJSValue(&eng, QString("123"));
+ QCOMPARE(str2.toNumber(), 123.0);
+ QCOMPARE(qjsvalue_cast<qreal>(str2), 123.0);
+ }
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(qIsNaN(object.toNumber()), true);
+ QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(object)), true);
+
+ // FIXME: No c-style callbacks currently
+#if 0
+ QJSValue fun = eng.newFunction(myFunction);
+ QCOMPARE(qIsNaN(fun.toNumber()), true);
+ QCOMPARE(qIsNaN(qscriptvalue_cast<qreal>(fun)), true);
+#endif
+
+ QJSValue inv = QJSValue();
+ QCOMPARE(inv.toNumber(), 0.0);
+ QCOMPARE(qjsvalue_cast<qreal>(inv), 0.0);
+
+ // V2 constructors
+ {
+ QJSValue falskt = QJSValue(false);
+ QCOMPARE(falskt.toNumber(), 0.0);
+ QCOMPARE(qjsvalue_cast<qreal>(falskt), 0.0);
+
+ QJSValue sant = QJSValue(true);
+ QCOMPARE(sant.toNumber(), 1.0);
+ QCOMPARE(qjsvalue_cast<qreal>(sant), 1.0);
+
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toNumber(), 123.0);
+ QCOMPARE(qjsvalue_cast<qreal>(number), 123.0);
+
+ QJSValue number2(int(0x43211234));
+ QCOMPARE(number2.toNumber(), 1126240820.0);
+
+ QJSValue str = QJSValue(QString("ciao"));
+ QCOMPARE(qIsNaN(str.toNumber()), true);
+ QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(str)), true);
+
+ QJSValue str2 = QJSValue(QString("123"));
+ QCOMPARE(str2.toNumber(), 123.0);
+ QCOMPARE(qjsvalue_cast<qreal>(str2), 123.0);
+ }
+}
+
+void tst_QJSValue::toBoolean() // deprecated
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(undefined), false);
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(null), false);
+
+ {
+ QJSValue falskt = QJSValue(&eng, false);
+ QCOMPARE(falskt.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(falskt), false);
+
+ QJSValue sant = QJSValue(&eng, true);
+ QCOMPARE(sant.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(sant), true);
+
+ QJSValue number = QJSValue(&eng, 0.0);
+ QCOMPARE(number.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number), false);
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number2), false);
+
+ QJSValue number3 = QJSValue(&eng, 123.0);
+ QCOMPARE(number3.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number3), true);
+
+ QJSValue number4 = QJSValue(&eng, -456.0);
+ QCOMPARE(number4.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number4), true);
+
+ QJSValue str = QJSValue(&eng, QString(""));
+ QCOMPARE(str.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(str), false);
+
+ QJSValue str2 = QJSValue(&eng, QString("123"));
+ QCOMPARE(str2.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(str2), true);
+ }
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(object), true);
+
+ // FIXME: No c-style callbacks currently
+#if 0
+ QJSValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.toBoolean(), true);
+ QCOMPARE(qscriptvalue_cast<bool>(fun), true);
+#endif
+
+ QJSValue inv = QJSValue();
+ QCOMPARE(inv.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(inv), false);
+
+ // V2 constructors
+ {
+ QJSValue falskt = QJSValue(false);
+ QCOMPARE(falskt.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(falskt), false);
+
+ QJSValue sant = QJSValue(true);
+ QCOMPARE(sant.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(sant), true);
+
+ QJSValue number = QJSValue(0.0);
+ QCOMPARE(number.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number), false);
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number2), false);
+
+ QJSValue number3 = QJSValue(123.0);
+ QCOMPARE(number3.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number3), true);
+
+ QJSValue number4 = QJSValue(-456.0);
+ QCOMPARE(number4.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number4), true);
+
+ QJSValue number5 = QJSValue(0x43211234);
+ QCOMPARE(number5.toBoolean(), true);
+
+ QJSValue str = QJSValue(QString(""));
+ QCOMPARE(str.toBoolean(), false);
+ QCOMPARE(qjsvalue_cast<bool>(str), false);
+
+ QJSValue str2 = QJSValue(QString("123"));
+ QCOMPARE(str2.toBoolean(), true);
+ QCOMPARE(qjsvalue_cast<bool>(str2), true);
+ }
+}
+
+void tst_QJSValue::toBool()
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(undefined), false);
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(null), false);
+
+ {
+ QJSValue falskt = QJSValue(&eng, false);
+ QCOMPARE(falskt.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(falskt), false);
+
+ QJSValue sant = QJSValue(&eng, true);
+ QCOMPARE(sant.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(sant), true);
+
+ QJSValue number = QJSValue(&eng, 0.0);
+ QCOMPARE(number.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number), false);
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number2), false);
+
+ QJSValue number3 = QJSValue(&eng, 123.0);
+ QCOMPARE(number3.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number3), true);
+
+ QJSValue number4 = QJSValue(&eng, -456.0);
+ QCOMPARE(number4.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number4), true);
+
+ QJSValue str = QJSValue(&eng, QString(""));
+ QCOMPARE(str.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(str), false);
+
+ QJSValue str2 = QJSValue(&eng, QString("123"));
+ QCOMPARE(str2.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(str2), true);
+ }
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(object), true);
+
+ // FIXME: No c-style callbacks currently
+#if 0
+ QJSValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.toBool(), true);
+ QCOMPARE(qscriptvalue_cast<bool>(fun), true);
+#endif
+
+ QJSValue inv = QJSValue();
+ QCOMPARE(inv.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(inv), false);
+
+ // V2 constructors
+ {
+ QJSValue falskt = QJSValue(false);
+ QCOMPARE(falskt.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(falskt), false);
+
+ QJSValue sant = QJSValue(true);
+ QCOMPARE(sant.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(sant), true);
+
+ QJSValue number = QJSValue(0.0);
+ QCOMPARE(number.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number), false);
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(number2), false);
+
+ QJSValue number3 = QJSValue(123.0);
+ QCOMPARE(number3.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number3), true);
+
+ QJSValue number4 = QJSValue(-456.0);
+ QCOMPARE(number4.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(number4), true);
+
+ QJSValue number5 = QJSValue(0x43211234);
+ QCOMPARE(number5.toBool(), true);
+
+ QJSValue str = QJSValue(QString(""));
+ QCOMPARE(str.toBool(), false);
+ QCOMPARE(qjsvalue_cast<bool>(str), false);
+
+ QJSValue str2 = QJSValue(QString("123"));
+ QCOMPARE(str2.toBool(), true);
+ QCOMPARE(qjsvalue_cast<bool>(str2), true);
+ }
+}
+
+void tst_QJSValue::toInteger()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toInteger(), 123.0);
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toInteger(), 0.0);
+
+ QJSValue number3 = QJSValue(&eng, qInf());
+ QCOMPARE(qIsInf(number3.toInteger()), true);
+
+ QJSValue number4 = QJSValue(&eng, 0.5);
+ QCOMPARE(number4.toInteger(), 0.0);
+
+ QJSValue number5 = QJSValue(&eng, 123.5);
+ QCOMPARE(number5.toInteger(), 123.0);
+
+ QJSValue number6 = QJSValue(&eng, -456.5);
+ QCOMPARE(number6.toInteger(), -456.0);
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123.0"));
+ QCOMPARE(str.toInteger(), 123.0);
+
+ QJSValue str2 = QJSValue(&eng, QLatin1String("NaN"));
+ QCOMPARE(str2.toInteger(), 0.0);
+
+ QJSValue str3 = QJSValue(&eng, QLatin1String("Infinity"));
+ QCOMPARE(qIsInf(str3.toInteger()), true);
+
+ QJSValue str4 = QJSValue(&eng, QLatin1String("0.5"));
+ QCOMPARE(str4.toInteger(), 0.0);
+
+ QJSValue str5 = QJSValue(&eng, QLatin1String("123.5"));
+ QCOMPARE(str5.toInteger(), 123.0);
+
+ QJSValue str6 = QJSValue(&eng, QLatin1String("-456.5"));
+ QCOMPARE(str6.toInteger(), -456.0);
+ }
+ // V2 constructors
+ {
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toInteger(), 123.0);
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toInteger(), 0.0);
+
+ QJSValue number3 = QJSValue(qInf());
+ QCOMPARE(qIsInf(number3.toInteger()), true);
+
+ QJSValue number4 = QJSValue(0.5);
+ QCOMPARE(number4.toInteger(), 0.0);
+
+ QJSValue number5 = QJSValue(123.5);
+ QCOMPARE(number5.toInteger(), 123.0);
+
+ QJSValue number6 = QJSValue(-456.5);
+ QCOMPARE(number6.toInteger(), -456.0);
+
+ QJSValue number7 = QJSValue(0x43211234);
+ QCOMPARE(number7.toInteger(), qreal(0x43211234));
+
+ QJSValue str = QJSValue("123.0");
+ QCOMPARE(str.toInteger(), 123.0);
+
+ QJSValue str2 = QJSValue("NaN");
+ QCOMPARE(str2.toInteger(), 0.0);
+
+ QJSValue str3 = QJSValue("Infinity");
+ QCOMPARE(qIsInf(str3.toInteger()), true);
+
+ QJSValue str4 = QJSValue("0.5");
+ QCOMPARE(str4.toInteger(), 0.0);
+
+ QJSValue str5 = QJSValue("123.5");
+ QCOMPARE(str5.toInteger(), 123.0);
+
+ QJSValue str6 = QJSValue("-456.5");
+ QCOMPARE(str6.toInteger(), -456.0);
+ }
+
+ QJSValue inv;
+ QCOMPARE(inv.toInteger(), 0.0);
+}
+
+void tst_QJSValue::toInt32()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue zer0 = QJSValue(&eng, 0.0);
+ QCOMPARE(zer0.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(zer0), 0);
+
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(number), 123);
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number2), 0);
+
+ QJSValue number3 = QJSValue(&eng, +qInf());
+ QCOMPARE(number3.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number3), 0);
+
+ QJSValue number3_2 = QJSValue(&eng, -qInf());
+ QCOMPARE(number3_2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number3_2), 0);
+
+ QJSValue number4 = QJSValue(&eng, 0.5);
+ QCOMPARE(number4.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number4), 0);
+
+ QJSValue number5 = QJSValue(&eng, 123.5);
+ QCOMPARE(number5.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(number5), 123);
+
+ QJSValue number6 = QJSValue(&eng, -456.5);
+ QCOMPARE(number6.toInt32(), -456);
+ QCOMPARE(qjsvalue_cast<qint32>(number6), -456);
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123.0"));
+ QCOMPARE(str.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(str), 123);
+
+ QJSValue str2 = QJSValue(&eng, QLatin1String("NaN"));
+ QCOMPARE(str2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str2), 0);
+
+ QJSValue str3 = QJSValue(&eng, QLatin1String("Infinity"));
+ QCOMPARE(str3.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str3), 0);
+
+ QJSValue str3_2 = QJSValue(&eng, QLatin1String("-Infinity"));
+ QCOMPARE(str3_2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str3_2), 0);
+
+ QJSValue str4 = QJSValue(&eng, QLatin1String("0.5"));
+ QCOMPARE(str4.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str4), 0);
+
+ QJSValue str5 = QJSValue(&eng, QLatin1String("123.5"));
+ QCOMPARE(str5.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(str5), 123);
+
+ QJSValue str6 = QJSValue(&eng, QLatin1String("-456.5"));
+ QCOMPARE(str6.toInt32(), -456);
+ QCOMPARE(qjsvalue_cast<qint32>(str6), -456);
+ }
+ // V2 constructors
+ {
+ QJSValue zer0 = QJSValue(0.0);
+ QCOMPARE(zer0.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(zer0), 0);
+
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(number), 123);
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number2), 0);
+
+ QJSValue number3 = QJSValue(+qInf());
+ QCOMPARE(number3.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number3), 0);
+
+ QJSValue number3_2 = QJSValue(-qInf());
+ QCOMPARE(number3_2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number3_2), 0);
+
+ QJSValue number4 = QJSValue(0.5);
+ QCOMPARE(number4.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(number4), 0);
+
+ QJSValue number5 = QJSValue(123.5);
+ QCOMPARE(number5.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(number5), 123);
+
+ QJSValue number6 = QJSValue(-456.5);
+ QCOMPARE(number6.toInt32(), -456);
+ QCOMPARE(qjsvalue_cast<qint32>(number6), -456);
+
+ QJSValue number7 = QJSValue(0x43211234);
+ QCOMPARE(number7.toInt32(), 0x43211234);
+
+ QJSValue str = QJSValue("123.0");
+ QCOMPARE(str.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(str), 123);
+
+ QJSValue str2 = QJSValue("NaN");
+ QCOMPARE(str2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str2), 0);
+
+ QJSValue str3 = QJSValue("Infinity");
+ QCOMPARE(str3.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str3), 0);
+
+ QJSValue str3_2 = QJSValue("-Infinity");
+ QCOMPARE(str3_2.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str3_2), 0);
+
+ QJSValue str4 = QJSValue("0.5");
+ QCOMPARE(str4.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(str4), 0);
+
+ QJSValue str5 = QJSValue("123.5");
+ QCOMPARE(str5.toInt32(), 123);
+ QCOMPARE(qjsvalue_cast<qint32>(str5), 123);
+
+ QJSValue str6 = QJSValue("-456.5");
+ QCOMPARE(str6.toInt32(), -456);
+ QCOMPARE(qjsvalue_cast<qint32>(str6), -456);
+ }
+
+ QJSValue inv;
+ QCOMPARE(inv.toInt32(), 0);
+ QCOMPARE(qjsvalue_cast<qint32>(inv), 0);
+}
+
+void tst_QJSValue::toUInt32()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue zer0 = QJSValue(&eng, 0.0);
+ QCOMPARE(zer0.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(zer0), quint32(0));
+
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(number), quint32(123));
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number2), quint32(0));
+
+ QJSValue number3 = QJSValue(&eng, +qInf());
+ QCOMPARE(number3.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number3), quint32(0));
+
+ QJSValue number3_2 = QJSValue(&eng, -qInf());
+ QCOMPARE(number3_2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number3_2), quint32(0));
+
+ QJSValue number4 = QJSValue(&eng, 0.5);
+ QCOMPARE(number4.toUInt32(), quint32(0));
+
+ QJSValue number5 = QJSValue(&eng, 123.5);
+ QCOMPARE(number5.toUInt32(), quint32(123));
+
+ QJSValue number6 = QJSValue(&eng, -456.5);
+ QCOMPARE(number6.toUInt32(), quint32(-456));
+ QCOMPARE(qjsvalue_cast<quint32>(number6), quint32(-456));
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123.0"));
+ QCOMPARE(str.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(str), quint32(123));
+
+ QJSValue str2 = QJSValue(&eng, QLatin1String("NaN"));
+ QCOMPARE(str2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str2), quint32(0));
+
+ QJSValue str3 = QJSValue(&eng, QLatin1String("Infinity"));
+ QCOMPARE(str3.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str3), quint32(0));
+
+ QJSValue str3_2 = QJSValue(&eng, QLatin1String("-Infinity"));
+ QCOMPARE(str3_2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str3_2), quint32(0));
+
+ QJSValue str4 = QJSValue(&eng, QLatin1String("0.5"));
+ QCOMPARE(str4.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str4), quint32(0));
+
+ QJSValue str5 = QJSValue(&eng, QLatin1String("123.5"));
+ QCOMPARE(str5.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(str5), quint32(123));
+
+ QJSValue str6 = QJSValue(&eng, QLatin1String("-456.5"));
+ QCOMPARE(str6.toUInt32(), quint32(-456));
+ QCOMPARE(qjsvalue_cast<quint32>(str6), quint32(-456));
+ }
+ // V2 constructors
+ {
+ QJSValue zer0 = QJSValue(0.0);
+ QCOMPARE(zer0.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(zer0), quint32(0));
+
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(number), quint32(123));
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number2), quint32(0));
+
+ QJSValue number3 = QJSValue(+qInf());
+ QCOMPARE(number3.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number3), quint32(0));
+
+ QJSValue number3_2 = QJSValue(-qInf());
+ QCOMPARE(number3_2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(number3_2), quint32(0));
+
+ QJSValue number4 = QJSValue(0.5);
+ QCOMPARE(number4.toUInt32(), quint32(0));
+
+ QJSValue number5 = QJSValue(123.5);
+ QCOMPARE(number5.toUInt32(), quint32(123));
+
+ QJSValue number6 = QJSValue(-456.5);
+ QCOMPARE(number6.toUInt32(), quint32(-456));
+ QCOMPARE(qjsvalue_cast<quint32>(number6), quint32(-456));
+
+ QJSValue number7 = QJSValue(0x43211234);
+ QCOMPARE(number7.toUInt32(), quint32(0x43211234));
+
+ QJSValue str = QJSValue(QLatin1String("123.0"));
+ QCOMPARE(str.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(str), quint32(123));
+
+ QJSValue str2 = QJSValue(QLatin1String("NaN"));
+ QCOMPARE(str2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str2), quint32(0));
+
+ QJSValue str3 = QJSValue(QLatin1String("Infinity"));
+ QCOMPARE(str3.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str3), quint32(0));
+
+ QJSValue str3_2 = QJSValue(QLatin1String("-Infinity"));
+ QCOMPARE(str3_2.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str3_2), quint32(0));
+
+ QJSValue str4 = QJSValue(QLatin1String("0.5"));
+ QCOMPARE(str4.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(str4), quint32(0));
+
+ QJSValue str5 = QJSValue(QLatin1String("123.5"));
+ QCOMPARE(str5.toUInt32(), quint32(123));
+ QCOMPARE(qjsvalue_cast<quint32>(str5), quint32(123));
+
+ QJSValue str6 = QJSValue(QLatin1String("-456.5"));
+ QCOMPARE(str6.toUInt32(), quint32(-456));
+ QCOMPARE(qjsvalue_cast<quint32>(str6), quint32(-456));
+ }
+
+ QJSValue inv;
+ QCOMPARE(inv.toUInt32(), quint32(0));
+ QCOMPARE(qjsvalue_cast<quint32>(inv), quint32(0));
+}
+
+void tst_QJSValue::toUInt16()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue zer0 = QJSValue(&eng, 0.0);
+ QCOMPARE(zer0.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(zer0), quint16(0));
+
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toUInt16(), quint16(123));
+ QCOMPARE(qjsvalue_cast<quint16>(number), quint16(123));
+
+ QJSValue number2 = QJSValue(&eng, qSNaN());
+ QCOMPARE(number2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number2), quint16(0));
+
+ QJSValue number3 = QJSValue(&eng, +qInf());
+ QCOMPARE(number3.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number3), quint16(0));
+
+ QJSValue number3_2 = QJSValue(&eng, -qInf());
+ QCOMPARE(number3_2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number3_2), quint16(0));
+
+ QJSValue number4 = QJSValue(&eng, 0.5);
+ QCOMPARE(number4.toUInt16(), quint16(0));
+
+ QJSValue number5 = QJSValue(&eng, 123.5);
+ QCOMPARE(number5.toUInt16(), quint16(123));
+
+ QJSValue number6 = QJSValue(&eng, -456.5);
+ QCOMPARE(number6.toUInt16(), quint16(-456));
+ QCOMPARE(qjsvalue_cast<quint16>(number6), quint16(-456));
+
+ QJSValue number7 = QJSValue(&eng, 0x10000);
+ QCOMPARE(number7.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number7), quint16(0));
+
+ QJSValue number8 = QJSValue(&eng, 0x10001);
+ QCOMPARE(number8.toUInt16(), quint16(1));
+ QCOMPARE(qjsvalue_cast<quint16>(number8), quint16(1));
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123.0"));
+ QCOMPARE(str.toUInt16(), quint16(123));
+ QCOMPARE(qjsvalue_cast<quint16>(str), quint16(123));
+
+ QJSValue str2 = QJSValue(&eng, QLatin1String("NaN"));
+ QCOMPARE(str2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str2), quint16(0));
+
+ QJSValue str3 = QJSValue(&eng, QLatin1String("Infinity"));
+ QCOMPARE(str3.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str3), quint16(0));
+
+ QJSValue str3_2 = QJSValue(&eng, QLatin1String("-Infinity"));
+ QCOMPARE(str3_2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str3_2), quint16(0));
+
+ QJSValue str4 = QJSValue(&eng, QLatin1String("0.5"));
+ QCOMPARE(str4.toUInt16(), quint16(0));
+
+ QJSValue str5 = QJSValue(&eng, QLatin1String("123.5"));
+ QCOMPARE(str5.toUInt16(), quint16(123));
+
+ QJSValue str6 = QJSValue(&eng, QLatin1String("-456.5"));
+ QCOMPARE(str6.toUInt16(), quint16(-456));
+ QCOMPARE(qjsvalue_cast<quint16>(str6), quint16(-456));
+
+ QJSValue str7 = QJSValue(&eng, QLatin1String("0x10000"));
+ QCOMPARE(str7.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str7), quint16(0));
+
+ QJSValue str8 = QJSValue(&eng, QLatin1String("0x10001"));
+ QCOMPARE(str8.toUInt16(), quint16(1));
+ QCOMPARE(qjsvalue_cast<quint16>(str8), quint16(1));
+ }
+ // V2 constructors
+ {
+ QJSValue zer0 = QJSValue(0.0);
+ QCOMPARE(zer0.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(zer0), quint16(0));
+
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toUInt16(), quint16(123));
+ QCOMPARE(qjsvalue_cast<quint16>(number), quint16(123));
+
+ QJSValue number2 = QJSValue(qSNaN());
+ QCOMPARE(number2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number2), quint16(0));
+
+ QJSValue number3 = QJSValue(+qInf());
+ QCOMPARE(number3.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number3), quint16(0));
+
+ QJSValue number3_2 = QJSValue(-qInf());
+ QCOMPARE(number3_2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number3_2), quint16(0));
+
+ QJSValue number4 = QJSValue(0.5);
+ QCOMPARE(number4.toUInt16(), quint16(0));
+
+ QJSValue number5 = QJSValue(123.5);
+ QCOMPARE(number5.toUInt16(), quint16(123));
+
+ QJSValue number6 = QJSValue(-456.5);
+ QCOMPARE(number6.toUInt16(), quint16(-456));
+ QCOMPARE(qjsvalue_cast<quint16>(number6), quint16(-456));
+
+ QJSValue number7 = QJSValue(0x10000);
+ QCOMPARE(number7.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(number7), quint16(0));
+
+ QJSValue number8 = QJSValue(0x10001);
+ QCOMPARE(number8.toUInt16(), quint16(1));
+ QCOMPARE(qjsvalue_cast<quint16>(number8), quint16(1));
+
+ QJSValue str = QJSValue(QLatin1String("123.0"));
+ QCOMPARE(str.toUInt16(), quint16(123));
+ QCOMPARE(qjsvalue_cast<quint16>(str), quint16(123));
+
+ QJSValue str2 = QJSValue(QLatin1String("NaN"));
+ QCOMPARE(str2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str2), quint16(0));
+
+ QJSValue str3 = QJSValue(QLatin1String("Infinity"));
+ QCOMPARE(str3.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str3), quint16(0));
+
+ QJSValue str3_2 = QJSValue(QLatin1String("-Infinity"));
+ QCOMPARE(str3_2.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str3_2), quint16(0));
+
+ QJSValue str4 = QJSValue("0.5");
+ QCOMPARE(str4.toUInt16(), quint16(0));
+
+ QJSValue str5 = QJSValue("123.5");
+ QCOMPARE(str5.toUInt16(), quint16(123));
+
+ QJSValue str6 = QJSValue("-456.5");
+ QCOMPARE(str6.toUInt16(), quint16(-456));
+ QCOMPARE(qjsvalue_cast<quint16>(str6), quint16(-456));
+
+ QJSValue str7 = QJSValue("0x10000");
+ QCOMPARE(str7.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(str7), quint16(0));
+
+ QJSValue str8 = QJSValue("0x10001");
+ QCOMPARE(str8.toUInt16(), quint16(1));
+ QCOMPARE(qjsvalue_cast<quint16>(str8), quint16(1));
+ }
+
+ QJSValue inv;
+ QCOMPARE(inv.toUInt16(), quint16(0));
+ QCOMPARE(qjsvalue_cast<quint16>(inv), quint16(0));
+}
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+Q_DECLARE_METATYPE(QVariant)
+#endif
+
+void tst_QJSValue::toVariant()
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toVariant(), QVariant());
+ QCOMPARE(qjsvalue_cast<QVariant>(undefined), QVariant());
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toVariant(), QVariant());
+ QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant());
+
+ {
+ QJSValue number = QJSValue(&eng, 123.0);
+ QCOMPARE(number.toVariant(), QVariant(123.0));
+ QCOMPARE(qjsvalue_cast<QVariant>(number), QVariant(123.0));
+
+ QJSValue intNumber = QJSValue(&eng, (qint32)123);
+ QCOMPARE(intNumber.toVariant().type(), QVariant((qint32)123).type());
+ QCOMPARE((qjsvalue_cast<QVariant>(number)).type(), QVariant((qint32)123).type());
+
+ QJSValue falskt = QJSValue(&eng, false);
+ QCOMPARE(falskt.toVariant(), QVariant(false));
+ QCOMPARE(qjsvalue_cast<QVariant>(falskt), QVariant(false));
+
+ QJSValue sant = QJSValue(&eng, true);
+ QCOMPARE(sant.toVariant(), QVariant(true));
+ QCOMPARE(qjsvalue_cast<QVariant>(sant), QVariant(true));
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ QCOMPARE(str.toVariant(), QVariant(QString("ciao")));
+ QCOMPARE(qjsvalue_cast<QVariant>(str), QVariant(QString("ciao")));
+ }
+
+ QVariant var(QChar(0x007A));
+ QJSValue opaque = eng.newVariant(var);
+ QVERIFY(opaque.isVariant());
+ QCOMPARE(opaque.toVariant(), var);
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.toVariant(), QVariant(QVariantMap()));
+
+ QJSValue qobject = eng.newQObject(this);
+ {
+ QVariant var = qobject.toVariant();
+ QCOMPARE(var.userType(), int(QMetaType::QObjectStar));
+ QCOMPARE(qVariantValue<QObject*>(var), (QObject *)this);
+ }
+
+ {
+ QDateTime dateTime = QDateTime(QDate(1980, 10, 4));
+ QJSValue dateObject = eng.newDate(dateTime);
+ QVariant var = dateObject.toVariant();
+ QCOMPARE(var, QVariant(dateTime));
+ }
+
+ {
+ QRegExp rx = QRegExp("[0-9a-z]+", Qt::CaseSensitive, QRegExp::RegExp2);
+ QJSValue rxObject = eng.newRegExp(rx);
+ QVariant var = rxObject.toVariant();
+ QCOMPARE(var, QVariant(rx));
+ }
+
+ QJSValue inv;
+ QCOMPARE(inv.toVariant(), QVariant());
+ QCOMPARE(qjsvalue_cast<QVariant>(inv), QVariant());
+
+ // V2 constructors
+ {
+ QJSValue number = QJSValue(123.0);
+ QCOMPARE(number.toVariant(), QVariant(123.0));
+ QCOMPARE(qjsvalue_cast<QVariant>(number), QVariant(123.0));
+
+ QJSValue falskt = QJSValue(false);
+ QCOMPARE(falskt.toVariant(), QVariant(false));
+ QCOMPARE(qjsvalue_cast<QVariant>(falskt), QVariant(false));
+
+ QJSValue sant = QJSValue(true);
+ QCOMPARE(sant.toVariant(), QVariant(true));
+ QCOMPARE(qjsvalue_cast<QVariant>(sant), QVariant(true));
+
+ QJSValue str = QJSValue(QString("ciao"));
+ QCOMPARE(str.toVariant(), QVariant(QString("ciao")));
+ QCOMPARE(qjsvalue_cast<QVariant>(str), QVariant(QString("ciao")));
+ }
+
+#if 0 // FIXME: No automatic sequence conversion
+ // array
+ {
+ QVariantList listIn;
+ listIn << 123 << "hello";
+ QJSValue array = qScriptValueFromValue(&eng, listIn);
+ QVERIFY(array.isArray());
+ QCOMPARE(array.property("length").toInt32(), 2);
+ QVariant ret = array.toVariant();
+ QCOMPARE(ret.type(), QVariant::List);
+ QVariantList listOut = ret.toList();
+ QCOMPARE(listOut.size(), listIn.size());
+ for (int i = 0; i < listIn.size(); ++i)
+ QVERIFY(listOut.at(i) == listIn.at(i));
+ // round-trip conversion
+ QJSValue array2 = qScriptValueFromValue(&eng, ret);
+ QVERIFY(array2.isArray());
+ QCOMPARE(array2.property("length").toInt32(), array.property("length").toInt32());
+ for (int i = 0; i < array.property("length").toInt32(); ++i)
+ QVERIFY(array2.property(i).strictlyEquals(array.property(i)));
+ }
+#endif
+}
+
+void tst_QJSValue::toQObject_nonQObject_data()
+{
+ newEngine();
+ QTest::addColumn<QJSValue>("value");
+
+ QTest::newRow("invalid") << QJSValue();
+ QTest::newRow("bool(false)") << QJSValue(false);
+ QTest::newRow("bool(true)") << QJSValue(true);
+ QTest::newRow("int") << QJSValue(123);
+ QTest::newRow("string") << QJSValue(QString::fromLatin1("ciao"));
+ QTest::newRow("undefined") << QJSValue(QJSValue::UndefinedValue);
+ QTest::newRow("null") << QJSValue(QJSValue::NullValue);
+
+ QTest::newRow("bool bound(false)") << QJSValue(engine, false);
+ QTest::newRow("bool bound(true)") << QJSValue(engine, true);
+ QTest::newRow("int bound") << QJSValue(engine, 123);
+ QTest::newRow("string bound") << QJSValue(engine, QString::fromLatin1("ciao"));
+ QTest::newRow("undefined bound") << engine->undefinedValue();
+ QTest::newRow("null bound") << engine->nullValue();
+ QTest::newRow("object") << engine->newObject();
+ QTest::newRow("array") << engine->newArray();
+ QTest::newRow("date") << engine->newDate(124);
+ QTest::newRow("variant(12345)") << engine->newVariant(12345);
+ QTest::newRow("variant((QObject*)0)") << engine->newVariant(qVariantFromValue((QObject*)0));
+ QTest::newRow("newQObject(0)") << engine->newQObject(0);
+}
+
+
+void tst_QJSValue::toQObject_nonQObject()
+{
+ QFETCH(QJSValue, value);
+ QCOMPARE(value.toQObject(), (QObject *)0);
+ QCOMPARE(qjsvalue_cast<QObject*>(value), (QObject *)0);
+}
+
+// unfortunately, this is necessary in order to do qscriptvalue_cast<QPushButton*>(...)
+Q_DECLARE_METATYPE(QPushButton*);
+
+void tst_QJSValue::toQObject()
+{
+ QJSEngine eng;
+
+ QJSValue qobject = eng.newQObject(this);
+ QCOMPARE(qobject.toQObject(), (QObject *)this);
+ QCOMPARE(qjsvalue_cast<QObject*>(qobject), (QObject *)this);
+ QCOMPARE(qjsvalue_cast<QWidget*>(qobject), (QWidget *)0);
+
+ QWidget widget;
+ QJSValue qwidget = eng.newQObject(&widget);
+ QCOMPARE(qwidget.toQObject(), (QObject *)&widget);
+ QCOMPARE(qjsvalue_cast<QObject*>(qwidget), (QObject *)&widget);
+ QCOMPARE(qjsvalue_cast<QWidget*>(qwidget), &widget);
+
+ QPushButton button;
+ QJSValue qbutton = eng.newQObject(&button);
+ QCOMPARE(qbutton.toQObject(), (QObject *)&button);
+ QCOMPARE(qjsvalue_cast<QObject*>(qbutton), (QObject *)&button);
+ QCOMPARE(qjsvalue_cast<QWidget*>(qbutton), (QWidget *)&button);
+ QCOMPARE(qjsvalue_cast<QPushButton*>(qbutton), &button);
+
+ // wrapping a QObject* as variant
+ QJSValue variant = eng.newVariant(qVariantFromValue((QObject*)&button));
+ QCOMPARE(variant.toQObject(), (QObject*)&button);
+ QCOMPARE(qjsvalue_cast<QObject*>(variant), (QObject*)&button);
+ QCOMPARE(qjsvalue_cast<QWidget*>(variant), (QWidget*)&button);
+ QCOMPARE(qjsvalue_cast<QPushButton*>(variant), &button);
+
+ QJSValue variant2 = eng.newVariant(qVariantFromValue((QWidget*)&button));
+ QCOMPARE(variant2.toQObject(), (QObject*)&button);
+ QCOMPARE(qjsvalue_cast<QObject*>(variant2), (QObject*)&button);
+ QCOMPARE(qjsvalue_cast<QWidget*>(variant2), (QWidget*)&button);
+ QCOMPARE(qjsvalue_cast<QPushButton*>(variant2), &button);
+
+ QJSValue variant3 = eng.newVariant(qVariantFromValue(&button));
+ QCOMPARE(variant3.toQObject(), (QObject*)0);
+ QCOMPARE(qjsvalue_cast<QObject*>(variant3), (QObject*)0);
+ QCOMPARE(qjsvalue_cast<QWidget*>(variant3), (QWidget*)0);
+ QCOMPARE(qjsvalue_cast<QPushButton*>(variant3), &button);
+}
+
+void tst_QJSValue::toObject()
+{
+ QJSEngine eng;
+
+ QJSValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toObject().isValid(), false);
+ QVERIFY(undefined.isUndefined());
+
+ QJSValue null = eng.nullValue();
+ QCOMPARE(null.toObject().isValid(), false);
+ QVERIFY(null.isNull());
+
+ {
+ QJSValue falskt = QJSValue(&eng, false);
+ {
+ QJSValue tmp = falskt.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(tmp.toNumber(), falskt.toNumber());
+ }
+ QVERIFY(falskt.isBool());
+
+ QJSValue sant = QJSValue(&eng, true);
+ {
+ QJSValue tmp = sant.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(tmp.toNumber(), sant.toNumber());
+ }
+ QVERIFY(sant.isBool());
+
+ QJSValue number = QJSValue(&eng, 123.0);
+ {
+ QJSValue tmp = number.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(tmp.toNumber(), number.toNumber());
+ }
+ QVERIFY(number.isNumber());
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ {
+ QJSValue tmp = str.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(tmp.toString(), str.toString());
+ }
+ QVERIFY(str.isString());
+ }
+
+ QJSValue object = eng.newObject();
+ {
+ QJSValue tmp = object.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ }
+
+ QJSValue qobject = eng.newQObject(this);
+ QCOMPARE(qobject.toObject().isValid(), true);
+
+ QJSValue inv;
+ QCOMPARE(inv.toObject().isValid(), false);
+
+ // V2 constructors: in this case, you have to use QScriptEngine::toObject()
+ {
+ QJSValue undefined = QJSValue(QJSValue::UndefinedValue);
+ QVERIFY(!undefined.toObject().isValid());
+ QVERIFY(!eng.toObject(undefined).isValid());
+ QVERIFY(undefined.isUndefined());
+
+ QJSValue null = QJSValue(QJSValue::NullValue);
+ QVERIFY(!null.toObject().isValid());
+ QVERIFY(!eng.toObject(null).isValid());
+ QVERIFY(null.isNull());
+
+ QJSValue falskt = QJSValue(false);
+ QVERIFY(!falskt.toObject().isValid());
+ {
+ QJSValue tmp = eng.toObject(falskt);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.toBool());
+ }
+ QVERIFY(falskt.isBool());
+
+ QJSValue sant = QJSValue(true);
+ QVERIFY(!sant.toObject().isValid());
+ {
+ QJSValue tmp = eng.toObject(sant);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.toBool());
+ }
+ QVERIFY(sant.isBool());
+
+ QJSValue number = QJSValue(123.0);
+ QVERIFY(!number.toObject().isValid());
+ {
+ QJSValue tmp = eng.toObject(number);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toInt32(), number.toInt32());
+ }
+ QVERIFY(number.isNumber());
+
+ QJSValue str = QJSValue(QString::fromLatin1("ciao"));
+ QVERIFY(!str.toObject().isValid());
+ {
+ QJSValue tmp = eng.toObject(str);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toString(), QString::fromLatin1("ciao"));
+ }
+ QVERIFY(str.isString());
+ }
+}
+
+void tst_QJSValue::toDateTime()
+{
+ QJSEngine eng;
+ QDateTime dt = eng.evaluate("new Date(0)").toDateTime();
+ QVERIFY(dt.isValid());
+ QCOMPARE(dt.timeSpec(), Qt::LocalTime);
+ QCOMPARE(dt.toUTC(), QDateTime(QDate(1970, 1, 1), QTime(0, 0, 0), Qt::UTC));
+
+ QVERIFY(!eng.evaluate("[]").toDateTime().isValid());
+ QVERIFY(!eng.evaluate("{}").toDateTime().isValid());
+ QVERIFY(!eng.globalObject().toDateTime().isValid());
+ QVERIFY(!QJSValue().toDateTime().isValid());
+ QVERIFY(!QJSValue(123).toDateTime().isValid());
+ QVERIFY(!QJSValue(false).toDateTime().isValid());
+ QVERIFY(!eng.nullValue().toDateTime().isValid());
+ QVERIFY(!eng.undefinedValue().toDateTime().isValid());
+}
+
+void tst_QJSValue::toRegExp()
+{
+ QJSEngine eng;
+ {
+ QRegExp rx = eng.evaluate("/foo/").toRegExp();
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.patternSyntax(), QRegExp::RegExp2);
+ QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
+ QCOMPARE(rx.caseSensitivity(), Qt::CaseSensitive);
+ QVERIFY(!rx.isMinimal());
+ }
+ {
+ QRegExp rx = eng.evaluate("/bar/gi").toRegExp();
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.patternSyntax(), QRegExp::RegExp2);
+ QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
+ QCOMPARE(rx.caseSensitivity(), Qt::CaseInsensitive);
+ QVERIFY(!rx.isMinimal());
+ }
+
+ QVERIFY(eng.evaluate("[]").toRegExp().isEmpty());
+ QVERIFY(eng.evaluate("{}").toRegExp().isEmpty());
+ QVERIFY(eng.globalObject().toRegExp().isEmpty());
+ QVERIFY(QJSValue().toRegExp().isEmpty());
+ QVERIFY(QJSValue(123).toRegExp().isEmpty());
+ QVERIFY(QJSValue(false).toRegExp().isEmpty());
+ QVERIFY(eng.nullValue().toRegExp().isEmpty());
+ QVERIFY(eng.undefinedValue().toRegExp().isEmpty());
+}
+
+void tst_QJSValue::instanceOf_twoEngines()
+{
+ QJSEngine eng;
+ QJSValue obj = eng.newObject();
+ QJSEngine otherEngine;
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::instanceof: cannot perform operation on a value created in a different engine");
+ QCOMPARE(obj.instanceOf(otherEngine.globalObject().property("Object")), false);
+}
+
+void tst_QJSValue::instanceOf()
+{
+ QJSEngine eng;
+ QJSValue obj = eng.newObject();
+ QCOMPARE(obj.instanceOf(eng.evaluate("Object.prototype")), false);
+ QCOMPARE(obj.instanceOf(eng.evaluate("Array.prototype")), false);
+ QCOMPARE(obj.instanceOf(eng.evaluate("Function.prototype")), false);
+ QCOMPARE(obj.instanceOf(eng.evaluate("QObject.prototype")), false);
+ QCOMPARE(obj.instanceOf(QJSValue(&eng, 123)), false);
+ QCOMPARE(obj.instanceOf(eng.undefinedValue()), false);
+ QCOMPARE(obj.instanceOf(eng.nullValue()), false);
+ QCOMPARE(obj.instanceOf(QJSValue()), false);
+
+ QCOMPARE(obj.instanceOf(eng.evaluate("Object")), true);
+ QCOMPARE(obj.instanceOf(eng.evaluate("Array")), false);
+ QCOMPARE(obj.instanceOf(eng.evaluate("Function")), false);
+ QCOMPARE(obj.instanceOf(eng.evaluate("QObject")), false);
+
+ QJSValue arr = eng.newArray();
+ QVERIFY(arr.isArray());
+ QCOMPARE(arr.instanceOf(eng.evaluate("Object.prototype")), false);
+ QCOMPARE(arr.instanceOf(eng.evaluate("Array.prototype")), false);
+ QCOMPARE(arr.instanceOf(eng.evaluate("Function.prototype")), false);
+ QCOMPARE(arr.instanceOf(eng.evaluate("QObject.prototype")), false);
+ QCOMPARE(arr.instanceOf(eng.evaluate("Object")), true);
+ QCOMPARE(arr.instanceOf(eng.evaluate("Array")), true);
+ QCOMPARE(arr.instanceOf(eng.evaluate("Function")), false);
+ QCOMPARE(arr.instanceOf(eng.evaluate("QObject")), false);
+
+ QCOMPARE(QJSValue().instanceOf(arr), false);
+}
+
+void tst_QJSValue::isArray_data()
+{
+ newEngine();
+
+ QTest::addColumn<QJSValue>("value");
+ QTest::addColumn<bool>("array");
+
+ QTest::newRow("[]") << engine->evaluate("[]") << true;
+ QTest::newRow("{}") << engine->evaluate("{}") << false;
+ QTest::newRow("globalObject") << engine->globalObject() << false;
+ QTest::newRow("invalid") << QJSValue() << false;
+ QTest::newRow("number") << QJSValue(123) << false;
+ QTest::newRow("bool") << QJSValue(false) << false;
+ QTest::newRow("null") << engine->nullValue() << false;
+ QTest::newRow("undefined") << engine->undefinedValue() << false;
+}
+
+void tst_QJSValue::isArray()
+{
+ QFETCH(QJSValue, value);
+ QFETCH(bool, array);
+
+ QCOMPARE(value.isArray(), array);
+}
+
+void tst_QJSValue::isDate_data()
+{
+ newEngine();
+
+ QTest::addColumn<QJSValue>("value");
+ QTest::addColumn<bool>("date");
+
+ QTest::newRow("date") << engine->evaluate("new Date()") << true;
+ QTest::newRow("[]") << engine->evaluate("[]") << false;
+ QTest::newRow("{}") << engine->evaluate("{}") << false;
+ QTest::newRow("globalObject") << engine->globalObject() << false;
+ QTest::newRow("invalid") << QJSValue() << false;
+ QTest::newRow("number") << QJSValue(123) << false;
+ QTest::newRow("bool") << QJSValue(false) << false;
+ QTest::newRow("null") << engine->nullValue() << false;
+ QTest::newRow("undefined") << engine->undefinedValue() << false;
+}
+
+void tst_QJSValue::isDate()
+{
+ QFETCH(QJSValue, value);
+ QFETCH(bool, date);
+
+ QCOMPARE(value.isDate(), date);
+}
+
+void tst_QJSValue::isError_propertiesOfGlobalObject()
+{
+ QStringList errors;
+ errors << "Error"
+ << "EvalError"
+ << "RangeError"
+ << "ReferenceError"
+ << "SyntaxError"
+ << "TypeError"
+ << "URIError";
+ QJSEngine eng;
+ for (int i = 0; i < errors.size(); ++i) {
+ QJSValue ctor = eng.globalObject().property(errors.at(i));
+ QVERIFY(ctor.isFunction());
+ QVERIFY(ctor.property("prototype").isError());
+ }
+}
+
+void tst_QJSValue::isError_data()
+{
+ newEngine();
+
+ QTest::addColumn<QJSValue>("value");
+ QTest::addColumn<bool>("error");
+
+ QTest::newRow("syntax error") << engine->evaluate("%fsdg's") << true;
+ QTest::newRow("[]") << engine->evaluate("[]") << false;
+ QTest::newRow("{}") << engine->evaluate("{}") << false;
+ QTest::newRow("globalObject") << engine->globalObject() << false;
+ QTest::newRow("invalid") << QJSValue() << false;
+ QTest::newRow("number") << QJSValue(123) << false;
+ QTest::newRow("bool") << QJSValue(false) << false;
+ QTest::newRow("null") << engine->nullValue() << false;
+ QTest::newRow("undefined") << engine->undefinedValue() << false;
+ QTest::newRow("newObject") << engine->newObject() << false;
+ QTest::newRow("new Object") << engine->evaluate("new Object()") << false;
+}
+
+void tst_QJSValue::isError()
+{
+ QFETCH(QJSValue, value);
+ QFETCH(bool, error);
+
+ QCOMPARE(value.isError(), error);
+}
+
+void tst_QJSValue::isRegExp_data()
+{
+ newEngine();
+
+ QTest::addColumn<QJSValue>("value");
+ QTest::addColumn<bool>("regexp");
+
+ QTest::newRow("/foo/") << engine->evaluate("/foo/") << true;
+ QTest::newRow("[]") << engine->evaluate("[]") << false;
+ QTest::newRow("{}") << engine->evaluate("{}") << false;
+ QTest::newRow("globalObject") << engine->globalObject() << false;
+ QTest::newRow("invalid") << QJSValue() << false;
+ QTest::newRow("number") << QJSValue(123) << false;
+ QTest::newRow("bool") << QJSValue(false) << false;
+ QTest::newRow("null") << engine->nullValue() << false;
+ QTest::newRow("undefined") << engine->undefinedValue() << false;
+}
+
+void tst_QJSValue::isRegExp()
+{
+ QFETCH(QJSValue, value);
+ QFETCH(bool, regexp);
+
+ QCOMPARE(value.isRegExp(), regexp);
+}
+
+#if 0 // FIXME: No c-style callbacks currently
+static QJSValue getter(QScriptContext *ctx, QScriptEngine *)
+{
+ return ctx->thisObject().property("x");
+}
+
+static QJSValue setter(QScriptContext *ctx, QScriptEngine *)
+{
+ ctx->thisObject().setProperty("x", ctx->argument(0));
+ return ctx->argument(0);
+}
+
+static QJSValue getterSetter(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() > 0)
+ ctx->thisObject().setProperty("x", ctx->argument(0));
+ return ctx->thisObject().property("x");
+}
+
+static QJSValue getterSetterThrowingError(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() > 0)
+ return ctx->throwError("set foo");
+ else
+ return ctx->throwError("get foo");
+}
+
+static QJSValue getSet__proto__(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() > 0)
+ ctx->callee().setProperty("value", ctx->argument(0));
+ return ctx->callee().property("value");
+}
+#endif
+
+void tst_QJSValue::getSetProperty_HooliganTask162051()
+{
+ QJSEngine eng;
+ // task 162051 -- detecting whether the property is an array index or not
+ QVERIFY(eng.evaluate("a = []; a['00'] = 123; a['00']").strictlyEquals(QJSValue(&eng, 123)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QJSValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('00')").strictlyEquals(QJSValue(&eng, true)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('0')").strictlyEquals(QJSValue(&eng, false)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0.5] = 456; a[0.5]").strictlyEquals(QJSValue(&eng, 456)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QJSValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('0.5')").strictlyEquals(QJSValue(&eng, true)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0] = 789; a[0]").strictlyEquals(QJSValue(&eng, 789)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QJSValue(&eng, 1)));
+}
+
+void tst_QJSValue::getSetProperty_HooliganTask183072()
+{
+ QJSEngine eng;
+ // task 183072 -- 0x800000000 is not an array index
+ eng.evaluate("a = []; a[0x800000000] = 123");
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QJSValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0x800000000]").strictlyEquals(QJSValue(&eng, 123)));
+}
+
+void tst_QJSValue::getSetProperty_propertyRemoval()
+{
+ // test property removal (setProperty(QJSValue()))
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ QJSValue str = QJSValue(&eng, QLatin1String("bar"));
+ QJSValue num = QJSValue(&eng, 123.0);
+
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ object.setProperty("bar", str);
+ QCOMPARE(object.property("bar").strictlyEquals(str), true);
+ object.setProperty("foo", QJSValue());
+ QCOMPARE(object.property("foo").isValid(), false);
+ QCOMPARE(object.property("bar").strictlyEquals(str), true);
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ QCOMPARE(object.property("bar").strictlyEquals(str), true);
+ object.setProperty("bar", QJSValue());
+ QCOMPARE(object.property("bar").isValid(), false);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ object.setProperty("foo", QJSValue());
+ object.setProperty("foo", QJSValue());
+
+ eng.globalObject().setProperty("object3", object);
+ QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
+ .strictlyEquals(QJSValue(&eng, false)), true);
+ object.setProperty("foo", num);
+ QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
+ .strictlyEquals(QJSValue(&eng, true)), true);
+ eng.globalObject().setProperty("object3", QJSValue());
+ QCOMPARE(eng.evaluate("this.hasOwnProperty('object3')")
+ .strictlyEquals(QJSValue(&eng, false)), true);
+}
+
+void tst_QJSValue::getSetProperty_resolveMode()
+{
+ // test ResolveMode
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ QJSValue prototype = eng.newObject();
+ object.setPrototype(prototype);
+ QJSValue num2 = QJSValue(&eng, 456.0);
+ prototype.setProperty("propertyInPrototype", num2);
+ // default is ResolvePrototype
+ QCOMPARE(object.property("propertyInPrototype")
+ .strictlyEquals(num2), true);
+#if 0 // FIXME: ResolveFlags removed from API
+ QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolvePrototype)
+ .strictlyEquals(num2), true);
+ QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveLocal)
+ .isValid(), false);
+ QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveScope)
+ .strictlyEquals(num2), false);
+ QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveFull)
+ .strictlyEquals(num2), true);
+#endif
+}
+
+void tst_QJSValue::getSetProperty_twoEngines()
+{
+ QJSEngine engine;
+ QJSValue object = engine.newObject();
+
+ QJSEngine otherEngine;
+ QJSValue otherNum = QJSValue(&otherEngine, 123);
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setProperty(oof) failed: cannot set value created in a different engine");
+ object.setProperty("oof", otherNum);
+ QCOMPARE(object.property("oof").isValid(), false);
+}
+
+
+void tst_QJSValue::getSetProperty_gettersAndSetters()
+{
+#if 0 // FIXME: No setters/getters right now
+ QScriptEngine eng;
+ QJSValue str = QJSValue(&eng, QLatin1String("bar"));
+ QJSValue num = QJSValue(&eng, 123.0);
+ QJSValue object = eng.newObject();
+ for (int x = 0; x < 2; ++x) {
+ object.setProperty("foo", QJSValue());
+ // getter() returns this.x
+ object.setProperty("foo", eng.newFunction(getter),
+ QJSValue::PropertyGetter | QJSValue::UserRange);
+ QCOMPARE(object.propertyFlags("foo") & ~QJSValue::UserRange,
+ QJSValue::PropertyGetter );
+
+ QEXPECT_FAIL("", "QTBUG-17615: User-range flags are not retained for getter/setter properties", Continue);
+ QCOMPARE(object.propertyFlags("foo"),
+ QJSValue::PropertyGetter | QJSValue::UserRange);
+ object.setProperty("x", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+
+ // setter() sets this.x
+ object.setProperty("foo", eng.newFunction(setter),
+ QJSValue::PropertySetter);
+ QCOMPARE(object.propertyFlags("foo") & ~QJSValue::UserRange,
+ QJSValue::PropertySetter | QJSValue::PropertyGetter);
+
+ QCOMPARE(object.propertyFlags("foo"),
+ QJSValue::PropertySetter | QJSValue::PropertyGetter);
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("x").strictlyEquals(str), true);
+ QCOMPARE(object.property("foo").strictlyEquals(str), true);
+
+ // kill the getter
+ object.setProperty("foo", QJSValue(), QJSValue::PropertyGetter);
+ QVERIFY(!(object.propertyFlags("foo") & QJSValue::PropertyGetter));
+ QVERIFY(object.propertyFlags("foo") & QJSValue::PropertySetter);
+ QCOMPARE(object.property("foo").isUndefined(), true);
+
+ // setter should still work
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("x").strictlyEquals(num), true);
+
+ // kill the setter too
+ object.setProperty("foo", QJSValue(), QJSValue::PropertySetter);
+ QVERIFY(!(object.propertyFlags("foo") & QJSValue::PropertySetter));
+ // now foo is just a regular property
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("x").strictlyEquals(num), true);
+ QCOMPARE(object.property("foo").strictlyEquals(str), true);
+ }
+
+ for (int x = 0; x < 2; ++x) {
+ object.setProperty("foo", QJSValue());
+ // setter() sets this.x
+ object.setProperty("foo", eng.newFunction(setter), QJSValue::PropertySetter);
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("x").strictlyEquals(str), true);
+ QCOMPARE(object.property("foo").isUndefined(), true);
+
+ // getter() returns this.x
+ object.setProperty("foo", eng.newFunction(getter), QJSValue::PropertyGetter);
+ object.setProperty("x", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+
+ // kill the setter
+ object.setProperty("foo", QJSValue(), QJSValue::PropertySetter);
+ object.setProperty("foo", str);
+
+ // getter should still work
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+
+ // kill the getter too
+ object.setProperty("foo", QJSValue(), QJSValue::PropertyGetter);
+ // now foo is just a regular property
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("x").strictlyEquals(num), true);
+ QCOMPARE(object.property("foo").strictlyEquals(str), true);
+ }
+
+ // use a single function as both getter and setter
+ object.setProperty("foo", QJSValue());
+ object.setProperty("foo", eng.newFunction(getterSetter),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ QCOMPARE(object.propertyFlags("foo"),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ object.setProperty("x", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+
+ // killing the getter will preserve the setter, even though they are the same function
+ object.setProperty("foo", QJSValue(), QJSValue::PropertyGetter);
+ QVERIFY(object.propertyFlags("foo") & QJSValue::PropertySetter);
+ QCOMPARE(object.property("foo").isUndefined(), true);
+#endif
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersThrowErrorNative()
+{
+#if 0 // FIXME: No setters/getters right now
+ // getter/setter that throws an error
+ QScriptEngine eng;
+ QJSValue str = QJSValue(&eng, "bar");
+ QJSValue object = eng.newObject();
+
+ object.setProperty("foo", eng.newFunction(getterSetterThrowingError),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ QVERIFY(!eng.hasUncaughtException());
+ QJSValue ret = object.property("foo");
+ QVERIFY(ret.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+ QCOMPARE(ret.toString(), QLatin1String("Error: get foo"));
+ eng.evaluate("Object"); // clear exception state...
+ QVERIFY(!eng.hasUncaughtException());
+ object.setProperty("foo", str);
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: set foo"));
+#endif
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersThrowErrorJS()
+{
+ // getter/setter that throws an error (from js function)
+ QJSEngine eng;
+ QJSValue str = QJSValue(&eng, QLatin1String("bar"));
+
+ eng.evaluate("o = new Object; "
+ "o.__defineGetter__('foo', function() { throw new Error('get foo') }); "
+ "o.__defineSetter__('foo', function() { throw new Error('set foo') }); ");
+ QJSValue object = eng.evaluate("o");
+ QVERIFY(!eng.hasUncaughtException());
+ QJSValue ret = object.property("foo");
+ QVERIFY(ret.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+ QCOMPARE(ret.toString(), QLatin1String("Error: get foo"));
+ eng.evaluate("Object"); // clear exception state...
+ QVERIFY(!eng.hasUncaughtException());
+ object.setProperty("foo", str);
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: set foo"));
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersOnNative()
+{
+#if 0 // FIXME: No c-style functions right now
+ // attempt to install getter+setter on built-in (native) property
+ QScriptEngine eng;
+ QJSValue object = eng.newObject();
+ QVERIFY(object.property("__proto__").strictlyEquals(object.prototype()));
+
+ QJSValue fun = eng.newFunction(getSet__proto__);
+ fun.setProperty("value", QJSValue(&eng, "boo"));
+/* QTest::ignoreMessage(QtWarningMsg, "QJSValue::setProperty() failed: "
+ "cannot set getter or setter of native property "
+ "`__proto__'");*/
+ object.setProperty("__proto__", fun,
+ QJSValue::PropertyGetter | QJSValue::PropertySetter
+ | QJSValue::UserRange);
+ QVERIFY(object.property("__proto__").strictlyEquals(object.prototype()));
+
+ object.setProperty("__proto__", QJSValue(),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ QVERIFY(object.property("__proto__").strictlyEquals(object.prototype()));
+#endif
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersOnGlobalObject()
+{
+#if 0 // FIXME: No c-style functions right now
+ // global property that's a getter+setter
+ QScriptEngine eng;
+ eng.globalObject().setProperty("globalGetterSetterProperty", eng.newFunction(getterSetter),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ eng.evaluate("globalGetterSetterProperty = 123");
+ {
+ QJSValue ret = eng.evaluate("globalGetterSetterProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(QJSValue(&eng, 123)));
+ }
+ QCOMPARE(eng.evaluate("typeof globalGetterSetterProperty").toString(),
+ QString::fromLatin1("number"));
+ {
+ QJSValue ret = eng.evaluate("this.globalGetterSetterProperty()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Property 'globalGetterSetterProperty' of object #<Object> is not a function"));
+ }
+ {
+ QJSValue ret = eng.evaluate("new this.globalGetterSetterProperty()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: number is not a function"));
+ }
+#endif
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersChange()
+{
+#if 0 // FIXME: No setters/getters API right now
+ // "upgrading" an existing property to become a getter+setter
+ QScriptEngine eng;
+ QJSValue object = eng.newObject();
+ QJSValue num(&eng, 123);
+ object.setProperty("foo", num);
+ object.setProperty("foo", eng.newFunction(getterSetter),
+ QJSValue::PropertyGetter | QJSValue::PropertySetter);
+ QVERIFY(!object.property("x").isValid());
+ object.setProperty("foo", num);
+ QVERIFY(object.property("x").equals(num));
+
+ eng.globalObject().setProperty("object", object);
+ QJSValue res = eng.evaluate("object.x = 89; var a = object.foo; object.foo = 65; a");
+ QCOMPARE(res.toInt32(), 89);
+ QCOMPARE(object.property("x").toInt32(), 65);
+ QCOMPARE(object.property("foo").toInt32(), 65);
+#endif
+}
+
+void tst_QJSValue::getSetProperty_array()
+{
+ QJSEngine eng;
+ QJSValue str = QJSValue(&eng, QLatin1String("bar"));
+ QJSValue num = QJSValue(&eng, 123.0);
+ QJSValue array = eng.newArray();
+
+ QVERIFY(array.isArray());
+ array.setProperty(0, num);
+ QCOMPARE(array.property(0).toNumber(), num.toNumber());
+ QCOMPARE(array.property("0").toNumber(), num.toNumber());
+ QCOMPARE(array.property("length").toUInt32(), quint32(1));
+ array.setProperty(1, str);
+ QCOMPARE(array.property(1).toString(), str.toString());
+ QCOMPARE(array.property("1").toString(), str.toString());
+ QCOMPARE(array.property("length").toUInt32(), quint32(2));
+ array.setProperty("length", QJSValue(&eng, 1));
+ QCOMPARE(array.property("length").toUInt32(), quint32(1));
+ QCOMPARE(array.property(1).isValid(), false);
+}
+
+void tst_QJSValue::getSetProperty_gettersAndSettersStupid()
+{
+#if 0 // FIXME: No setters/getters API right now
+ //removing unexisting Setter or Getter should not crash.
+ QScriptEngine eng;
+ QJSValue num = QJSValue(&eng, 123.0);
+
+ {
+ QJSValue object = eng.newObject();
+ object.setProperty("foo", QJSValue(), QJSValue::PropertyGetter);
+ QVERIFY(!object.property("foo").isValid());
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ }
+
+ {
+ QJSValue object = eng.newObject();
+ object.setProperty("foo", QJSValue(), QJSValue::PropertySetter);
+ QVERIFY(!object.property("foo").isValid());
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ }
+
+ {
+ QJSValue object = eng.globalObject();
+ object.setProperty("foo", QJSValue(), QJSValue::PropertySetter);
+ object.setProperty("foo", QJSValue(), QJSValue::PropertyGetter);
+ QVERIFY(!object.property("foo").isValid());
+ object.setProperty("foo", num);
+ QCOMPARE(object.property("foo").strictlyEquals(num), true);
+ }
+#endif
+}
+
+void tst_QJSValue::getSetProperty()
+{
+ QJSEngine eng;
+
+ QJSValue object = eng.newObject();
+
+ QJSValue str = QJSValue(&eng, QLatin1String("bar"));
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("foo").toString(), str.toString());
+
+ QJSValue num = QJSValue(&eng, 123.0);
+ object.setProperty("baz", num);
+ QCOMPARE(object.property("baz").toNumber(), num.toNumber());
+
+ QJSValue strstr = QJSValue("bar");
+ QCOMPARE(strstr.engine(), (QJSEngine *)0);
+ object.setProperty("foo", strstr);
+ QCOMPARE(object.property("foo").toString(), strstr.toString());
+ QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
+
+ QJSValue numnum = QJSValue(123.0);
+ object.setProperty("baz", numnum);
+ QCOMPARE(object.property("baz").toNumber(), numnum.toNumber());
+
+ QJSValue inv;
+ inv.setProperty("foo", num);
+ QCOMPARE(inv.property("foo").isValid(), false);
+
+ eng.globalObject().setProperty("object", object);
+
+#if 0 // FIXME: no setProperty API with flags
+ // ReadOnly
+ object.setProperty("readOnlyProperty", num, QJSValue::ReadOnly);
+ QCOMPARE(object.propertyFlags("readOnlyProperty"), QJSValue::ReadOnly);
+ QCOMPARE(object.property("readOnlyProperty").strictlyEquals(num), true);
+ eng.evaluate("object.readOnlyProperty = !object.readOnlyProperty");
+ QCOMPARE(object.property("readOnlyProperty").strictlyEquals(num), true);
+ // should still be part of enumeration
+ {
+ QJSValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'readOnlyProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, true)), true);
+ }
+ // should still be deletable
+ {
+ QJSValue ret = eng.evaluate("delete object.readOnlyProperty");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, true)), true);
+ QCOMPARE(object.property("readOnlyProperty").isValid(), false);
+ }
+
+ // Undeletable
+ object.setProperty("undeletableProperty", num, QJSValue::Undeletable);
+ QCOMPARE(object.propertyFlags("undeletableProperty"), QJSValue::Undeletable);
+ QCOMPARE(object.property("undeletableProperty").strictlyEquals(num), true);
+ {
+ QJSValue ret = eng.evaluate("delete object.undeletableProperty");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, true)), false);
+ QCOMPARE(object.property("undeletableProperty").strictlyEquals(num), true);
+ }
+ // should still be writable
+ eng.evaluate("object.undeletableProperty = object.undeletableProperty + 1");
+ QCOMPARE(object.property("undeletableProperty").toNumber(), num.toNumber() + 1);
+ // should still be part of enumeration
+ {
+ QJSValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'undeletableProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, true)), true);
+ }
+ // should still be deletable from C++
+ object.setProperty("undeletableProperty", QJSValue());
+ QEXPECT_FAIL("", "QTBUG-17617: With JSC-based back-end, undeletable properties can't be deleted from C++", Continue);
+ QVERIFY(!object.property("undeletableProperty").isValid());
+ QEXPECT_FAIL("", "QTBUG-17617: With JSC-based back-end, undeletable properties can't be deleted from C++", Continue);
+ QCOMPARE(object.propertyFlags("undeletableProperty"), 0);
+
+ // SkipInEnumeration
+ object.setProperty("dontEnumProperty", num, QJSValue::SkipInEnumeration);
+ QCOMPARE(object.propertyFlags("dontEnumProperty"), QJSValue::SkipInEnumeration);
+ QCOMPARE(object.property("dontEnumProperty").strictlyEquals(num), true);
+ // should not be part of enumeration
+ {
+ QJSValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'dontEnumProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, false)), true);
+ }
+ // should still be writable
+ eng.evaluate("object.dontEnumProperty = object.dontEnumProperty + 1");
+ QCOMPARE(object.property("dontEnumProperty").toNumber(), num.toNumber() + 1);
+ // should still be deletable
+ {
+ QJSValue ret = eng.evaluate("delete object.dontEnumProperty");
+ QCOMPARE(ret.strictlyEquals(QJSValue(&eng, true)), true);
+ QCOMPARE(object.property("dontEnumProperty").isValid(), false);
+ }
+
+ // change flags
+ object.setProperty("flagProperty", str);
+ QCOMPARE(object.propertyFlags("flagProperty"), static_cast<QJSValue::PropertyFlags>(0));
+
+ QEXPECT_FAIL("", "FIXME: v8 does not support changing flags of existing properties", Continue);
+ //v8::i::JSObject::SetProperty(LookupResult* result, ... ) does not take in account the attributes
+ // if the result->isFound()
+ object.setProperty("flagProperty", str, QJSValue::ReadOnly);
+ QCOMPARE(object.propertyFlags("flagProperty"), QJSValue::ReadOnly);
+
+ QEXPECT_FAIL("", "FIXME: v8 does not support changing flags of existing properties", Continue);
+ object.setProperty("flagProperty", str, object.propertyFlags("flagProperty") | QJSValue::SkipInEnumeration);
+ QCOMPARE(object.propertyFlags("flagProperty"), QJSValue::ReadOnly | QJSValue::SkipInEnumeration);
+
+ QEXPECT_FAIL("", "FIXME: v8 does not support changing flags of existing properties", Continue);
+ object.setProperty("flagProperty", str, QJSValue::KeepExistingFlags);
+ QCOMPARE(object.propertyFlags("flagProperty"), QJSValue::ReadOnly | QJSValue::SkipInEnumeration);
+
+ QEXPECT_FAIL("", "FIXME: v8 does not support UserRange", Continue);
+ object.setProperty("flagProperty", str, QJSValue::UserRange);
+ QCOMPARE(object.propertyFlags("flagProperty"), QJSValue::UserRange);
+
+ // flags of property in the prototype
+ {
+ QJSValue object2 = eng.newObject();
+ object2.setPrototype(object);
+ QCOMPARE(object2.propertyFlags("flagProperty", QJSValue::ResolveLocal), 0);
+ QEXPECT_FAIL("", "FIXME: v8 does not support UserRange", Continue);
+ QCOMPARE(object2.propertyFlags("flagProperty"), QJSValue::UserRange);
+ }
+
+ // using interned strings
+ QScriptString foo = eng.toStringHandle("foo");
+
+ object.setProperty(foo, QJSValue());
+ QVERIFY(!object.property(foo).isValid());
+
+ object.setProperty(foo, num);
+ QVERIFY(object.property(foo).strictlyEquals(num));
+ QVERIFY(object.property("foo").strictlyEquals(num));
+ QVERIFY(object.propertyFlags(foo) == 0);
+#endif
+
+ // Setting index property on non-Array
+ object.setProperty(13, num);
+ QVERIFY(object.property(13).equals(num));
+}
+
+void tst_QJSValue::arrayElementGetterSetter()
+{
+#if 0 // FIXME: No c-style functions
+ QScriptEngine eng;
+ QJSValue obj = eng.newObject();
+ obj.setProperty(1, eng.newFunction(getterSetter), QJSValue::PropertyGetter|QJSValue::PropertySetter);
+ {
+ QJSValue num(123);
+ obj.setProperty("x", num);
+ QJSValue ret = obj.property(1);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.equals(num));
+ }
+ {
+ QJSValue num(456);
+ obj.setProperty(1, num);
+ QJSValue ret = obj.property(1);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.equals(num));
+ QVERIFY(ret.equals(obj.property("1")));
+ }
+ QCOMPARE(obj.propertyFlags("1"), QJSValue::PropertyGetter|QJSValue::PropertySetter);
+
+ obj.setProperty(1, QJSValue(), QJSValue::PropertyGetter|QJSValue::PropertySetter);
+ QVERIFY(obj.propertyFlags("1") == 0);
+#endif
+}
+
+void tst_QJSValue::getSetPrototype_cyclicPrototype()
+{
+ QJSEngine eng;
+ QJSValue prototype = eng.newObject();
+ QJSValue object = eng.newObject();
+ object.setPrototype(prototype);
+
+ QJSValue previousPrototype = prototype.prototype();
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setPrototype() failed: cyclic prototype value");
+ prototype.setPrototype(prototype);
+ QCOMPARE(prototype.prototype().strictlyEquals(previousPrototype), true);
+
+ object.setPrototype(prototype);
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setPrototype() failed: cyclic prototype value");
+ prototype.setPrototype(object);
+ QCOMPARE(prototype.prototype().strictlyEquals(previousPrototype), true);
+
+}
+
+void tst_QJSValue::getSetPrototype_evalCyclicPrototype()
+{
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), QLatin1String("Error: Cyclic __proto__ value"));
+}
+
+void tst_QJSValue::getSetPrototype_eval()
+{
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("p = { }; p.__proto__ = { }");
+ QCOMPARE(eng.hasUncaughtException(), false);
+ QCOMPARE(ret.isError(), false);
+}
+
+void tst_QJSValue::getSetPrototype_invalidPrototype()
+{
+ QJSEngine eng;
+ QJSValue inv;
+ QJSValue object = eng.newObject();
+ QJSValue proto = object.prototype();
+ QVERIFY(object.prototype().strictlyEquals(proto));
+ inv.setPrototype(object);
+ QCOMPARE(inv.prototype().isValid(), false);
+ object.setPrototype(inv);
+ QVERIFY(object.prototype().strictlyEquals(proto));
+}
+
+void tst_QJSValue::getSetPrototype_twoEngines()
+{
+ QJSEngine eng;
+ QJSValue prototype = eng.newObject();
+ QJSValue object = eng.newObject();
+ object.setPrototype(prototype);
+ QJSEngine otherEngine;
+ QJSValue newPrototype = otherEngine.newObject();
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ object.setPrototype(newPrototype);
+ QCOMPARE(object.prototype().strictlyEquals(prototype), true);
+
+}
+
+void tst_QJSValue::getSetPrototype_null()
+{
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ object.setPrototype(QJSValue(QJSValue::NullValue));
+ QVERIFY(object.prototype().isNull());
+
+ QJSValue newProto = eng.newObject();
+ object.setPrototype(newProto);
+ QVERIFY(object.prototype().equals(newProto));
+
+ object.setPrototype(QJSValue(&eng, QJSValue::NullValue));
+ QVERIFY(object.prototype().isNull());
+}
+
+void tst_QJSValue::getSetPrototype_notObjectOrNull()
+{
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ QJSValue originalProto = object.prototype();
+
+ // bool
+ object.setPrototype(true);
+ QVERIFY(object.prototype().equals(originalProto));
+ object.setPrototype(QJSValue(&eng, true));
+ QVERIFY(object.prototype().equals(originalProto));
+
+ // number
+ object.setPrototype(123);
+ QVERIFY(object.prototype().equals(originalProto));
+ object.setPrototype(QJSValue(&eng, 123));
+ QVERIFY(object.prototype().equals(originalProto));
+
+ // string
+ object.setPrototype("foo");
+ QVERIFY(object.prototype().equals(originalProto));
+ object.setPrototype(QJSValue(&eng, QLatin1String("foo")));
+ QVERIFY(object.prototype().equals(originalProto));
+
+ // undefined
+ object.setPrototype(QJSValue(QJSValue::UndefinedValue));
+ QVERIFY(object.prototype().equals(originalProto));
+ object.setPrototype(QJSValue(&eng, QJSValue::UndefinedValue));
+ QVERIFY(object.prototype().equals(originalProto));
+}
+
+void tst_QJSValue::getSetPrototype()
+{
+ QJSEngine eng;
+ QJSValue prototype = eng.newObject();
+ QJSValue object = eng.newObject();
+ object.setPrototype(prototype);
+ QCOMPARE(object.prototype().strictlyEquals(prototype), true);
+}
+
+void tst_QJSValue::getSetScope()
+{
+#if 0 // FIXME: No QJSValue::scope
+ QScriptEngine eng;
+
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.scope().isValid(), false);
+
+ QJSValue object2 = eng.newObject();
+ object2.setScope(object);
+
+ QEXPECT_FAIL("", "FIXME: scope not implemented yet", Abort);
+ QCOMPARE(object2.scope().strictlyEquals(object), true);
+
+ object.setProperty("foo", 123);
+ QVERIFY(!object2.property("foo").isValid());
+ {
+ QJSValue ret = object2.property("foo", QJSValue::ResolveScope);
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+
+ QJSValue inv;
+ inv.setScope(object);
+ QCOMPARE(inv.scope().isValid(), false);
+
+ QScriptEngine otherEngine;
+ QJSValue object3 = otherEngine.newObject();
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::setScope() failed: cannot set a scope object created in a different engine");
+ object2.setScope(object3);
+ QCOMPARE(object2.scope().strictlyEquals(object), true);
+
+ object2.setScope(QJSValue());
+ QVERIFY(!object2.scope().isValid());
+#endif
+}
+
+void tst_QJSValue::getSetData_objects_data()
+{
+#if 0 // FIXME: no setData/data API
+ newEngine();
+
+ QTest::addColumn<QJSValue>("object");
+
+ QTest::newRow("object from evaluate") << engine->evaluate("new Object()");
+ QTest::newRow("object from engine") << engine->newObject();
+ QTest::newRow("Array") << engine->newArray();
+ QTest::newRow("Date") << engine->newDate(12324);
+ QTest::newRow("QObject") << engine->newQObject(this);
+ QTest::newRow("RegExp") << engine->newRegExp(QRegExp());
+#endif
+}
+
+void tst_QJSValue::getSetData_objects()
+{
+#if 0 // FIXME: no setData/data API
+ QFETCH(QJSValue, object);
+
+ QVERIFY(!object.data().isValid());
+ QJSValue v1(true);
+ object.setData(v1);
+ QVERIFY(object.data().strictlyEquals(v1));
+ QJSValue v2(123);
+ object.setData(v2);
+ QVERIFY(object.data().strictlyEquals(v2));
+ QJSValue v3 = engine->newObject();
+ object.setData(v3);
+ QVERIFY(object.data().strictlyEquals(v3));
+ object.setData(QJSValue());
+ QVERIFY(!object.data().isValid());
+#endif
+}
+
+void tst_QJSValue::getSetData_nonObjects_data()
+{
+#if 0 // FIXME: no setData/data API
+ newEngine();
+
+ QTest::addColumn<QJSValue>("value");
+
+ QTest::newRow("undefined (bound)") << engine->undefinedValue();
+ QTest::newRow("null (bound)") << engine->nullValue();
+ QTest::newRow("string (bound)") << QJSValue(engine, "Pong");
+ QTest::newRow("bool (bound)") << QJSValue(engine, false);
+
+ QTest::newRow("undefined") << QJSValue(QJSValue::UndefinedValue);
+ QTest::newRow("null") << QJSValue(QJSValue::NullValue);
+ QTest::newRow("string") << QJSValue("Pong");
+ QTest::newRow("bool") << QJSValue(true);
+#endif
+}
+
+void tst_QJSValue::getSetData_nonObjects()
+{
+#if 0 // FIXME: no setData/data API
+ QFETCH(QJSValue, value);
+
+ QVERIFY(!value.data().isValid());
+ QJSValue v1(true);
+ value.setData(v1);
+ QVERIFY(!value.data().isValid());
+ QJSValue v2(123);
+ value.setData(v2);
+ QVERIFY(!value.data().isValid());
+ QJSValue v3 = engine->newObject();
+ value.setData(v3);
+ QVERIFY(!value.data().isValid());
+ value.setData(QJSValue());
+ QVERIFY(!value.data().isValid());
+#endif
+}
+
+void tst_QJSValue::setData_QTBUG15144()
+{
+#if 0 // FIXME: no setData/data API
+ QScriptEngine eng;
+ QJSValue obj = eng.newObject();
+ for (int i = 0; i < 10000; ++i) {
+ // Create an object with property 'fooN' on it, and immediately kill
+ // the reference to the object so it and the property name become garbage.
+ eng.evaluate(QString::fromLatin1("o = {}; o.foo%0 = 10; o = null;").arg(i));
+ // Setting the data will cause a JS string to be allocated, which could
+ // trigger a GC. This should not cause a crash.
+ obj.setData("foodfight");
+ }
+#endif
+}
+
+#if 0 // FIXME: no QScriptClass
+class TestScriptClass : public QScriptClass
+{
+public:
+ TestScriptClass(QScriptEngine *engine) : QScriptClass(engine) {}
+};
+
+void tst_QJSValue::getSetScriptClass_emptyClass_data()
+{
+ newEngine();
+ QTest::addColumn<QJSValue>("value");
+
+ QTest::newRow("invalid") << QJSValue();
+ QTest::newRow("number") << QJSValue(123);
+ QTest::newRow("string") << QJSValue("pong");
+ QTest::newRow("bool") << QJSValue(false);
+ QTest::newRow("null") << QJSValue(QJSValue::NullValue);
+ QTest::newRow("undefined") << QJSValue(QJSValue::UndefinedValue);
+
+ QTest::newRow("number") << QJSValue(engine, 123);
+ QTest::newRow("string") << QJSValue(engine, "pong");
+ QTest::newRow("bool") << QJSValue(engine, true);
+ QTest::newRow("null") << QJSValue(engine->nullValue());
+ QTest::newRow("undefined") << QJSValue(engine->undefinedValue());
+ QTest::newRow("object") << QJSValue(engine->newObject());
+ QTest::newRow("date") << QJSValue(engine->evaluate("new Date()"));
+ QTest::newRow("qobject") << QJSValue(engine->newQObject(this));
+}
+
+void tst_QJSValue::getSetScriptClass_emptyClass()
+{
+ QFETCH(QJSValue, value);
+ QCOMPARE(value.scriptClass(), (QScriptClass*)0);
+}
+
+void tst_QJSValue::getSetScriptClass_JSObjectFromCpp()
+{
+ QScriptEngine eng;
+ TestScriptClass testClass(&eng);
+ // object created in C++ (newObject())
+ {
+ QJSValue obj = eng.newObject();
+ obj.setScriptClass(&testClass);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)&testClass);
+ obj.setScriptClass(0);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)0);
+ }
+}
+
+void tst_QJSValue::getSetScriptClass_JSObjectFromJS()
+{
+ QScriptEngine eng;
+ TestScriptClass testClass(&eng);
+ // object created in JS
+ {
+ QJSValue obj = eng.evaluate("new Object");
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)0);
+ obj.setScriptClass(&testClass);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)&testClass);
+ obj.setScriptClass(0);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)0);
+ }
+}
+
+void tst_QJSValue::getSetScriptClass_QVariant()
+{
+ QScriptEngine eng;
+ TestScriptClass testClass(&eng);
+ // object that already has a(n internal) class
+ {
+ QJSValue obj = eng.newVariant(QUrl("http://example.com"));
+ QVERIFY(obj.isVariant());
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)0);
+ obj.setScriptClass(&testClass);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)&testClass);
+ QVERIFY(obj.isObject());
+ QVERIFY(!obj.isVariant());
+ QCOMPARE(obj.toVariant(), QVariant(QVariantMap()));
+ }
+}
+
+void tst_QJSValue::getSetScriptClass_QObject()
+{
+ QScriptEngine eng;
+ TestScriptClass testClass(&eng);
+ {
+ QJSValue obj = eng.newQObject(this);
+ QVERIFY(obj.isQObject());
+ obj.setScriptClass(&testClass);
+ QCOMPARE(obj.scriptClass(), (QScriptClass*)&testClass);
+ QVERIFY(obj.isObject());
+ QVERIFY(!obj.isQObject());
+ QVERIFY(obj.toQObject() == 0);
+ }
+}
+#endif
+
+#if 0 // FIXME: No c-style callbacks
+static QJSValue getArg(QScriptContext *ctx, QScriptEngine *)
+{
+ return ctx->argument(0);
+}
+
+static QJSValue evaluateArg(QScriptContext *, QScriptEngine *eng)
+{
+ return eng->evaluate("arguments[0]");
+}
+
+static QJSValue addArgs(QScriptContext *, QScriptEngine *eng)
+{
+ return eng->evaluate("arguments[0] + arguments[1]");
+}
+
+static QJSValue returnInvalidValue(QScriptContext *, QScriptEngine *)
+{
+ return QJSValue();
+}
+#endif
+
+void tst_QJSValue::call_function()
+{
+ QJSEngine eng;
+ QJSValue fun = eng.evaluate("(function() { return 1; })");
+ QVERIFY(fun.isFunction());
+ QJSValue result = fun.call();
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toInt32(), 1);
+}
+
+void tst_QJSValue::call_object()
+{
+ QJSEngine eng;
+ QJSValue Object = eng.evaluate("Object");
+ QCOMPARE(Object.isFunction(), true);
+ QJSValue result = Object.call(Object);
+ QCOMPARE(result.isObject(), true);
+}
+
+void tst_QJSValue::call_newObjects()
+{
+ QJSEngine eng;
+ // test that call() doesn't construct new objects
+ QJSValue Number = eng.evaluate("Number");
+ QJSValue Object = eng.evaluate("Object");
+ QCOMPARE(Object.isFunction(), true);
+ QJSValueList args;
+ args << QJSValue(&eng, 123);
+ QJSValue result = Number.call(Object, args);
+ QCOMPARE(result.strictlyEquals(args.at(0)), true);
+}
+
+void tst_QJSValue::call_this()
+{
+ QJSEngine eng;
+ // test that correct "this" object is used
+ QJSValue fun = eng.evaluate("(function() { return this; })");
+ QCOMPARE(fun.isFunction(), true);
+
+ QJSValue numberObject = QJSValue(&eng, 123.0).toObject();
+ QJSValue result = fun.call(numberObject);
+ QCOMPARE(result.isObject(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+}
+
+void tst_QJSValue::call_arguments()
+{
+ QJSEngine eng;
+ // test that correct arguments are passed
+
+ QJSValue fun = eng.evaluate("(function() { return arguments[0]; })");
+ QCOMPARE(fun.isFunction(), true);
+ {
+ QJSValue result = fun.call(eng.undefinedValue());
+ QCOMPARE(result.isUndefined(), true);
+ }
+ {
+ QJSValueList args;
+ args << QJSValue(&eng, 123.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+ // V2 constructors
+ {
+ QJSValueList args;
+ args << QJSValue(123.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+#if 0 // FIXME: The feature of interpreting a passed array as argument list has been removed from the API
+ {
+ QJSValue args = eng.newArray();
+ args.setProperty(0, 123);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+#endif
+}
+
+void tst_QJSValue::call()
+{
+ QJSEngine eng;
+ {
+ QJSValue fun = eng.evaluate("(function() { return arguments[1]; })");
+ QCOMPARE(fun.isFunction(), true);
+
+ {
+ QJSValueList args;
+ args << QJSValue(&eng, 123.0) << QJSValue(&eng, 456.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 456.0);
+ }
+#if 0 // FIXME: The feature of interpreting a passed array as argument list has been removed from the API
+ {
+ QJSValue args = eng.newArray();
+ args.setProperty(0, 123);
+ args.setProperty(1, 456);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toNumber(), 456.0);
+ }
+#endif
+ }
+ {
+ QJSValue fun = eng.evaluate("(function() { throw new Error('foo'); })");
+ QCOMPARE(fun.isFunction(), true);
+ QVERIFY(!eng.hasUncaughtException());
+
+ {
+ QJSValue result = fun.call();
+ QCOMPARE(result.isError(), true);
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QVERIFY(result.strictlyEquals(eng.uncaughtException()));
+ }
+ }
+#if 0 // FIXME: No c-style callbacks
+ {
+ eng.clearExceptions();
+ QJSValue fun = eng.newFunction(getArg);
+ {
+ QJSValueList args;
+ args << QJSValue(&eng, 123.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+ // V2 constructors
+ {
+ QJSValueList args;
+ args << QJSValue(123.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+#if 0 // FIXME: The feature of interpreting a passed array as argument list has been removed from the API
+ {
+ QJSValue args = eng.newArray();
+ args.setProperty(0, 123);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+#endif
+ }
+ {
+ QJSValue fun = eng.newFunction(evaluateArg);
+ {
+ QJSValueList args;
+ args << QJSValue(&eng, 123.0);
+ QJSValue result = fun.call(eng.undefinedValue(), args);
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toNumber(), 123.0);
+ }
+ }
+#endif
+}
+
+void tst_QJSValue::call_invalidArguments()
+{
+#if 0 // FIXME: No c-style callbacks
+ // test that invalid arguments are handled gracefully
+ QScriptEngine eng;
+ {
+ QJSValue fun = eng.newFunction(getArg);
+ {
+ QJSValueList args;
+ args << QJSValue();
+ QJSValue ret = fun.call(QJSValue(), args);
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(ret.isValid(), true);
+ QCOMPARE(ret.isUndefined(), true);
+ }
+ }
+ {
+ QJSValue fun = eng.newFunction(evaluateArg);
+ {
+ QJSValueList args;
+ args << QJSValue();
+ QJSValue ret = fun.call(QJSValue(), args);
+ QCOMPARE(ret.isValid(), true);
+ QCOMPARE(ret.isUndefined(), true);
+ }
+ }
+ {
+ QJSValue fun = eng.newFunction(addArgs);
+ {
+ QJSValueList args;
+ args << QJSValue() << QJSValue();
+ QJSValue ret = fun.call(QJSValue(), args);
+ QCOMPARE(ret.isValid(), true);
+ QCOMPARE(ret.isNumber(), true);
+ QCOMPARE(qIsNaN(ret.toNumber()), true);
+ }
+ }
+#endif
+}
+
+void tst_QJSValue::call_invalidReturn()
+{
+#if 0 // FIXME: No c-style callbacks
+ // test that invalid return value is handled gracefully
+ QScriptEngine eng;
+ QJSValue fun = eng.newFunction(returnInvalidValue);
+ eng.globalObject().setProperty("returnInvalidValue", fun);
+ QJSValue ret = eng.evaluate("returnInvalidValue() + returnInvalidValue()");
+ QCOMPARE(ret.isValid(), true);
+ QCOMPARE(ret.isNumber(), true);
+ QCOMPARE(qIsNaN(ret.toNumber()), true);
+#endif
+}
+
+void tst_QJSValue::call_twoEngines()
+{
+ QJSEngine eng;
+ QJSValue object = eng.evaluate("Object");
+ QJSEngine otherEngine;
+ QJSValue fun = otherEngine.evaluate("(function() { return 1; })");
+ QVERIFY(fun.isFunction());
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::call() failed: "
+ "cannot call function with thisObject created in "
+ "a different engine");
+ QCOMPARE(fun.call(object).isValid(), false);
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::call() failed: "
+ "cannot call function with argument created in "
+ "a different engine");
+ QCOMPARE(fun.call(QJSValue(), QJSValueList() << QJSValue(&eng, 123)).isValid(), false);
+ {
+ QJSValue fun = eng.evaluate("Object");
+ QVERIFY(fun.isFunction());
+ QJSEngine eng2;
+ QJSValue objectInDifferentEngine = eng2.newObject();
+ QJSValueList args;
+ args << objectInDifferentEngine;
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::call() failed: cannot call function with argument created in a different engine");
+ fun.call(QJSValue(), args);
+ }
+}
+
+void tst_QJSValue::call_array()
+{
+#if 0 // FIXME: The feature of interpreting an array as argument list has been removed from the API
+ QScriptEngine eng;
+ QJSValue fun = eng.evaluate("(function() { return arguments; })");
+ QVERIFY(fun.isFunction());
+ QJSValue array = eng.newArray(3);
+ array.setProperty(0, QJSValue(&eng, 123.0));
+ array.setProperty(1, QJSValue(&eng, 456.0));
+ array.setProperty(2, QJSValue(&eng, 789.0));
+ // call with single array object as arguments
+ QJSValue ret = fun.call(QJSValue(), array);
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(ret.isError(), false);
+ QCOMPARE(ret.property(0).strictlyEquals(array.property(0)), true);
+ QCOMPARE(ret.property(1).strictlyEquals(array.property(1)), true);
+ QCOMPARE(ret.property(2).strictlyEquals(array.property(2)), true);
+ // call with arguments object as arguments
+ QJSValue ret2 = fun.call(QJSValue(), ret);
+ QCOMPARE(ret2.isError(), false);
+ QCOMPARE(ret2.property(0).strictlyEquals(ret.property(0)), true);
+ QCOMPARE(ret2.property(1).strictlyEquals(ret.property(1)), true);
+ QCOMPARE(ret2.property(2).strictlyEquals(ret.property(2)), true);
+ // call with null as arguments
+ QJSValue ret3 = fun.call(QJSValue(), eng.nullValue());
+ QCOMPARE(ret3.isError(), false);
+ QCOMPARE(ret3.property("length").isNumber(), true);
+ QCOMPARE(ret3.property("length").toNumber(), 0.0);
+ // call with undefined as arguments
+ QJSValue ret4 = fun.call(QJSValue(), eng.undefinedValue());
+ QCOMPARE(ret4.isError(), false);
+ QCOMPARE(ret4.property("length").isNumber(), true);
+ QCOMPARE(ret4.property("length").toNumber(), 0.0);
+ // call with something else as arguments
+ QJSValue ret5 = fun.call(QJSValue(), QJSValue(&eng, 123.0));
+ QCOMPARE(ret5.isError(), true);
+ // call with a non-array object as arguments
+ QJSValue ret6 = fun.call(QJSValue(), eng.globalObject());
+ QVERIFY(ret6.isError());
+ QCOMPARE(ret6.toString(), QString::fromLatin1("TypeError: Arguments must be an array"));
+#endif
+}
+
+
+void tst_QJSValue::call_nonFunction_data()
+{
+ newEngine();
+ QTest::addColumn<QJSValue>("value");
+
+ QTest::newRow("invalid") << QJSValue();
+ QTest::newRow("bool") << QJSValue(false);
+ QTest::newRow("int") << QJSValue(123);
+ QTest::newRow("string") << QJSValue(QString::fromLatin1("ciao"));
+ QTest::newRow("undefined") << QJSValue(QJSValue::UndefinedValue);
+ QTest::newRow("null") << QJSValue(QJSValue::NullValue);
+
+ QTest::newRow("bool bound") << QJSValue(engine, false);
+ QTest::newRow("int bound") << QJSValue(engine, 123);
+ QTest::newRow("string bound") << QJSValue(engine, QString::fromLatin1("ciao"));
+ QTest::newRow("undefined bound") << engine->undefinedValue();
+ QTest::newRow("null bound") << engine->nullValue();
+}
+
+void tst_QJSValue::call_nonFunction()
+{
+ // calling things that are not functions
+ QFETCH(QJSValue, value);
+ QVERIFY(!value.call().isValid());
+}
+
+#if 0 // FIXME: no c-style callbacks
+static QJSValue ctorReturningUndefined(QScriptContext *ctx, QScriptEngine *)
+{
+ ctx->thisObject().setProperty("foo", 123);
+ return QJSValue(QJSValue::UndefinedValue);
+}
+
+static QJSValue ctorReturningNewObject(QScriptContext *, QScriptEngine *eng)
+{
+ QJSValue result = eng->newObject();
+ result.setProperty("bar", 456);
+ return result;
+}
+#endif
+
+void tst_QJSValue::construct_nonFunction_data()
+{
+ newEngine();
+ QTest::addColumn<QJSValue>("value");
+
+ QTest::newRow("invalid") << QJSValue();
+ QTest::newRow("bool") << QJSValue(false);
+ QTest::newRow("int") << QJSValue(123);
+ QTest::newRow("string") << QJSValue(QString::fromLatin1("ciao"));
+ QTest::newRow("undefined") << QJSValue(QJSValue::UndefinedValue);
+ QTest::newRow("null") << QJSValue(QJSValue::NullValue);
+
+ QTest::newRow("bool bound") << QJSValue(engine, false);
+ QTest::newRow("int bound") << QJSValue(engine, 123);
+ QTest::newRow("string bound") << QJSValue(engine, QString::fromLatin1("ciao"));
+ QTest::newRow("undefined bound") << engine->undefinedValue();
+ QTest::newRow("null bound") << engine->nullValue();
+}
+
+void tst_QJSValue::construct_nonFunction()
+{
+ QFETCH(QJSValue, value);
+ QVERIFY(!value.construct().isValid());
+}
+
+void tst_QJSValue::construct_simple()
+{
+ QJSEngine eng;
+ QJSValue fun = eng.evaluate("(function () { this.foo = 123; })");
+ QVERIFY(fun.isFunction());
+ QJSValue ret = fun.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.instanceOf(fun));
+ QCOMPARE(ret.property("foo").toInt32(), 123);
+}
+
+void tst_QJSValue::construct_newObjectJS()
+{
+ QJSEngine eng;
+ // returning a different object overrides the default-constructed one
+ QJSValue fun = eng.evaluate("(function () { return { bar: 456 }; })");
+ QVERIFY(fun.isFunction());
+ QJSValue ret = fun.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(!ret.instanceOf(fun));
+ QCOMPARE(ret.property("bar").toInt32(), 456);
+}
+
+#if 0 // FIXME: no c-style callbacks
+void tst_QJSValue::construct_undefined()
+{
+ QScriptEngine eng;
+ QJSValue fun = eng.newFunction(ctorReturningUndefined);
+ QJSValue ret = fun.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.instanceOf(fun));
+ QCOMPARE(ret.property("foo").toInt32(), 123);
+}
+
+void tst_QJSValue::construct_newObjectCpp()
+{
+ QScriptEngine eng;
+ QJSValue fun = eng.newFunction(ctorReturningNewObject);
+ QJSValue ret = fun.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(!ret.instanceOf(fun));
+ QCOMPARE(ret.property("bar").toInt32(), 456);
+}
+#endif
+
+void tst_QJSValue::construct_arg()
+{
+ QJSEngine eng;
+ QJSValue Number = eng.evaluate("Number");
+ QCOMPARE(Number.isFunction(), true);
+ QJSValueList args;
+ args << QJSValue(&eng, 123);
+ QJSValue ret = Number.construct(args);
+ QCOMPARE(ret.isObject(), true);
+ QCOMPARE(ret.toNumber(), args.at(0).toNumber());
+}
+
+void tst_QJSValue::construct_proto()
+{
+ QJSEngine eng;
+ // test that internal prototype is set correctly
+ QJSValue fun = eng.evaluate("(function() { return this.__proto__; })");
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.property("prototype").isObject(), true);
+ QJSValue ret = fun.construct();
+ QCOMPARE(fun.property("prototype").strictlyEquals(ret), true);
+}
+
+void tst_QJSValue::construct_returnInt()
+{
+ QJSEngine eng;
+ // test that we return the new object even if a non-object value is returned from the function
+ QJSValue fun = eng.evaluate("(function() { return 123; })");
+ QCOMPARE(fun.isFunction(), true);
+ QJSValue ret = fun.construct();
+ QCOMPARE(ret.isObject(), true);
+}
+
+void tst_QJSValue::construct_throw()
+{
+ QJSEngine eng;
+ QJSValue fun = eng.evaluate("(function() { throw new Error('foo'); })");
+ QCOMPARE(fun.isFunction(), true);
+ QJSValue ret = fun.construct();
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+}
+
+#if 0 // FIXME: The feature of interpreting an array as argument list has been removed from the API
+void tst_QJSValue::construct()
+{
+ QScriptEngine eng;
+ QJSValue fun = eng.evaluate("(function() { return arguments; })");
+ QVERIFY(fun.isFunction());
+ QJSValue array = eng.newArray(3);
+ array.setProperty(0, QJSValue(&eng, 123.0));
+ array.setProperty(1, QJSValue(&eng, 456.0));
+ array.setProperty(2, QJSValue(&eng, 789.0));
+ // construct with single array object as arguments
+ QJSValue ret = fun.construct(array);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.property(0).strictlyEquals(array.property(0)), true);
+ QCOMPARE(ret.property(1).strictlyEquals(array.property(1)), true);
+ QCOMPARE(ret.property(2).strictlyEquals(array.property(2)), true);
+ // construct with arguments object as arguments
+ QJSValue ret2 = fun.construct(ret);
+ QCOMPARE(ret2.property(0).strictlyEquals(ret.property(0)), true);
+ QCOMPARE(ret2.property(1).strictlyEquals(ret.property(1)), true);
+ QCOMPARE(ret2.property(2).strictlyEquals(ret.property(2)), true);
+ // construct with null as arguments
+ QJSValue ret3 = fun.construct(eng.nullValue());
+ QCOMPARE(ret3.isError(), false);
+ QCOMPARE(ret3.property("length").isNumber(), true);
+ QCOMPARE(ret3.property("length").toNumber(), 0.0);
+ // construct with undefined as arguments
+ QJSValue ret4 = fun.construct(eng.undefinedValue());
+ QCOMPARE(ret4.isError(), false);
+ QCOMPARE(ret4.property("length").isNumber(), true);
+ QCOMPARE(ret4.property("length").toNumber(), 0.0);
+ // construct with something else as arguments
+ QJSValue ret5 = fun.construct(QJSValue(&eng, 123.0));
+ QCOMPARE(ret5.isError(), true);
+ // construct with a non-array object as arguments
+ QJSValue ret6 = fun.construct(eng.globalObject());
+ QVERIFY(ret6.isError());
+ QCOMPARE(ret6.toString(), QString::fromLatin1("TypeError: Arguments must be an array"));
+}
+#endif
+
+void tst_QJSValue::construct_twoEngines()
+{
+ QJSEngine engine;
+ QJSEngine otherEngine;
+ QJSValue ctor = engine.evaluate("(function (a, b) { this.foo = 123; })");
+ QJSValue arg(&otherEngine, 124567);
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::construct() failed: cannot construct function with argument created in a different engine");
+ QVERIFY(!ctor.construct(QJSValueList() << arg).isValid());
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::construct() failed: cannot construct function with argument created in a different engine");
+ QVERIFY(!ctor.construct(QJSValueList() << arg << otherEngine.newObject()).isValid());
+}
+
+void tst_QJSValue::construct_constructorThrowsPrimitive()
+{
+ QJSEngine eng;
+ QJSValue fun = eng.evaluate("(function() { throw 123; })");
+ QVERIFY(fun.isFunction());
+ // construct(QJSValueList)
+ {
+ QJSValue ret = fun.construct();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), 123.0);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+ eng.clearExceptions();
+ }
+#if 0 // FIXME: The feature of interpreting an array as argument list has been removed from the API
+ // construct(QJSValue)
+ {
+ QJSValue ret = fun.construct(eng.newArray());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), 123.0);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(eng.uncaughtException()));
+ eng.clearExceptions();
+ }
+#endif
+}
+
+#if 0 // FIXME: No QJSValue::lessThan
+void tst_QJSValue::lessThan()
+{
+ QScriptEngine eng;
+
+ QVERIFY(!QJSValue().lessThan(QJSValue()));
+
+ QJSValue num = QJSValue(&eng, 123);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 124)), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 122)), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 123)), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "124")), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "122")), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "123")), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, qSNaN())), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, +qInf())), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, -qInf())), false);
+ QCOMPARE(num.lessThan(num), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 124).toObject()), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 122).toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, 123).toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "124").toObject()), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "122").toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, "123").toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, qSNaN()).toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue(&eng, +qInf()).toObject()), true);
+ QCOMPARE(num.lessThan(QJSValue(&eng, -qInf()).toObject()), false);
+ QCOMPARE(num.lessThan(num.toObject()), false);
+ QCOMPARE(num.lessThan(QJSValue()), false);
+
+ QJSValue str = QJSValue(&eng, "123");
+ QCOMPARE(str.lessThan(QJSValue(&eng, "124")), true);
+ QCOMPARE(str.lessThan(QJSValue(&eng, "122")), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, "123")), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 124)), true);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 122)), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 123)), false);
+ QCOMPARE(str.lessThan(str), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, "124").toObject()), true);
+ QCOMPARE(str.lessThan(QJSValue(&eng, "122").toObject()), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, "123").toObject()), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 124).toObject()), true);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 122).toObject()), false);
+ QCOMPARE(str.lessThan(QJSValue(&eng, 123).toObject()), false);
+ QCOMPARE(str.lessThan(str.toObject()), false);
+ QCOMPARE(str.lessThan(QJSValue()), false);
+
+ // V2 constructors
+ QJSValue num2 = QJSValue(123);
+ QCOMPARE(num2.lessThan(QJSValue(124)), true);
+ QCOMPARE(num2.lessThan(QJSValue(122)), false);
+ QCOMPARE(num2.lessThan(QJSValue(123)), false);
+ QCOMPARE(num2.lessThan(QJSValue("124")), true);
+ QCOMPARE(num2.lessThan(QJSValue("122")), false);
+ QCOMPARE(num2.lessThan(QJSValue("123")), false);
+ QCOMPARE(num2.lessThan(QJSValue(qSNaN())), false);
+ QCOMPARE(num2.lessThan(QJSValue(+qInf())), true);
+ QCOMPARE(num2.lessThan(QJSValue(-qInf())), false);
+ QCOMPARE(num2.lessThan(num), false);
+ QCOMPARE(num2.lessThan(QJSValue()), false);
+
+ QJSValue str2 = QJSValue("123");
+ QCOMPARE(str2.lessThan(QJSValue("124")), true);
+ QCOMPARE(str2.lessThan(QJSValue("122")), false);
+ QCOMPARE(str2.lessThan(QJSValue("123")), false);
+ QCOMPARE(str2.lessThan(QJSValue(124)), true);
+ QCOMPARE(str2.lessThan(QJSValue(122)), false);
+ QCOMPARE(str2.lessThan(QJSValue(123)), false);
+ QCOMPARE(str2.lessThan(str), false);
+ QCOMPARE(str2.lessThan(QJSValue()), false);
+
+ QJSValue obj1 = eng.newObject();
+ QJSValue obj2 = eng.newObject();
+ QCOMPARE(obj1.lessThan(obj2), false);
+ QCOMPARE(obj2.lessThan(obj1), false);
+ QCOMPARE(obj1.lessThan(obj1), false);
+ QCOMPARE(obj2.lessThan(obj2), false);
+
+ QJSValue date1 = eng.newDate(QDateTime(QDate(2000, 1, 1)));
+ QJSValue date2 = eng.newDate(QDateTime(QDate(1999, 1, 1)));
+ QCOMPARE(date1.lessThan(date2), false);
+ QCOMPARE(date2.lessThan(date1), true);
+ QCOMPARE(date1.lessThan(date1), false);
+ QCOMPARE(date2.lessThan(date2), false);
+ QCOMPARE(date1.lessThan(QJSValue()), false);
+
+ QCOMPARE(QJSValue().lessThan(date2), false);
+
+ QScriptEngine otherEngine;
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::lessThan: "
+ "cannot compare to a value created in "
+ "a different engine");
+ QCOMPARE(date1.lessThan(QJSValue(&otherEngine, 123)), false);
+}
+#endif
+
+void tst_QJSValue::equals()
+{
+ QJSEngine eng;
+
+ QVERIFY(QJSValue().equals(QJSValue()));
+
+ QJSValue num = QJSValue(&eng, 123);
+ QCOMPARE(num.equals(QJSValue(&eng, 123)), true);
+ QCOMPARE(num.equals(QJSValue(&eng, 321)), false);
+ QCOMPARE(num.equals(QJSValue(&eng, QLatin1String("123"))), true);
+ QCOMPARE(num.equals(QJSValue(&eng, QLatin1String("321"))), false);
+ QCOMPARE(num.equals(QJSValue(&eng, 123).toObject()), true);
+ QCOMPARE(num.equals(QJSValue(&eng, 321).toObject()), false);
+ QCOMPARE(num.equals(QJSValue(&eng, QLatin1String("123")).toObject()), true);
+ QCOMPARE(num.equals(QJSValue(&eng, QLatin1String("321")).toObject()), false);
+ QVERIFY(num.toObject().equals(num));
+ QCOMPARE(num.equals(QJSValue()), false);
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123"));
+ QCOMPARE(str.equals(QJSValue(&eng, QLatin1String("123"))), true);
+ QCOMPARE(str.equals(QJSValue(&eng, QLatin1String("321"))), false);
+ QCOMPARE(str.equals(QJSValue(&eng, 123)), true);
+ QCOMPARE(str.equals(QJSValue(&eng, 321)), false);
+ QCOMPARE(str.equals(QJSValue(&eng, QLatin1String("123")).toObject()), true);
+ QCOMPARE(str.equals(QJSValue(&eng, QLatin1String("321")).toObject()), false);
+ QCOMPARE(str.equals(QJSValue(&eng, 123).toObject()), true);
+ QCOMPARE(str.equals(QJSValue(&eng, 321).toObject()), false);
+ QVERIFY(str.toObject().equals(str));
+ QCOMPARE(str.equals(QJSValue()), false);
+
+ QJSValue num2 = QJSValue(123);
+ QCOMPARE(num2.equals(QJSValue(123)), true);
+ QCOMPARE(num2.equals(QJSValue(321)), false);
+ QCOMPARE(num2.equals(QJSValue("123")), true);
+ QCOMPARE(num2.equals(QJSValue("321")), false);
+ QCOMPARE(num2.equals(QJSValue()), false);
+
+ QJSValue str2 = QJSValue("123");
+ QCOMPARE(str2.equals(QJSValue("123")), true);
+ QCOMPARE(str2.equals(QJSValue("321")), false);
+ QCOMPARE(str2.equals(QJSValue(123)), true);
+ QCOMPARE(str2.equals(QJSValue(321)), false);
+ QCOMPARE(str2.equals(QJSValue()), false);
+
+ QJSValue date1 = eng.newDate(QDateTime(QDate(2000, 1, 1)));
+ QJSValue date2 = eng.newDate(QDateTime(QDate(1999, 1, 1)));
+ QCOMPARE(date1.equals(date2), false);
+ QCOMPARE(date1.equals(date1), true);
+ QCOMPARE(date2.equals(date2), true);
+
+ QJSValue undefined = eng.undefinedValue();
+ QJSValue null = eng.nullValue();
+ QCOMPARE(undefined.equals(undefined), true);
+ QCOMPARE(null.equals(null), true);
+ QCOMPARE(undefined.equals(null), true);
+ QCOMPARE(null.equals(undefined), true);
+ QCOMPARE(undefined.equals(QJSValue()), false);
+ QCOMPARE(null.equals(QJSValue()), false);
+ QVERIFY(!null.equals(num));
+ QVERIFY(!undefined.equals(num));
+
+ QJSValue sant = QJSValue(&eng, true);
+ QVERIFY(sant.equals(QJSValue(&eng, 1)));
+ QVERIFY(sant.equals(QJSValue(&eng, QLatin1String("1"))));
+ QVERIFY(sant.equals(sant));
+ QVERIFY(sant.equals(QJSValue(&eng, 1).toObject()));
+ QVERIFY(sant.equals(QJSValue(&eng, QLatin1String("1")).toObject()));
+ QVERIFY(sant.equals(sant.toObject()));
+ QVERIFY(sant.toObject().equals(sant));
+ QVERIFY(!sant.equals(QJSValue(&eng, 0)));
+ QVERIFY(!sant.equals(undefined));
+ QVERIFY(!sant.equals(null));
+
+ QJSValue falskt = QJSValue(&eng, false);
+ QVERIFY(falskt.equals(QJSValue(&eng, 0)));
+ QVERIFY(falskt.equals(QJSValue(&eng, QLatin1String("0"))));
+ QVERIFY(falskt.equals(falskt));
+ QVERIFY(falskt.equals(QJSValue(&eng, 0).toObject()));
+ QVERIFY(falskt.equals(QJSValue(&eng, QLatin1String("0")).toObject()));
+ QVERIFY(falskt.equals(falskt.toObject()));
+ QVERIFY(falskt.toObject().equals(falskt));
+ QVERIFY(!falskt.equals(sant));
+ QVERIFY(!falskt.equals(undefined));
+ QVERIFY(!falskt.equals(null));
+
+ QJSValue obj1 = eng.newObject();
+ QJSValue obj2 = eng.newObject();
+ QCOMPARE(obj1.equals(obj2), false);
+ QCOMPARE(obj2.equals(obj1), false);
+ QCOMPARE(obj1.equals(obj1), true);
+ QCOMPARE(obj2.equals(obj2), true);
+
+ QJSValue qobj1 = eng.newQObject(this);
+ QJSValue qobj2 = eng.newQObject(this);
+ QJSValue qobj3 = eng.newQObject(0);
+
+ // FIXME: No ScriptOwnership: QJSValue qobj4 = eng.newQObject(new QObject(), QScriptEngine::ScriptOwnership);
+ QJSValue qobj4 = eng.newQObject(new QObject());
+
+ QVERIFY(qobj1.equals(qobj2)); // compares the QObject pointers
+ QVERIFY(!qobj2.equals(qobj4)); // compares the QObject pointers
+ QVERIFY(!qobj2.equals(obj2)); // compares the QObject pointers
+
+ QJSValue compareFun = eng.evaluate("(function(a, b) { return a == b; })");
+ QVERIFY(compareFun.isFunction());
+ {
+ QJSValue ret = compareFun.call(QJSValue(), QJSValueList() << qobj1 << qobj2);
+ QVERIFY(ret.isBool());
+ ret = compareFun.call(QJSValue(), QJSValueList() << qobj1 << qobj3);
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ ret = compareFun.call(QJSValue(), QJSValueList() << qobj1 << qobj4);
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ ret = compareFun.call(QJSValue(), QJSValueList() << qobj1 << obj1);
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+
+ {
+ QJSValue var1 = eng.newVariant(QVariant(false));
+ QJSValue var2 = eng.newVariant(QVariant(false));
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ {
+ QJSValue ret = compareFun.call(QJSValue(), QJSValueList() << var1 << var2);
+ QVERIFY(ret.isBool());
+ }
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(false));
+ QJSValue var2 = eng.newVariant(QVariant(0));
+ // QVariant::operator==() performs type conversion
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QStringList() << "a"));
+ QJSValue var2 = eng.newVariant(QVariant(QStringList() << "a"));
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QStringList() << "a"));
+ QJSValue var2 = eng.newVariant(QVariant(QStringList() << "b"));
+ QVERIFY(!var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QJSValue var2 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QJSValue var2 = eng.newVariant(QVariant(QPoint(3, 4)));
+ QVERIFY(!var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(int(1)));
+ QJSValue var2 = eng.newVariant(QVariant(double(1)));
+ // QVariant::operator==() performs type conversion
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QString::fromLatin1("123")));
+ QJSValue var2 = eng.newVariant(QVariant(double(123)));
+ QJSValue var3(QString::fromLatin1("123"));
+ QJSValue var4(123);
+
+ QVERIFY(var1.equals(var1));
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var1.equals(var2));
+ QVERIFY(var1.equals(var3));
+ QVERIFY(var1.equals(var4));
+
+ QEXPECT_FAIL("", "FIXME: QVariant comparison does not work with v8", Continue);
+ QVERIFY(var2.equals(var1));
+ QVERIFY(var2.equals(var2));
+ QVERIFY(var2.equals(var3));
+ QVERIFY(var2.equals(var4));
+
+ QVERIFY(var3.equals(var1));
+ QVERIFY(var3.equals(var2));
+ QVERIFY(var3.equals(var3));
+ QVERIFY(var3.equals(var4));
+
+ QVERIFY(var4.equals(var1));
+ QVERIFY(var4.equals(var2));
+ QVERIFY(var4.equals(var3));
+ QVERIFY(var4.equals(var4));
+ }
+
+ QJSEngine otherEngine;
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::equals: "
+ "cannot compare to a value created in "
+ "a different engine");
+ QCOMPARE(date1.equals(QJSValue(&otherEngine, 123)), false);
+}
+
+void tst_QJSValue::strictlyEquals()
+{
+ QJSEngine eng;
+
+ QVERIFY(QJSValue().strictlyEquals(QJSValue()));
+
+ QJSValue num = QJSValue(&eng, 123);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123)), true);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 321)), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, QLatin1String("123"))), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, QLatin1String("321"))), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123).toObject()), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 321).toObject()), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, QLatin1String("123")).toObject()), false);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, QLatin1String("321")).toObject()), false);
+ QVERIFY(!num.toObject().strictlyEquals(num));
+ QVERIFY(!num.strictlyEquals(QJSValue()));
+ QVERIFY(!QJSValue().strictlyEquals(num));
+
+ QJSValue str = QJSValue(&eng, QLatin1String("123"));
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, QLatin1String("123"))), true);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, QLatin1String("321"))), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, 123)), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, 321)), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, QLatin1String("123")).toObject()), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, QLatin1String("321")).toObject()), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, 123).toObject()), false);
+ QCOMPARE(str.strictlyEquals(QJSValue(&eng, 321).toObject()), false);
+ QVERIFY(!str.toObject().strictlyEquals(str));
+ QVERIFY(!str.strictlyEquals(QJSValue()));
+
+ QJSValue num2 = QJSValue(123);
+ QCOMPARE(num2.strictlyEquals(QJSValue(123)), true);
+ QCOMPARE(num2.strictlyEquals(QJSValue(321)), false);
+ QCOMPARE(num2.strictlyEquals(QJSValue("123")), false);
+ QCOMPARE(num2.strictlyEquals(QJSValue("321")), false);
+ QVERIFY(!num2.strictlyEquals(QJSValue()));
+
+ QJSValue str2 = QJSValue("123");
+ QCOMPARE(str2.strictlyEquals(QJSValue("123")), true);
+ QCOMPARE(str2.strictlyEquals(QJSValue("321")), false);
+ QCOMPARE(str2.strictlyEquals(QJSValue(123)), false);
+ QCOMPARE(str2.strictlyEquals(QJSValue(321)), false);
+ QVERIFY(!str2.strictlyEquals(QJSValue()));
+
+ QJSValue date1 = eng.newDate(QDateTime(QDate(2000, 1, 1)));
+ QJSValue date2 = eng.newDate(QDateTime(QDate(1999, 1, 1)));
+ QCOMPARE(date1.strictlyEquals(date2), false);
+ QCOMPARE(date1.strictlyEquals(date1), true);
+ QCOMPARE(date2.strictlyEquals(date2), true);
+ QVERIFY(!date1.strictlyEquals(QJSValue()));
+
+ QJSValue undefined = eng.undefinedValue();
+ QJSValue null = eng.nullValue();
+ QCOMPARE(undefined.strictlyEquals(undefined), true);
+ QCOMPARE(null.strictlyEquals(null), true);
+ QCOMPARE(undefined.strictlyEquals(null), false);
+ QCOMPARE(null.strictlyEquals(undefined), false);
+ QVERIFY(!null.strictlyEquals(QJSValue()));
+
+ QJSValue sant = QJSValue(&eng, true);
+ QVERIFY(!sant.strictlyEquals(QJSValue(&eng, 1)));
+ QVERIFY(!sant.strictlyEquals(QJSValue(&eng, QLatin1String("1"))));
+ QVERIFY(sant.strictlyEquals(sant));
+ QVERIFY(!sant.strictlyEquals(QJSValue(&eng, 1).toObject()));
+ QVERIFY(!sant.strictlyEquals(QJSValue(&eng, QLatin1String("1")).toObject()));
+ QVERIFY(!sant.strictlyEquals(sant.toObject()));
+ QVERIFY(!sant.toObject().strictlyEquals(sant));
+ QVERIFY(!sant.strictlyEquals(QJSValue(&eng, 0)));
+ QVERIFY(!sant.strictlyEquals(undefined));
+ QVERIFY(!sant.strictlyEquals(null));
+ QVERIFY(!sant.strictlyEquals(QJSValue()));
+
+ QJSValue falskt = QJSValue(&eng, false);
+ QVERIFY(!falskt.strictlyEquals(QJSValue(&eng, 0)));
+ QVERIFY(!falskt.strictlyEquals(QJSValue(&eng, QLatin1String("0"))));
+ QVERIFY(falskt.strictlyEquals(falskt));
+ QVERIFY(!falskt.strictlyEquals(QJSValue(&eng, 0).toObject()));
+ QVERIFY(!falskt.strictlyEquals(QJSValue(&eng, QLatin1String("0")).toObject()));
+ QVERIFY(!falskt.strictlyEquals(falskt.toObject()));
+ QVERIFY(!falskt.toObject().strictlyEquals(falskt));
+ QVERIFY(!falskt.strictlyEquals(sant));
+ QVERIFY(!falskt.strictlyEquals(undefined));
+ QVERIFY(!falskt.strictlyEquals(null));
+ QVERIFY(!falskt.strictlyEquals(QJSValue()));
+
+ QVERIFY(!QJSValue(false).strictlyEquals(123));
+ QVERIFY(!QJSValue(QJSValue::UndefinedValue).strictlyEquals(123));
+ QVERIFY(!QJSValue(QJSValue::NullValue).strictlyEquals(123));
+ QVERIFY(!QJSValue(false).strictlyEquals("ciao"));
+ QVERIFY(!QJSValue(QJSValue::UndefinedValue).strictlyEquals("ciao"));
+ QVERIFY(!QJSValue(QJSValue::NullValue).strictlyEquals("ciao"));
+ QVERIFY(QJSValue(&eng, QLatin1String("ciao")).strictlyEquals("ciao"));
+ QVERIFY(QJSValue("ciao").strictlyEquals(QJSValue(&eng, QLatin1String("ciao"))));
+ QVERIFY(!QJSValue("ciao").strictlyEquals(123));
+ QVERIFY(!QJSValue("ciao").strictlyEquals(QJSValue(&eng, 123)));
+ QVERIFY(!QJSValue(123).strictlyEquals("ciao"));
+ QVERIFY(!QJSValue(123).strictlyEquals(QJSValue(&eng, QLatin1String("ciao"))));
+ QVERIFY(!QJSValue(&eng, 123).strictlyEquals("ciao"));
+
+ QJSValue obj1 = eng.newObject();
+ QJSValue obj2 = eng.newObject();
+ QCOMPARE(obj1.strictlyEquals(obj2), false);
+ QCOMPARE(obj2.strictlyEquals(obj1), false);
+ QCOMPARE(obj1.strictlyEquals(obj1), true);
+ QCOMPARE(obj2.strictlyEquals(obj2), true);
+ QVERIFY(!obj1.strictlyEquals(QJSValue()));
+
+ QJSValue qobj1 = eng.newQObject(this);
+ QJSValue qobj2 = eng.newQObject(this);
+ QVERIFY(qobj1.strictlyEquals(qobj2));
+
+ {
+ QJSValue var1 = eng.newVariant(QVariant(false));
+ QJSValue var2 = eng.newVariant(QVariant(false));
+ QVERIFY(!var1.strictlyEquals(var2));
+ QVERIFY(!var1.strictlyEquals(QJSValue()));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(false));
+ QJSValue var2 = eng.newVariant(QVariant(0));
+ QVERIFY(!var1.strictlyEquals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QStringList() << "a"));
+ QJSValue var2 = eng.newVariant(QVariant(QStringList() << "a"));
+ QVERIFY(!var1.strictlyEquals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QStringList() << "a"));
+ QJSValue var2 = eng.newVariant(QVariant(QStringList() << "b"));
+ QVERIFY(!var1.strictlyEquals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QJSValue var2 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QVERIFY(!var1.strictlyEquals(var2));
+ }
+ {
+ QJSValue var1 = eng.newVariant(QVariant(QPoint(1, 2)));
+ QJSValue var2 = eng.newVariant(QVariant(QPoint(3, 4)));
+ QVERIFY(!var1.strictlyEquals(var2));
+ }
+
+ QJSEngine otherEngine;
+ QTest::ignoreMessage(QtWarningMsg, "QJSValue::strictlyEquals: "
+ "cannot compare to a value created in "
+ "a different engine");
+ QCOMPARE(date1.strictlyEquals(QJSValue(&otherEngine, 123)), false);
+}
+
+Q_DECLARE_METATYPE(int*)
+Q_DECLARE_METATYPE(double*)
+Q_DECLARE_METATYPE(QColor*)
+Q_DECLARE_METATYPE(QBrush*)
+
+void tst_QJSValue::castToPointer()
+{
+ QJSEngine eng;
+ {
+ QJSValue v = eng.newVariant(int(123));
+ int *ip = qjsvalue_cast<int*>(v);
+ QVERIFY(ip != 0);
+ QCOMPARE(*ip, 123);
+ QEXPECT_FAIL("", "Pointer magic for variants is currently not supported by QJSEngine", Abort);
+ *ip = 456;
+ QCOMPARE(qjsvalue_cast<int>(v), 456);
+
+ double *dp = qjsvalue_cast<double*>(v);
+ QVERIFY(dp == 0);
+
+ QJSValue v2 = eng.newVariant(qVariantFromValue(ip));
+ QCOMPARE(qjsvalue_cast<int*>(v2), ip);
+ }
+ {
+ QColor c(123, 210, 231);
+ QJSValue v = eng.newVariant(c);
+ QColor *cp = qjsvalue_cast<QColor*>(v);
+ QVERIFY(cp != 0);
+ QCOMPARE(*cp, c);
+
+ QBrush *bp = qjsvalue_cast<QBrush*>(v);
+ QVERIFY(bp == 0);
+
+ QJSValue v2 = eng.newVariant(qVariantFromValue(cp));
+ QCOMPARE(qjsvalue_cast<QColor*>(v2), cp);
+ }
+}
+
+void tst_QJSValue::prettyPrinter_data()
+{
+ QTest::addColumn<QString>("function");
+ QTest::addColumn<QString>("expected");
+ QTest::newRow("function() { }") << QString("function() { }") << QString("function () { }");
+ QTest::newRow("function foo() { }") << QString("(function foo() { })") << QString("function foo() { }");
+ QTest::newRow("function foo(bar) { }") << QString("(function foo(bar) { })") << QString("function foo(bar) { }");
+ QTest::newRow("function foo(bar, baz) { }") << QString("(function foo(bar, baz) { })") << QString("function foo(bar, baz) { }");
+ QTest::newRow("this") << QString("function() { this; }") << QString("function () { this; }");
+ QTest::newRow("identifier") << QString("function(a) { a; }") << QString("function (a) { a; }");
+ QTest::newRow("null") << QString("function() { null; }") << QString("function () { null; }");
+ QTest::newRow("true") << QString("function() { true; }") << QString("function () { true; }");
+ QTest::newRow("false") << QString("function() { false; }") << QString("function () { false; }");
+ QTest::newRow("string") << QString("function() { 'test'; }") << QString("function () { \'test\'; }");
+ QTest::newRow("string") << QString("function() { \"test\"; }") << QString("function () { \"test\"; }");
+ QTest::newRow("number") << QString("function() { 123; }") << QString("function () { 123; }");
+ QTest::newRow("number") << QString("function() { 123.456; }") << QString("function () { 123.456; }");
+ QTest::newRow("regexp") << QString("function() { /hello/; }") << QString("function () { /hello/; }");
+ QTest::newRow("regexp") << QString("function() { /hello/gim; }") << QString("function () { /hello/gim; }");
+ QTest::newRow("array") << QString("function() { []; }") << QString("function () { []; }");
+ QTest::newRow("array") << QString("function() { [10]; }") << QString("function () { [10]; }");
+ QTest::newRow("array") << QString("function() { [10, 20, 30]; }") << QString("function () { [10, 20, 30]; }");
+ QTest::newRow("array") << QString("function() { [10, 20, , 40]; }") << QString("function () { [10, 20, , 40]; }");
+ QTest::newRow("array") << QString("function() { [,]; }") << QString("function () { [,]; }");
+ QTest::newRow("array") << QString("function() { [, 10]; }") << QString("function () { [, 10]; }");
+ QTest::newRow("array") << QString("function() { [, 10, ]; }") << QString("function () { [, 10, ]; }");
+ QTest::newRow("array") << QString("function() { [, 10, ,]; }") << QString("function () { [, 10, ,]; }");
+ QTest::newRow("array") << QString("function() { [[10], [20]]; }") << QString("function () { [[10], [20]]; }");
+ QTest::newRow("member") << QString("function() { a.b; }") << QString("function () { a.b; }");
+ QTest::newRow("member") << QString("function() { a.b.c; }") << QString("function () { a.b.c; }");
+ QTest::newRow("call") << QString("function() { f(); }") << QString("function () { f(); }");
+ QTest::newRow("call") << QString("function() { f(a); }") << QString("function () { f(a); }");
+ QTest::newRow("call") << QString("function() { f(a, b); }") << QString("function () { f(a, b); }");
+ QTest::newRow("new") << QString("function() { new C(); }") << QString("function () { new C(); }");
+ QTest::newRow("new") << QString("function() { new C(a); }") << QString("function () { new C(a); }");
+ QTest::newRow("new") << QString("function() { new C(a, b); }") << QString("function () { new C(a, b); }");
+ QTest::newRow("++") << QString("function() { a++; }") << QString("function () { a++; }");
+ QTest::newRow("++") << QString("function() { ++a; }") << QString("function () { ++a; }");
+ QTest::newRow("--") << QString("function() { a--; }") << QString("function () { a--; }");
+ QTest::newRow("--") << QString("function() { --a; }") << QString("function () { --a; }");
+ QTest::newRow("delete") << QString("function() { delete a; }") << QString("function () { delete a; }");
+ QTest::newRow("void") << QString("function() { void a; }") << QString("function () { void a; }");
+ QTest::newRow("typeof") << QString("function() { typeof a; }") << QString("function () { typeof a; }");
+ QTest::newRow("+") << QString("function() { +a; }") << QString("function () { +a; }");
+ QTest::newRow("-") << QString("function() { -a; }") << QString("function () { -a; }");
+ QTest::newRow("~") << QString("function() { ~a; }") << QString("function () { ~a; }");
+ QTest::newRow("!") << QString("function() { !a; }") << QString("function () { !a; }");
+ QTest::newRow("+") << QString("function() { a + b; }") << QString("function () { a + b; }");
+ QTest::newRow("&&") << QString("function() { a && b; }") << QString("function () { a && b; }");
+ QTest::newRow("&=") << QString("function() { a &= b; }") << QString("function () { a &= b; }");
+ QTest::newRow("=") << QString("function() { a = b; }") << QString("function () { a = b; }");
+ QTest::newRow("&") << QString("function() { a & b; }") << QString("function () { a & b; }");
+ QTest::newRow("|") << QString("function() { a | b; }") << QString("function () { a | b; }");
+ QTest::newRow("^") << QString("function() { a ^ b; }") << QString("function () { a ^ b; }");
+ QTest::newRow("-=") << QString("function() { a -= b; }") << QString("function () { a -= b; }");
+ QTest::newRow("/") << QString("function() { a / b; }") << QString("function () { a / b; }");
+ QTest::newRow("/=") << QString("function() { a /= b; }") << QString("function () { a /= b; }");
+ QTest::newRow("==") << QString("function() { a == b; }") << QString("function () { a == b; }");
+ QTest::newRow(">=") << QString("function() { a >= b; }") << QString("function () { a >= b; }");
+ QTest::newRow(">") << QString("function() { a > b; }") << QString("function () { a > b; }");
+ QTest::newRow("in") << QString("function() { a in b; }") << QString("function () { a in b; }");
+ QTest::newRow("+=") << QString("function() { a += b; }") << QString("function () { a += b; }");
+ QTest::newRow("instanceof") << QString("function() { a instanceof b; }") << QString("function () { a instanceof b; }");
+ QTest::newRow("<=") << QString("function() { a <= b; }") << QString("function () { a <= b; }");
+ QTest::newRow("<<") << QString("function() { a << b; }") << QString("function () { a << b; }");
+ QTest::newRow("<<=") << QString("function() { a <<= b; }") << QString("function () { a <<= b; }");
+ QTest::newRow("<") << QString("function() { a < b; }") << QString("function () { a < b; }");
+ QTest::newRow("%") << QString("function() { a % b; }") << QString("function () { a % b; }");
+ QTest::newRow("%=") << QString("function() { a %= b; }") << QString("function () { a %= b; }");
+ QTest::newRow("*") << QString("function() { a * b; }") << QString("function () { a * b; }");
+ QTest::newRow("*=") << QString("function() { a *= b; }") << QString("function () { a *= b; }");
+ QTest::newRow("!=") << QString("function() { a != b; }") << QString("function () { a != b; }");
+ QTest::newRow("||") << QString("function() { a || b; }") << QString("function () { a || b; }");
+ QTest::newRow("|=") << QString("function() { a |= b; }") << QString("function () { a |= b; }");
+ QTest::newRow(">>") << QString("function() { a >> b; }") << QString("function () { a >> b; }");
+ QTest::newRow(">>=") << QString("function() { a >>= b; }") << QString("function () { a >>= b; }");
+ QTest::newRow("===") << QString("function() { a === b; }") << QString("function () { a === b; }");
+ QTest::newRow("!==") << QString("function() { a !== b; }") << QString("function () { a !== b; }");
+ QTest::newRow("-") << QString("function() { a - b; }") << QString("function () { a - b; }");
+ QTest::newRow(">>>") << QString("function() { a >>> b; }") << QString("function () { a >>> b; }");
+ QTest::newRow(">>>=") << QString("function() { a >>>= b; }") << QString("function () { a >>>= b; }");
+ QTest::newRow("^=") << QString("function() { a ^= b; }") << QString("function () { a ^= b; }");
+ QTest::newRow("? :") << QString("function() { a ? b : c; }") << QString("function () { a ? b : c; }");
+ QTest::newRow("a; b; c") << QString("function() { a; b; c; }") << QString("function () { a; b; c; }");
+ QTest::newRow("var a;") << QString("function() { var a; }") << QString("function () { var a; }");
+ QTest::newRow("var a, b;") << QString("function() { var a, b; }") << QString("function () { var a, b; }");
+ QTest::newRow("var a = 10;") << QString("function() { var a = 10; }") << QString("function () { var a = 10; }");
+ QTest::newRow("var a, b = 20;") << QString("function() { var a, b = 20; }") << QString("function () { var a, b = 20; }");
+ QTest::newRow("var a = 10, b = 20;") << QString("function() { var a = 10, b = 20; }") << QString("function () { var a = 10, b = 20; }");
+ QTest::newRow("if") << QString("function() { if (a) b; }") << QString("function () { if (a) b; }");
+ QTest::newRow("if") << QString("function() { if (a) { b; c; } }") << QString("function () { if (a) { b; c; } }");
+ QTest::newRow("if-else") << QString("function() { if (a) b; else c; }") << QString("function () { if (a) b; else c; }");
+ QTest::newRow("if-else") << QString("function() { if (a) { b; c; } else { d; e; } }") << QString("function () { if (a) { b; c; } else { d; e; } }");
+ QTest::newRow("do-while") << QString("function() { do { a; } while (b); }") << QString("function () { do { a; } while (b); }");
+ QTest::newRow("do-while") << QString("function() { do { a; b; c; } while (d); }") << QString("function () { do { a; b; c; } while (d); }");
+ QTest::newRow("while") << QString("function() { while (a) { b; } }") << QString("function () { while (a) { b; } }");
+ QTest::newRow("while") << QString("function() { while (a) { b; c; } }") << QString("function () { while (a) { b; c; } }");
+ QTest::newRow("for") << QString("function() { for (a; b; c) { } }") << QString("function () { for (a; b; c) { } }");
+ QTest::newRow("for") << QString("function() { for (; a; b) { } }") << QString("function () { for (; a; b) { } }");
+ QTest::newRow("for") << QString("function() { for (; ; a) { } }") << QString("function () { for (; ; a) { } }");
+ QTest::newRow("for") << QString("function() { for (; ; ) { } }") << QString("function () { for (; ; ) { } }");
+ QTest::newRow("for") << QString("function() { for (var a; b; c) { } }") << QString("function () { for (var a; b; c) { } }");
+ QTest::newRow("for") << QString("function() { for (var a, b, c; d; e) { } }") << QString("function () { for (var a, b, c; d; e) { } }");
+ QTest::newRow("continue") << QString("function() { for (; ; ) { continue; } }") << QString("function () { for (; ; ) { continue; } }");
+ QTest::newRow("break") << QString("function() { for (; ; ) { break; } }") << QString("function () { for (; ; ) { break; } }");
+ QTest::newRow("return") << QString("function() { return; }") << QString("function () { return; }");
+ QTest::newRow("return") << QString("function() { return 10; }") << QString("function () { return 10; }");
+ QTest::newRow("with") << QString("function() { with (a) { b; } }") << QString("function () { with (a) { b; } }");
+ QTest::newRow("with") << QString("function() { with (a) { b; c; } }") << QString("function () { with (a) { b; c; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { } }") << QString("function () { switch (a) { } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: ; } }") << QString("function () { switch (a) { case 1: ; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: b; break; } }") << QString("function () { switch (a) { case 1: b; break; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: b; break; case 2: break; } }") << QString("function () { switch (a) { case 1: b; break; case 2: break; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: case 2: ; } }") << QString("function () { switch (a) { case 1: case 2: ; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: default: ; } }") << QString("function () { switch (a) { case 1: default: ; } }");
+ QTest::newRow("switch") << QString("function() { switch (a) { case 1: default: ; case 3: ; } }") << QString("function () { switch (a) { case 1: default: ; case 3: ; } }");
+ QTest::newRow("label") << QString("function() { a: b; }") << QString("function () { a: b; }");
+ QTest::newRow("throw") << QString("function() { throw a; }") << QString("function () { throw a; }");
+ QTest::newRow("try-catch") << QString("function() { try { a; } catch (e) { b; } }") << QString("function () { try { a; } catch (e) { b; } }");
+ QTest::newRow("try-finally") << QString("function() { try { a; } finally { b; } }") << QString("function () { try { a; } finally { b; } }");
+ QTest::newRow("try-catch-finally") << QString("function() { try { a; } catch (e) { b; } finally { c; } }") << QString("function () { try { a; } catch (e) { b; } finally { c; } }");
+ QTest::newRow("a + b + c + d") << QString("function() { a + b + c + d; }") << QString("function () { a + b + c + d; }");
+ QTest::newRow("a + b - c") << QString("function() { a + b - c; }") << QString("function () { a + b - c; }");
+ QTest::newRow("a + -b") << QString("function() { a + -b; }") << QString("function () { a + -b; }");
+ QTest::newRow("a + ~b") << QString("function() { a + ~b; }") << QString("function () { a + ~b; }");
+ QTest::newRow("a + !b") << QString("function() { a + !b; }") << QString("function () { a + !b; }");
+ QTest::newRow("a + +b") << QString("function() { a + +b; }") << QString("function () { a + +b; }");
+ QTest::newRow("(a + b) - c") << QString("function() { (a + b) - c; }") << QString("function () { (a + b) - c; }");
+ QTest::newRow("(a - b + c") << QString("function() { a - b + c; }") << QString("function () { a - b + c; }");
+ QTest::newRow("(a - (b + c)") << QString("function() { a - (b + c); }") << QString("function () { a - (b + c); }");
+ QTest::newRow("a + -(b + c)") << QString("function() { a + -(b + c); }") << QString("function () { a + -(b + c); }");
+ QTest::newRow("a + ~(b + c)") << QString("function() { a + ~(b + c); }") << QString("function () { a + ~(b + c); }");
+ QTest::newRow("a + !(b + c)") << QString("function() { a + !(b + c); }") << QString("function () { a + !(b + c); }");
+ QTest::newRow("a + +(b + c)") << QString("function() { a + +(b + c); }") << QString("function () { a + +(b + c); }");
+ QTest::newRow("a + b * c") << QString("function() { a + b * c; }") << QString("function () { a + b * c; }");
+ QTest::newRow("(a + b) * c") << QString("function() { (a + b) * c; }") << QString("function () { (a + b) * c; }");
+ QTest::newRow("(a + b) * (c + d)") << QString("function() { (a + b) * (c + d); }") << QString("function () { (a + b) * (c + d); }");
+ QTest::newRow("a + (b * c)") << QString("function() { a + (b * c); }") << QString("function () { a + (b * c); }");
+ QTest::newRow("a + (b / c)") << QString("function() { a + (b / c); }") << QString("function () { a + (b / c); }");
+ QTest::newRow("(a / b) * c") << QString("function() { (a / b) * c; }") << QString("function () { (a / b) * c; }");
+ QTest::newRow("a / (b * c)") << QString("function() { a / (b * c); }") << QString("function () { a / (b * c); }");
+ QTest::newRow("a / (b % c)") << QString("function() { a / (b % c); }") << QString("function () { a / (b % c); }");
+ QTest::newRow("a && b || c") << QString("function() { a && b || c; }") << QString("function () { a && b || c; }");
+ QTest::newRow("a && (b || c)") << QString("function() { a && (b || c); }") << QString("function () { a && (b || c); }");
+ QTest::newRow("a & b | c") << QString("function() { a & b | c; }") << QString("function () { a & b | c; }");
+ QTest::newRow("a & (b | c)") << QString("function() { a & (b | c); }") << QString("function () { a & (b | c); }");
+ QTest::newRow("a & b | c ^ d") << QString("function() { a & b | c ^ d; }") << QString("function () { a & b | c ^ d; }");
+ QTest::newRow("a & (b | c ^ d)") << QString("function() { a & (b | c ^ d); }") << QString("function () { a & (b | c ^ d); }");
+ QTest::newRow("(a & b | c) ^ d") << QString("function() { (a & b | c) ^ d; }") << QString("function () { (a & b | c) ^ d; }");
+ QTest::newRow("a << b + c") << QString("function() { a << b + c; }") << QString("function () { a << b + c; }");
+ QTest::newRow("(a << b) + c") << QString("function() { (a << b) + c; }") << QString("function () { (a << b) + c; }");
+ QTest::newRow("a >> b + c") << QString("function() { a >> b + c; }") << QString("function () { a >> b + c; }");
+ QTest::newRow("(a >> b) + c") << QString("function() { (a >> b) + c; }") << QString("function () { (a >> b) + c; }");
+ QTest::newRow("a >>> b + c") << QString("function() { a >>> b + c; }") << QString("function () { a >>> b + c; }");
+ QTest::newRow("(a >>> b) + c") << QString("function() { (a >>> b) + c; }") << QString("function () { (a >>> b) + c; }");
+ QTest::newRow("a == b || c != d") << QString("function() { a == b || c != d; }") << QString("function () { a == b || c != d; }");
+ QTest::newRow("a == (b || c != d)") << QString("function() { a == (b || c != d); }") << QString("function () { a == (b || c != d); }");
+ QTest::newRow("a === b || c !== d") << QString("function() { a === b || c !== d; }") << QString("function () { a === b || c !== d; }");
+ QTest::newRow("a === (b || c !== d)") << QString("function() { a === (b || c !== d); }") << QString("function () { a === (b || c !== d); }");
+ QTest::newRow("a &= b + c") << QString("function() { a &= b + c; }") << QString("function () { a &= b + c; }");
+ QTest::newRow("debugger") << QString("function() { debugger; }") << QString("function () { debugger; }");
+}
+
+void tst_QJSValue::prettyPrinter()
+{
+ QFETCH(QString, function);
+ QFETCH(QString, expected);
+ QJSEngine eng;
+ QJSValue val = eng.evaluate("(" + function + ")");
+ QVERIFY(val.isFunction());
+ QString actual = val.toString();
+ int count = qMin(actual.size(), expected.size());
+// qDebug() << actual << expected;
+ for (int i = 0; i < count; ++i) {
+// qDebug() << i << actual.at(i) << expected.at(i);
+ QCOMPARE(actual.at(i), expected.at(i));
+ }
+ QCOMPARE(actual.size(), expected.size());
+}
+
+void tst_QJSValue::engineDeleted()
+{
+ QJSEngine *eng = new QJSEngine;
+ QJSValue v1(eng, 123);
+ QVERIFY(v1.isNumber());
+ QJSValue v2(eng, QString("ciao"));
+ QVERIFY(v2.isString());
+ QJSValue v3 = eng->newObject();
+ QVERIFY(v3.isObject());
+ QJSValue v4 = eng->newQObject(this);
+ QVERIFY(v4.isQObject());
+ QJSValue v5 = "Hello";
+ QVERIFY(v2.isString());
+
+ delete eng;
+
+ QVERIFY(!v1.isValid());
+ QVERIFY(v1.engine() == 0);
+ QVERIFY(!v2.isValid());
+ QVERIFY(v2.engine() == 0);
+ QVERIFY(!v3.isValid());
+ QVERIFY(v3.engine() == 0);
+ QVERIFY(!v4.isValid());
+ QVERIFY(v4.engine() == 0);
+ QVERIFY(v5.isValid());
+ QVERIFY(v5.engine() == 0);
+
+ QVERIFY(!v3.property("foo").isValid());
+}
+
+void tst_QJSValue::valueOfWithClosure()
+{
+ QJSEngine eng;
+ // valueOf()
+ {
+ QJSValue obj = eng.evaluate("o = {}; (function(foo) { o.valueOf = function() { return foo; } })(123); o");
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.toInt32(), 123);
+ }
+ // toString()
+ {
+ QJSValue obj = eng.evaluate("o = {}; (function(foo) { o.toString = function() { return foo; } })('ciao'); o");
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.toString(), QString::fromLatin1("ciao"));
+ }
+}
+
+#if 0 // FIXME: no objectId()
+void tst_QJSValue::objectId()
+{
+ QCOMPARE(QJSValue().objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(QJSValue::UndefinedValue).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(QJSValue::NullValue).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(false).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(123).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(uint(123)).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue(123.5).objectId(), (qint64)-1);
+ QCOMPARE(QJSValue("ciao").objectId(), (qint64)-1);
+
+ QScriptEngine eng;
+ QJSValue o1 = eng.newObject();
+ QVERIFY(o1.objectId() != -1);
+ QJSValue o2 = eng.newObject();
+ QVERIFY(o2.objectId() != -1);
+ QVERIFY(o1.objectId() != o2.objectId());
+
+ QVERIFY(eng.objectById(o1.objectId()).strictlyEquals(o1));
+ QVERIFY(eng.objectById(o2.objectId()).strictlyEquals(o2));
+
+ qint64 globalObjectId = -1;
+ {
+ QJSValue global = eng.globalObject();
+ globalObjectId = global.objectId();
+ QVERIFY(globalObjectId != -1);
+ QVERIFY(eng.objectById(globalObjectId).strictlyEquals(global));
+ }
+ QJSValue obj = eng.objectById(globalObjectId);
+ QVERIFY(obj.isObject());
+ QVERIFY(obj.strictlyEquals(eng.globalObject()));
+}
+#endif
+
+void tst_QJSValue::nestedObjectToVariant_data()
+{
+ QTest::addColumn<QString>("program");
+ QTest::addColumn<QVariant>("expected");
+
+ // Array literals
+ QTest::newRow("[[]]")
+ << QString::fromLatin1("[[]]")
+ << QVariant(QVariantList() << (QVariant(QVariantList())));
+ QTest::newRow("[[123]]")
+ << QString::fromLatin1("[[123]]")
+ << QVariant(QVariantList() << (QVariant(QVariantList() << 123)));
+ QTest::newRow("[[], 123]")
+ << QString::fromLatin1("[[], 123]")
+ << QVariant(QVariantList() << QVariant(QVariantList()) << 123);
+
+ // Cyclic arrays
+ QTest::newRow("var a=[]; a.push(a)")
+ << QString::fromLatin1("var a=[]; a.push(a); a")
+ << QVariant(QVariantList() << QVariant(QVariantList()));
+ QTest::newRow("var a=[]; a.push(123, a)")
+ << QString::fromLatin1("var a=[]; a.push(123, a); a")
+ << QVariant(QVariantList() << 123 << QVariant(QVariantList()));
+ QTest::newRow("var a=[]; var b=[]; a.push(b); b.push(a)")
+ << QString::fromLatin1("var a=[]; var b=[]; a.push(b); b.push(a); a")
+ << QVariant(QVariantList() << QVariant(QVariantList() << QVariant(QVariantList())));
+ QTest::newRow("var a=[]; var b=[]; a.push(123, b); b.push(456, a)")
+ << QString::fromLatin1("var a=[]; var b=[]; a.push(123, b); b.push(456, a); a")
+ << QVariant(QVariantList() << 123 << QVariant(QVariantList() << 456 << QVariant(QVariantList())));
+
+ // Object literals
+ {
+ QVariantMap m;
+ m["a"] = QVariantMap();
+ QTest::newRow("{ a:{} }")
+ << QString::fromLatin1("({ a:{} })")
+ << QVariant(m);
+ }
+ {
+ QVariantMap m, m2;
+ m2["b"] = 10;
+ m2["c"] = 20;
+ m["a"] = m2;
+ QTest::newRow("{ a:{b:10, c:20} }")
+ << QString::fromLatin1("({ a:{b:10, c:20} })")
+ << QVariant(m);
+ }
+ {
+ QVariantMap m;
+ m["a"] = 10;
+ m["b"] = QVariantList() << 20 << 30;
+ QTest::newRow("{ a:10, b:[20, 30]}")
+ << QString::fromLatin1("({ a:10, b:[20,30]})")
+ << QVariant(m);
+ }
+
+ // Cyclic objects
+ {
+ QVariantMap m;
+ m["p"] = QVariantMap();
+ QTest::newRow("var o={}; o.p=o")
+ << QString::fromLatin1("var o={}; o.p=o; o")
+ << QVariant(m);
+ }
+ {
+ QVariantMap m;
+ m["p"] = 123;
+ m["q"] = QVariantMap();
+ QTest::newRow("var o={}; o.p=123; o.q=o")
+ << QString::fromLatin1("var o={}; o.p=123; o.q=o; o")
+ << QVariant(m);
+ }
+}
+
+void tst_QJSValue::nestedObjectToVariant()
+{
+ QJSEngine eng;
+ QFETCH(QString, program);
+ QFETCH(QVariant, expected);
+ QJSValue o = eng.evaluate(program);
+ QVERIFY(!o.isError());
+ QVERIFY(o.isObject());
+ QCOMPARE(o.toVariant(), expected);
+}
+
+void tst_QJSValue::propertyFlags_data()
+{
+ QTest::addColumn<QString>("program");
+ QTest::addColumn<uint>("expected");
+
+ QTest::newRow("nothing") << "" << 0u;
+#if 0 // FIXME: No getter/setter API
+ QTest::newRow("getter") << "o.__defineGetter__('prop', function() { return 'blah' } );\n" << uint(QJSValue::PropertyGetter);
+ QTest::newRow("setter") << "o.__defineSetter__('prop', function(a) { this.setted_prop2 = a; } );\n" << uint(QJSValue::PropertySetter);
+ QTest::newRow("getterSetter") << "o.__defineGetter__('prop', function() { return 'ploup' } );\n"
+ "o.__defineSetter__('prop', function(a) { this.setted_prop3 = a; } );\n" << uint(QJSValue::PropertySetter|QJSValue::PropertyGetter);
+#endif
+ QTest::newRow("nothing2") << "o.prop = 'nothing'" << 0u;
+}
+
+void tst_QJSValue::propertyFlags()
+{
+ QFETCH(QString, program);
+ QFETCH(uint, expected);
+ QJSEngine eng;
+ eng.evaluate("o = new Object;");
+ eng.evaluate(program);
+ QJSValue o = eng.evaluate("o");
+
+ QCOMPARE(uint(o.propertyFlags("prop")), expected);
+}
+
+
+QTEST_MAIN(tst_QJSValue)
diff --git a/tests/auto/declarative/qjsvalue/tst_qjsvalue.h b/tests/auto/declarative/qjsvalue/tst_qjsvalue.h
new file mode 100644
index 0000000000..b605066aef
--- /dev/null
+++ b/tests/auto/declarative/qjsvalue/tst_qjsvalue.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TST_QJSVALUE_H
+#define TST_QJSVALUE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qnumeric.h>
+#include <qjsengine.h>
+#include <qjsvalue.h>
+#include <QtTest/QtTest>
+
+Q_DECLARE_METATYPE(QVariant)
+Q_DECLARE_METATYPE(QJSValue)
+
+class tst_QJSValue : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QJSValue();
+ virtual ~tst_QJSValue();
+
+private slots:
+ void toObject();
+
+ void ctor_invalid();
+ void ctor_undefinedWithEngine();
+ void ctor_undefined();
+ void ctor_nullWithEngine();
+ void ctor_null();
+ void ctor_boolWithEngine();
+ void ctor_bool();
+ void ctor_intWithEngine();
+ void ctor_int();
+ void ctor_uintWithEngine();
+ void ctor_uint();
+ void ctor_floatWithEngine();
+ void ctor_float();
+ void ctor_stringWithEngine();
+ void ctor_string();
+ void ctor_copyAndAssignWithEngine();
+ void ctor_copyAndAssign();
+ void ctor_nullEngine();
+
+ void toString();
+ void toNumber();
+ void toBoolean();
+ void toBool();
+ void toInteger();
+ void toInt32();
+ void toUInt32();
+ void toUInt16();
+ void toVariant();
+ void toQObject_nonQObject_data();
+ void toQObject_nonQObject();
+ void toQObject();
+ void toDateTime();
+ void toRegExp();
+ void instanceOf_twoEngines();
+ void instanceOf();
+ void isArray_data();
+ void isArray();
+ void isDate();
+ void isDate_data();
+ void isError_propertiesOfGlobalObject();
+ void isError_data();
+ void isError();
+ void isRegExp_data();
+ void isRegExp();
+
+#if 0 // FIXME: No QScriptValue::lessThan
+ void lessThan();
+#endif
+ void equals();
+ void strictlyEquals();
+
+ void getSetPrototype_cyclicPrototype();
+ void getSetPrototype_evalCyclicPrototype();
+ void getSetPrototype_eval();
+ void getSetPrototype_invalidPrototype();
+ void getSetPrototype_twoEngines();
+ void getSetPrototype_null();
+ void getSetPrototype_notObjectOrNull();
+ void getSetPrototype();
+ void getSetScope();
+ void getSetProperty_HooliganTask162051();
+ void getSetProperty_HooliganTask183072();
+ void getSetProperty_propertyRemoval();
+ void getSetProperty_resolveMode();
+ void getSetProperty_twoEngines();
+ void getSetProperty_gettersAndSetters();
+ void getSetProperty_gettersAndSettersThrowErrorNative();
+ void getSetProperty_gettersAndSettersThrowErrorJS();
+ void getSetProperty_gettersAndSettersOnNative();
+ void getSetProperty_gettersAndSettersOnGlobalObject();
+ void getSetProperty_gettersAndSettersChange();
+ void getSetProperty_gettersAndSettersStupid();
+ void getSetProperty_array();
+ void getSetProperty();
+ void arrayElementGetterSetter();
+ void getSetData_objects_data();
+ void getSetData_objects();
+ void getSetData_nonObjects_data();
+ void getSetData_nonObjects();
+ void setData_QTBUG15144();
+#if 0 // FIXME: no QScriptClass
+ void getSetScriptClass_emptyClass_data();
+ void getSetScriptClass_emptyClass();
+ void getSetScriptClass_JSObjectFromCpp();
+ void getSetScriptClass_JSObjectFromJS();
+ void getSetScriptClass_QVariant();
+ void getSetScriptClass_QObject();
+#endif
+ void call_function();
+ void call_object();
+ void call_newObjects();
+ void call_this();
+ void call_arguments();
+ void call();
+ void call_invalidArguments();
+ void call_invalidReturn();
+ void call_twoEngines();
+ void call_array();
+ void call_nonFunction_data();
+ void call_nonFunction();
+ void construct_nonFunction_data();
+ void construct_nonFunction();
+ void construct_simple();
+ void construct_newObjectJS();
+#if 0 // FIXME: no c-style callbacks
+ void construct_undefined();
+ void construct_newObjectCpp();
+#endif
+ void construct_arg();
+ void construct_proto();
+ void construct_returnInt();
+ void construct_throw();
+#if 0 // FIXME: The feature of interpreting an array as argument list has been removed from the API
+ void construct();
+#endif
+ void construct_twoEngines();
+ void construct_constructorThrowsPrimitive();
+ void castToPointer();
+ void prettyPrinter_data();
+ void prettyPrinter();
+ void engineDeleted();
+ void valueOfWithClosure();
+#if 0 // FIXME: no objectId()
+ void objectId();
+#endif
+ void nestedObjectToVariant_data();
+ void nestedObjectToVariant();
+ void propertyFlags_data();
+ void propertyFlags();
+
+private:
+ void newEngine()
+ {
+ if (engine)
+ delete engine;
+ engine = new QJSEngine();
+ }
+ QJSEngine *engine;
+};
+
+#endif
diff --git a/tests/auto/declarative/qjsvalueiterator/qjsvalueiterator.pro b/tests/auto/declarative/qjsvalueiterator/qjsvalueiterator.pro
new file mode 100644
index 0000000000..e5137fcdf1
--- /dev/null
+++ b/tests/auto/declarative/qjsvalueiterator/qjsvalueiterator.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT = core declarative
+SOURCES += tst_qjsvalueiterator.cpp
+
+
diff --git a/tests/auto/declarative/qjsvalueiterator/tst_qjsvalueiterator.cpp b/tests/auto/declarative/qjsvalueiterator/tst_qjsvalueiterator.cpp
new file mode 100644
index 0000000000..1cd5952c54
--- /dev/null
+++ b/tests/auto/declarative/qjsvalueiterator/tst_qjsvalueiterator.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QJSEngine>
+#include <QJSValue>
+#include <QJSValueIterator>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QJSValue);
+
+class tst_QJSValueIterator : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QJSValueIterator();
+ virtual ~tst_QJSValueIterator();
+
+private slots:
+ void iterateForward_data();
+ void iterateForward();
+ void iterateArray_data();
+ void iterateArray();
+ void iterateString();
+#if 0
+ void iterateGetterSetter();
+#endif
+ void assignObjectToIterator();
+ void iterateNonObject();
+ void iterateOverObjectFromDeletedEngine();
+};
+
+tst_QJSValueIterator::tst_QJSValueIterator()
+{
+}
+
+tst_QJSValueIterator::~tst_QJSValueIterator()
+{
+}
+
+void tst_QJSValueIterator::iterateForward_data()
+{
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QStringList>("propertyValues");
+
+ QTest::newRow("no properties")
+ << QStringList() << QStringList();
+ QTest::newRow("foo=bar")
+ << (QStringList() << "foo")
+ << (QStringList() << "bar");
+ QTest::newRow("foo=bar, baz=123")
+ << (QStringList() << "foo" << "baz")
+ << (QStringList() << "bar" << "123");
+ QTest::newRow("foo=bar, baz=123, rab=oof")
+ << (QStringList() << "foo" << "baz" << "rab")
+ << (QStringList() << "bar" << "123" << "oof");
+}
+
+void tst_QJSValueIterator::iterateForward()
+{
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QStringList, propertyValues);
+ QMap<QString, QString> pmap;
+ QVERIFY(propertyNames.size() == propertyValues.size());
+
+ QJSEngine engine;
+ QJSValue object = engine.newObject();
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString name = propertyNames.at(i);
+ QString value = propertyValues.at(i);
+ pmap.insert(name, value);
+ object.setProperty(name, QJSValue(&engine, value));
+ }
+ QJSValue otherObject = engine.newObject();
+ otherObject.setProperty("foo", QJSValue(&engine, 123456));
+ otherObject.setProperty("protoProperty", QJSValue(&engine, 654321));
+ object.setPrototype(otherObject); // should not affect iterator
+
+ QStringList lst;
+ QJSValueIterator it(object);
+ while (!pmap.isEmpty()) {
+ QCOMPARE(it.hasNext(), true);
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QString name = it.name();
+ QCOMPARE(pmap.contains(name), true);
+ QCOMPARE(it.name(), name);
+ QCOMPARE(it.value().strictlyEquals(QJSValue(&engine, pmap.value(name))), true);
+ pmap.remove(name);
+ lst.append(name);
+ }
+
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.hasNext(), false);
+
+ it = object;
+ for (int i = 0; i < lst.count(); ++i) {
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), lst.at(i));
+ }
+}
+
+void tst_QJSValueIterator::iterateArray_data()
+{
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QStringList>("propertyValues");
+
+ QTest::newRow("no elements") << QStringList() << QStringList();
+
+ QTest::newRow("0=foo, 1=barr")
+ << (QStringList() << "0" << "1")
+ << (QStringList() << "foo" << "bar");
+
+
+ QTest::newRow("0=foo, 3=barr")
+ << (QStringList() << "0" << "1" << "2" << "3")
+ << (QStringList() << "foo" << "" << "" << "bar");
+}
+
+void tst_QJSValueIterator::iterateArray()
+{
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QStringList, propertyValues);
+
+ QJSEngine engine;
+ QJSValue array = engine.newArray();
+
+ // Fill the array
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ array.setProperty(propertyNames.at(i), propertyValues.at(i));
+ }
+
+ // Iterate thru array properties. Note that the QJSValueIterator doesn't guarantee
+ // any order on the iteration!
+ int length = array.property("length").toInt32();
+ QCOMPARE(length, propertyNames.size());
+
+ bool iteratedThruLength = false;
+ QHash<QString, QJSValue> arrayProperties;
+ QJSValueIterator it(array);
+
+ // Iterate forward
+ while (it.hasNext()) {
+ it.next();
+
+ const QString name = it.name();
+ if (name == QString::fromLatin1("length")) {
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
+ iteratedThruLength = true;
+ continue;
+ }
+
+ // Storing the properties we iterate in a hash to compare with test data.
+ QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
+ arrayProperties.insert(name, it.value());
+ QVERIFY(it.value().strictlyEquals(array.property(name)));
+ }
+
+ // Verify properties
+ QVERIFY(iteratedThruLength);
+ QCOMPARE(arrayProperties.size(), propertyNames.size());
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QVERIFY(arrayProperties.contains(propertyNames.at(i)));
+ QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
+ }
+
+#if 0
+
+ // Iterate backwards
+ arrayProperties.clear();
+ iteratedThruLength = false;
+ it.toBack();
+
+ while (it.hasPrevious()) {
+ it.previous();
+
+ const QString name = it.name();
+ if (name == QString::fromLatin1("length")) {
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QCOMPARE(it.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
+ QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
+ iteratedThruLength = true;
+ continue;
+ }
+
+ // Storing the properties we iterate in a hash to compare with test data.
+ QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
+ arrayProperties.insert(name, it.value());
+ QCOMPARE(it.flags(), array.propertyFlags(name));
+ QVERIFY(it.value().strictlyEquals(array.property(name)));
+ }
+
+ // Verify properties
+ QVERIFY(iteratedThruLength);
+ QCOMPARE(arrayProperties.size(), propertyNames.size());
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QVERIFY(arrayProperties.contains(propertyNames.at(i)));
+ QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
+ }
+
+ // ### Do we still need this test?
+ // Forward test again but as object
+ arrayProperties.clear();
+ iteratedThruLength = false;
+ QJSValue arrayObject = engine.toObject(array);
+ QJSValueIterator it2(arrayObject);
+
+ while (it2.hasNext()) {
+ it2.next();
+
+ const QString name = it2.name();
+ if (name == QString::fromLatin1("length")) {
+ QVERIFY(it2.value().isNumber());
+ QCOMPARE(it2.value().toInt32(), length);
+ QCOMPARE(it2.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
+ QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
+ iteratedThruLength = true;
+ continue;
+ }
+
+ // Storing the properties we iterate in a hash to compare with test data.
+ QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
+ arrayProperties.insert(name, it2.value());
+ QCOMPARE(it2.flags(), arrayObject.propertyFlags(name));
+ QVERIFY(it2.value().strictlyEquals(arrayObject.property(name)));
+ }
+
+ // Verify properties
+ QVERIFY(iteratedThruLength);
+ QCOMPARE(arrayProperties.size(), propertyNames.size());
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QVERIFY(arrayProperties.contains(propertyNames.at(i)));
+ QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
+ }
+#endif
+}
+
+void tst_QJSValueIterator::iterateString()
+{
+ QJSEngine engine;
+ QJSValue str = QJSValue(&engine, QString::fromLatin1("ciao"));
+ QVERIFY(str.isString());
+ QJSValue obj = str.toObject();
+ QVERIFY(obj.property("length").isNumber());
+ int length = obj.property("length").toInt32();
+ QCOMPARE(length, 4);
+
+ QJSValueIterator it(obj);
+ QHash<QString, QJSValue> stringProperties;
+ bool iteratedThruLength = false;
+
+ while (it.hasNext()) {
+ it.next();
+ const QString name = it.name();
+
+ if (name == QString::fromLatin1("length")) {
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
+ iteratedThruLength = true;
+ continue;
+ }
+
+ QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
+ stringProperties.insert(name, it.value());
+ QVERIFY(it.value().strictlyEquals(obj.property(name)));
+ }
+
+ QVERIFY(iteratedThruLength);
+ QCOMPARE(stringProperties.size(), length);
+#if 0
+ // And going backwards
+ iteratedThruLength = false;
+ stringProperties.clear();
+ it.toBack();
+
+ while (it.hasPrevious()) {
+ it.previous();
+ const QString name = it.name();
+
+ if (name == QString::fromLatin1("length")) {
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
+ iteratedThruLength = true;
+ continue;
+ }
+
+ QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
+ stringProperties.insert(name, it.value());
+ QVERIFY(it.value().strictlyEquals(obj.property(name)));
+ }
+#endif
+}
+
+#if 0 // FIXME what we should to keep from here?
+static QJSValue myGetterSetter(QScriptContext *ctx, QJSEngine *)
+{
+ if (ctx->argumentCount() == 1)
+ ctx->thisObject().setProperty("bar", ctx->argument(0));
+ return ctx->thisObject().property("bar");
+}
+
+static QJSValue myGetter(QScriptContext *ctx, QJSEngine *)
+{
+ return ctx->thisObject().property("bar");
+}
+
+static QJSValue mySetter(QScriptContext *ctx, QJSEngine *)
+{
+ ctx->thisObject().setProperty("bar", ctx->argument(0));
+ return ctx->argument(0);
+}
+
+void tst_QJSValueIterator::iterateGetterSetter()
+{
+ // unified getter/setter function
+ {
+ QJSEngine eng;
+ QJSValue obj = eng.newObject();
+ obj.setProperty("foo", eng.newFunction(myGetterSetter),
+ QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ QJSValue val(&eng, 123);
+ obj.setProperty("foo", val);
+ QVERIFY(obj.property("bar").strictlyEquals(val));
+ QVERIFY(obj.property("foo").strictlyEquals(val));
+
+ QJSValueIterator it(obj);
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
+ QVERIFY(it.value().strictlyEquals(val));
+ QJSValue val2(&eng, 456);
+ it.setValue(val2);
+ QVERIFY(obj.property("bar").strictlyEquals(val2));
+ QVERIFY(obj.property("foo").strictlyEquals(val2));
+
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+ QVERIFY(!it.hasNext());
+
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
+ QVERIFY(it.value().strictlyEquals(val2));
+ it.setValue(val);
+ QVERIFY(obj.property("bar").strictlyEquals(val));
+ QVERIFY(obj.property("foo").strictlyEquals(val));
+ }
+ // separate getter/setter function
+ for (int x = 0; x < 2; ++x) {
+ QJSEngine eng;
+ QJSValue obj = eng.newObject();
+ if (x == 0) {
+ obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
+ obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
+ } else {
+ obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
+ obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
+ }
+ QJSValue val(&eng, 123);
+ obj.setProperty("foo", val);
+ QVERIFY(obj.property("bar").strictlyEquals(val));
+ QVERIFY(obj.property("foo").strictlyEquals(val));
+
+ QJSValueIterator it(obj);
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QVERIFY(it.value().strictlyEquals(val));
+ QJSValue val2(&eng, 456);
+ it.setValue(val2);
+ QVERIFY(obj.property("bar").strictlyEquals(val2));
+ QVERIFY(obj.property("foo").strictlyEquals(val2));
+
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+ QVERIFY(!it.hasNext());
+
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QVERIFY(it.value().strictlyEquals(val2));
+ it.setValue(val);
+ QVERIFY(obj.property("bar").strictlyEquals(val));
+ QVERIFY(obj.property("foo").strictlyEquals(val));
+ }
+}
+#endif
+
+void tst_QJSValueIterator::assignObjectToIterator()
+{
+ QJSEngine eng;
+ QJSValue obj1 = eng.newObject();
+ obj1.setProperty("foo", 123);
+ QJSValue obj2 = eng.newObject();
+ obj2.setProperty("bar", 456);
+
+ QJSValueIterator it(obj1);
+ QVERIFY(it.hasNext());
+ it.next();
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+
+ it = obj1;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+}
+
+void tst_QJSValueIterator::iterateNonObject()
+{
+ QJSValueIterator it(123);
+ QVERIFY(!it.hasNext());
+ it.next();
+ it.name();
+ it.value();
+ QJSValue num(5);
+ it = num;
+ QVERIFY(!it.hasNext());
+}
+
+void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
+{
+ QJSEngine *engine = new QJSEngine;
+ QJSValue objet = engine->newObject();
+
+ // populate object with properties
+ QHash<QString, int> properties;
+ properties.insert("foo",1235);
+ properties.insert("oof",5321);
+ properties.insert("ofo",3521);
+ QHash<QString, int>::const_iterator i = properties.constBegin();
+ for (; i != properties.constEnd(); ++i) {
+ objet.setProperty(i.key(), i.value());
+ }
+
+ // start iterating
+ QJSValueIterator it(objet);
+ it.next();
+ QVERIFY(properties.contains(it.name()));
+
+ delete engine;
+
+ QVERIFY(!objet.isValid());
+ QVERIFY(it.name().isEmpty());
+ QVERIFY(!it.value().isValid());
+
+ QVERIFY(!it.hasNext());
+ it.next();
+
+ QVERIFY(it.name().isEmpty());
+ QVERIFY(!it.value().isValid());
+
+}
+
+QTEST_MAIN(tst_QJSValueIterator)
+#include "tst_qjsvalueiterator.moc"
diff --git a/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro b/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro
index c1a3f00aff..5da2ba95b9 100644
--- a/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro
+++ b/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro
@@ -15,4 +15,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/declarative/qsgborderimage/qsgborderimage.pro b/tests/auto/declarative/qsgborderimage/qsgborderimage.pro
index f75405bf43..db7fe77e1d 100644
--- a/tests/auto/declarative/qsgborderimage/qsgborderimage.pro
+++ b/tests/auto/declarative/qsgborderimage/qsgborderimage.pro
@@ -16,4 +16,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/declarative/qsgflickable/qsgflickable.pro b/tests/auto/declarative/qsgflickable/qsgflickable.pro
index 70956f3755..d5e5767e90 100644
--- a/tests/auto/declarative/qsgflickable/qsgflickable.pro
+++ b/tests/auto/declarative/qsgflickable/qsgflickable.pro
@@ -15,4 +15,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/declarative/qsgflipable/qsgflipable.pro b/tests/auto/declarative/qsgflipable/qsgflipable.pro
index 6cd52ec85f..c3998c1f9c 100644
--- a/tests/auto/declarative/qsgflipable/qsgflipable.pro
+++ b/tests/auto/declarative/qsgflipable/qsgflipable.pro
@@ -15,4 +15,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/declarative/qsggridview/qsggridview.pro b/tests/auto/declarative/qsggridview/qsggridview.pro
index 963df7a9b7..a8b3484f0d 100644
--- a/tests/auto/declarative/qsggridview/qsggridview.pro
+++ b/tests/auto/declarative/qsggridview/qsggridview.pro
@@ -15,5 +15,4 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgitem2/qsgitem.pro b/tests/auto/declarative/qsgitem2/qsgitem.pro
index 9226b4178d..afab61dec3 100644
--- a/tests/auto/declarative/qsgitem2/qsgitem.pro
+++ b/tests/auto/declarative/qsgitem2/qsgitem.pro
@@ -15,5 +15,4 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private opengl-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsglistview/qsglistview.pro b/tests/auto/declarative/qsglistview/qsglistview.pro
index 8650d75210..9b31bcb7bf 100644
--- a/tests/auto/declarative/qsglistview/qsglistview.pro
+++ b/tests/auto/declarative/qsglistview/qsglistview.pro
@@ -15,5 +15,4 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgpathview/qsgpathview.pro b/tests/auto/declarative/qsgpathview/qsgpathview.pro
index 70279757a5..eb188666bb 100644
--- a/tests/auto/declarative/qsgpathview/qsgpathview.pro
+++ b/tests/auto/declarative/qsgpathview/qsgpathview.pro
@@ -15,4 +15,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/declarative/qsgpositioners/qsgpositioners.pro b/tests/auto/declarative/qsgpositioners/qsgpositioners.pro
index 9602c721c2..bf8110ffd4 100644
--- a/tests/auto/declarative/qsgpositioners/qsgpositioners.pro
+++ b/tests/auto/declarative/qsgpositioners/qsgpositioners.pro
@@ -14,5 +14,4 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgtext/qsgtext.pro b/tests/auto/declarative/qsgtext/qsgtext.pro
index 99aac1982f..5254d1ebeb 100644
--- a/tests/auto/declarative/qsgtext/qsgtext.pro
+++ b/tests/auto/declarative/qsgtext/qsgtext.pro
@@ -20,5 +20,4 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgtextedit/qsgtextedit.pro b/tests/auto/declarative/qsgtextedit/qsgtextedit.pro
index be8d98ba01..fea4b71369 100644
--- a/tests/auto/declarative/qsgtextedit/qsgtextedit.pro
+++ b/tests/auto/declarative/qsgtextedit/qsgtextedit.pro
@@ -13,5 +13,4 @@ symbian: {
DEFINES += SRCDIR=\\\"$$PWD\\\"
}
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgtextinput/qsgtextinput.pro b/tests/auto/declarative/qsgtextinput/qsgtextinput.pro
index d3d03e7db1..56a811fa6d 100644
--- a/tests/auto/declarative/qsgtextinput/qsgtextinput.pro
+++ b/tests/auto/declarative/qsgtextinput/qsgtextinput.pro
@@ -13,5 +13,4 @@ symbian: {
}
QT += core-private gui-private declarative-private
-QT += script-private
QT += opengl-private
diff --git a/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro b/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro
index 7b961b6298..8f433c1208 100644
--- a/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro
+++ b/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro
@@ -15,4 +15,3 @@ symbian: {
CONFIG += parallel_test
QT += core-private gui-private declarative-private
-QT += script-private
diff --git a/tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro b/tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro
index fb1ef04ee1..6c3bec845a 100644
--- a/tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro
+++ b/tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro b/tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro
index 79b61d81c4..c01478380b 100644
--- a/tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro
+++ b/tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro
index e08611cbbd..64d5d0a518 100644
--- a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro
+++ b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro b/tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro
index bdff620e95..eb125599e1 100644
--- a/tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro
+++ b/tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro
index b1e51f28bf..059f923c17 100644
--- a/tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro
+++ b/tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro
@@ -1,6 +1,5 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative qtquick1
-QT += script
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativelistmodel.cpp
@@ -15,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro b/tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro
index 0454d4476a..5eb154dad2 100644
--- a/tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro
+++ b/tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro
@@ -14,4 +14,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro b/tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro
index 251277ef57..4233096a2d 100644
--- a/tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro
+++ b/tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro b/tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
index f9a0b17f81..99094cf101 100644
--- a/tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
+++ b/tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro b/tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro
index 10132374e2..56f9c2df17 100644
--- a/tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro
+++ b/tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro b/tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro
index 79990aa31a..b80ab88f01 100644
--- a/tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro
+++ b/tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro
@@ -13,4 +13,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro b/tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro
index fbb88ae1fa..ad9a667d57 100644
--- a/tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro
+++ b/tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro
@@ -19,4 +19,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro b/tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro
index 93019a53c5..a5a0add30f 100644
--- a/tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro
+++ b/tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro b/tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
index 6a4a50c7a3..6acfe35dca 100644
--- a/tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
+++ b/tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script gui network qtquick1
+contains(QT_CONFIG,declarative): QT += declarative gui network qtquick1
contains(QT_CONFIG,xmlpatterns) {
QT += xmlpatterns
DEFINES += QTEST_XMLPATTERNS
@@ -18,4 +18,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private qtquick1-private
+QT += core-private gui-private declarative-private qtquick1-private
diff --git a/tests/benchmarks/declarative/holistic/holistic.pro b/tests/benchmarks/declarative/holistic/holistic.pro
index 7f27696d60..fadb04db88 100644
--- a/tests/benchmarks/declarative/holistic/holistic.pro
+++ b/tests/benchmarks/declarative/holistic/holistic.pro
@@ -1,7 +1,7 @@
load(qttest_p4)
TEMPLATE = app
TARGET = tst_holistic
-QT += declarative script network
+QT += declarative network
macx:CONFIG -= app_bundle
CONFIG += release
diff --git a/tests/benchmarks/declarative/holistic/testtypes.h b/tests/benchmarks/declarative/holistic/testtypes.h
index 5a2b1c8ab1..7d1a59da44 100644
--- a/tests/benchmarks/declarative/holistic/testtypes.h
+++ b/tests/benchmarks/declarative/holistic/testtypes.h
@@ -53,7 +53,7 @@
#include <QtGui/qpixmap.h>
#include <QtGui/qvector3d.h>
#include <QtCore/qdatetime.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtScript/qjsvalue.h>
#include <QtDeclarative/qdeclarativescriptstring.h>
#include <QtDeclarative/qdeclarativecomponent.h>
diff --git a/tests/benchmarks/declarative/script/script.pro b/tests/benchmarks/declarative/script/script.pro
index 75faa5cf38..01df571fda 100644
--- a/tests/benchmarks/declarative/script/script.pro
+++ b/tests/benchmarks/declarative/script/script.pro
@@ -1,7 +1,7 @@
load(qttest_p4)
TEMPLATE = app
TARGET = tst_script
-QT += declarative script
+QT += declarative
macx:CONFIG -= app_bundle
CONFIG += release