summaryrefslogtreecommitdiffstats
path: root/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp')
-rw-r--r--tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp2883
1 files changed, 2883 insertions, 0 deletions
diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
new file mode 100644
index 0000000..85693dc
--- /dev/null
+++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
@@ -0,0 +1,2883 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** 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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qscriptengine.h>
+#include <qscriptcontext.h>
+#include <qscriptvalueiterator.h>
+#include <qwidget.h>
+#include <qpushbutton.h>
+#include <qlineedit.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=script/qscriptextqobject_p.h script/qscriptextqobject.cpp
+
+struct CustomType
+{
+ QString string;
+};
+Q_DECLARE_METATYPE(CustomType)
+
+Q_DECLARE_METATYPE(QBrush*)
+Q_DECLARE_METATYPE(QObjectList)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(Qt::BrushStyle)
+Q_DECLARE_METATYPE(QDir)
+
+static void dirFromScript(const QScriptValue &in, QDir &out)
+{
+ QScriptValue path = in.property("path");
+ if (!path.isValid())
+ in.engine()->currentContext()->throwError("No path");
+ else
+ out.setPath(path.toString());
+}
+
+namespace MyNS
+{
+ class A : public QObject
+ {
+ Q_OBJECT
+ public:
+ enum Type {
+ Foo,
+ Bar
+ };
+ Q_ENUMS(Type)
+ public Q_SLOTS:
+ int slotTakingScopedEnumArg(MyNS::A::Type t) {
+ return t;
+ }
+ };
+}
+
+class MyQObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
+ Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
+ Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
+ Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
+ Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
+ Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
+ Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
+ Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
+ Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
+ Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
+ Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
+ Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
+ Q_PROPERTY(Policy enumProperty READ enumProperty WRITE setEnumProperty)
+ Q_ENUMS(Policy Strategy)
+ Q_FLAGS(Ability)
+
+public:
+ enum Policy {
+ FooPolicy = 0,
+ BarPolicy,
+ BazPolicy
+ };
+
+ enum Strategy {
+ FooStrategy = 10,
+ BarStrategy,
+ BazStrategy
+ };
+
+ enum AbilityFlag {
+ NoAbility = 0x000,
+ FooAbility = 0x001,
+ BarAbility = 0x080,
+ BazAbility = 0x200,
+ AllAbility = FooAbility | BarAbility | BazAbility
+ };
+
+ Q_DECLARE_FLAGS(Ability, AbilityFlag)
+
+ MyQObject(QObject *parent = 0)
+ : QObject(parent),
+ m_intValue(123),
+ m_variantValue(QLatin1String("foo")),
+ m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
+ m_stringValue(QLatin1String("bar")),
+ m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
+ m_brushValue(QColor(10, 20, 30, 40)),
+ m_hiddenValue(456.0),
+ m_writeOnlyValue(789),
+ m_readOnlyValue(987),
+ m_enumValue(BarPolicy),
+ m_qtFunctionInvoked(-1)
+ { }
+
+ int intProperty() const
+ { return m_intValue; }
+ void setIntProperty(int value)
+ { m_intValue = value; }
+
+ QVariant variantProperty() const
+ { return m_variantValue; }
+ void setVariantProperty(const QVariant &value)
+ { m_variantValue = value; }
+
+ QVariantList variantListProperty() const
+ { return m_variantListValue; }
+ void setVariantListProperty(const QVariantList &value)
+ { m_variantListValue = value; }
+
+ QString stringProperty() const
+ { return m_stringValue; }
+ void setStringProperty(const QString &value)
+ { m_stringValue = value; }
+
+ QStringList stringListProperty() const
+ { return m_stringListValue; }
+ void setStringListProperty(const QStringList &value)
+ { m_stringListValue = value; }
+
+ QByteArray byteArrayProperty() const
+ { return m_byteArrayValue; }
+ void setByteArrayProperty(const QByteArray &value)
+ { m_byteArrayValue = value; }
+
+ QBrush brushProperty() const
+ { return m_brushValue; }
+ Q_INVOKABLE void setBrushProperty(const QBrush &value)
+ { m_brushValue = value; }
+
+ double hiddenProperty() const
+ { return m_hiddenValue; }
+ void setHiddenProperty(double value)
+ { m_hiddenValue = value; }
+
+ int writeOnlyProperty() const
+ { return m_writeOnlyValue; }
+ void setWriteOnlyProperty(int value)
+ { m_writeOnlyValue = value; }
+
+ int readOnlyProperty() const
+ { return m_readOnlyValue; }
+
+ QKeySequence shortcut() const
+ { return m_shortcut; }
+ void setShortcut(const QKeySequence &seq)
+ { m_shortcut = seq; }
+
+ CustomType propWithCustomType() const
+ { return m_customType; }
+ void setPropWithCustomType(const CustomType &c)
+ { m_customType = c; }
+
+ Policy enumProperty() const
+ { return m_enumValue; }
+ void setEnumProperty(Policy policy)
+ { m_enumValue = policy; }
+
+ int qtFunctionInvoked() const
+ { return m_qtFunctionInvoked; }
+
+ QVariantList qtFunctionActuals() const
+ { return m_actuals; }
+
+ void resetQtFunctionInvoked()
+ { m_qtFunctionInvoked = -1; m_actuals.clear(); }
+
+ void clearConnectedSignal()
+ { m_connectedSignal = QByteArray(); }
+ void clearDisconnectedSignal()
+ { m_disconnectedSignal = QByteArray(); }
+ QByteArray connectedSignal() const
+ { return m_connectedSignal; }
+ QByteArray disconnectedSignal() const
+ { return m_disconnectedSignal; }
+
+ Q_INVOKABLE void myInvokable()
+ { m_qtFunctionInvoked = 0; }
+ Q_INVOKABLE void myInvokableWithIntArg(int arg)
+ { m_qtFunctionInvoked = 1; m_actuals << arg; }
+ Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg)
+ { m_qtFunctionInvoked = 2; m_actuals << arg; }
+ Q_INVOKABLE void myInvokableWithFloatArg(float arg)
+ { m_qtFunctionInvoked = 3; m_actuals << arg; }
+ Q_INVOKABLE void myInvokableWithDoubleArg(double arg)
+ { m_qtFunctionInvoked = 4; m_actuals << arg; }
+ Q_INVOKABLE void myInvokableWithStringArg(const QString &arg)
+ { m_qtFunctionInvoked = 5; m_actuals << arg; }
+ Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2)
+ { m_qtFunctionInvoked = 6; m_actuals << arg1 << arg2; }
+ Q_INVOKABLE int myInvokableReturningInt()
+ { m_qtFunctionInvoked = 7; return 123; }
+ Q_INVOKABLE qlonglong myInvokableReturningLongLong()
+ { m_qtFunctionInvoked = 39; return 456; }
+ Q_INVOKABLE QString myInvokableReturningString()
+ { m_qtFunctionInvoked = 8; return QLatin1String("ciao"); }
+ Q_INVOKABLE QVariant myInvokableReturningVariant()
+ { m_qtFunctionInvoked = 60; return 123; }
+ Q_INVOKABLE QScriptValue myInvokableReturningScriptValue()
+ { m_qtFunctionInvoked = 61; return 456; }
+ Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // overload
+ { m_qtFunctionInvoked = 9; m_actuals << arg1 << arg2; }
+ Q_INVOKABLE void myInvokableWithEnumArg(Policy policy)
+ { m_qtFunctionInvoked = 10; m_actuals << policy; }
+ Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy)
+ { m_qtFunctionInvoked = 36; m_actuals << policy; }
+ Q_INVOKABLE Policy myInvokableReturningEnum()
+ { m_qtFunctionInvoked = 37; return BazPolicy; }
+ Q_INVOKABLE MyQObject::Strategy myInvokableReturningQualifiedEnum()
+ { m_qtFunctionInvoked = 38; return BazStrategy; }
+ Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt()
+ { m_qtFunctionInvoked = 11; return QVector<int>(); }
+ Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &)
+ { m_qtFunctionInvoked = 12; }
+ Q_INVOKABLE QObject *myInvokableReturningQObjectStar()
+ { m_qtFunctionInvoked = 13; return this; }
+ Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst)
+ { m_qtFunctionInvoked = 14; m_actuals << qVariantFromValue(lst); return lst; }
+ Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v)
+ { m_qtFunctionInvoked = 15; m_actuals << v; return v; }
+ Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm)
+ { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; }
+ Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst)
+ { m_qtFunctionInvoked = 17; m_actuals << qVariantFromValue(lst); return lst; }
+ Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj)
+ { m_qtFunctionInvoked = 18; m_actuals << qVariantFromValue(obj); return obj; }
+ Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush)
+ { m_qtFunctionInvoked = 19; m_actuals << qVariantFromValue(brush); return brush; }
+ Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style)
+ { m_qtFunctionInvoked = 43; m_actuals << qVariantFromValue(style); }
+ Q_INVOKABLE void myInvokableWithVoidStarArg(void *arg)
+ { m_qtFunctionInvoked = 44; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg)
+ { m_qtFunctionInvoked = 45; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg)
+ { m_qtFunctionInvoked = 46; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "")
+ { m_qtFunctionInvoked = 47; m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2); }
+ Q_INVOKABLE QObject& myInvokableReturningRef()
+ { m_qtFunctionInvoked = 48; return *this; }
+ Q_INVOKABLE const QObject& myInvokableReturningConstRef() const
+ { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49; return *this; }
+ Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg)
+ { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg)
+ { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE void myInvokableWithMyQObjectArg(MyQObject *arg)
+ { m_qtFunctionInvoked = 52; m_actuals << qVariantFromValue((QObject*)arg); }
+ Q_INVOKABLE MyQObject* myInvokableReturningMyQObject()
+ { m_qtFunctionInvoked = 53; return this; }
+ Q_INVOKABLE void myInvokableWithConstMyQObjectArg(const MyQObject *arg)
+ { m_qtFunctionInvoked = 54; m_actuals << qVariantFromValue((QObject*)arg); }
+ Q_INVOKABLE void myInvokableWithQDirArg(const QDir &arg)
+ { m_qtFunctionInvoked = 55; m_actuals << qVariantFromValue(arg); }
+ Q_INVOKABLE QScriptValue myInvokableWithScriptValueArg(const QScriptValue &arg)
+ { m_qtFunctionInvoked = 56; return arg; }
+ Q_INVOKABLE QObject* myInvokableReturningMyQObjectAsQObject()
+ { m_qtFunctionInvoked = 57; return this; }
+
+ void emitMySignal()
+ { emit mySignal(); }
+ void emitMySignalWithIntArg(int arg)
+ { emit mySignalWithIntArg(arg); }
+ void emitMySignal2(bool arg)
+ { emit mySignal2(arg); }
+ void emitMySignal2()
+ { emit mySignal2(); }
+ void emitMyOverloadedSignal(int arg)
+ { emit myOverloadedSignal(arg); }
+ void emitMyOverloadedSignal(const QString &arg)
+ { emit myOverloadedSignal(arg); }
+ void emitMyOtherOverloadedSignal(const QString &arg)
+ { emit myOtherOverloadedSignal(arg); }
+ void emitMyOtherOverloadedSignal(int arg)
+ { emit myOtherOverloadedSignal(arg); }
+ void emitMySignalWithDefaultArgWithArg(int arg)
+ { emit mySignalWithDefaultArg(arg); }
+ void emitMySignalWithDefaultArg()
+ { emit mySignalWithDefaultArg(); }
+ void emitMySignalWithVariantArg(const QVariant &arg)
+ { emit mySignalWithVariantArg(arg); }
+ void emitMySignalWithScriptEngineArg(QScriptEngine *arg)
+ { emit mySignalWithScriptEngineArg(arg); }
+
+public Q_SLOTS:
+ void mySlot()
+ { m_qtFunctionInvoked = 20; }
+ void mySlotWithIntArg(int arg)
+ { m_qtFunctionInvoked = 21; m_actuals << arg; }
+ void mySlotWithDoubleArg(double arg)
+ { m_qtFunctionInvoked = 22; m_actuals << arg; }
+ void mySlotWithStringArg(const QString &arg)
+ { m_qtFunctionInvoked = 23; m_actuals << arg; }
+
+ void myOverloadedSlot()
+ { m_qtFunctionInvoked = 24; }
+ void myOverloadedSlot(QObject *arg)
+ { m_qtFunctionInvoked = 41; m_actuals << qVariantFromValue(arg); }
+ void myOverloadedSlot(bool arg)
+ { m_qtFunctionInvoked = 25; m_actuals << arg; }
+ void myOverloadedSlot(const QStringList &arg)
+ { m_qtFunctionInvoked = 42; m_actuals << arg; }
+ void myOverloadedSlot(double arg)
+ { m_qtFunctionInvoked = 26; m_actuals << arg; }
+ void myOverloadedSlot(float arg)
+ { m_qtFunctionInvoked = 27; m_actuals << arg; }
+ void myOverloadedSlot(int arg)
+ { m_qtFunctionInvoked = 28; m_actuals << arg; }
+ void myOverloadedSlot(const QString &arg)
+ { m_qtFunctionInvoked = 29; m_actuals << arg; }
+ void myOverloadedSlot(const QColor &arg)
+ { m_qtFunctionInvoked = 30; m_actuals << arg; }
+ void myOverloadedSlot(const QBrush &arg)
+ { m_qtFunctionInvoked = 31; m_actuals << arg; }
+ void myOverloadedSlot(const QDateTime &arg)
+ { m_qtFunctionInvoked = 32; m_actuals << arg; }
+ void myOverloadedSlot(const QDate &arg)
+ { m_qtFunctionInvoked = 33; m_actuals << arg; }
+ void myOverloadedSlot(const QRegExp &arg)
+ { m_qtFunctionInvoked = 34; m_actuals << arg; }
+ void myOverloadedSlot(const QVariant &arg)
+ { m_qtFunctionInvoked = 35; m_actuals << arg; }
+
+ virtual int myVirtualSlot(int arg)
+ { m_qtFunctionInvoked = 58; return arg; }
+
+ void qscript_call(int arg)
+ { m_qtFunctionInvoked = 40; m_actuals << arg; }
+
+protected Q_SLOTS:
+ void myProtectedSlot() { m_qtFunctionInvoked = 36; }
+
+private Q_SLOTS:
+ void myPrivateSlot() { }
+
+Q_SIGNALS:
+ void mySignal();
+ void mySignalWithIntArg(int arg);
+ void mySignalWithDoubleArg(double arg);
+ void mySignal2(bool arg = false);
+ void myOverloadedSignal(int arg);
+ void myOverloadedSignal(const QString &arg);
+ void myOtherOverloadedSignal(const QString &arg);
+ void myOtherOverloadedSignal(int arg);
+ void mySignalWithDefaultArg(int arg = 123);
+ void mySignalWithVariantArg(const QVariant &arg);
+ void mySignalWithScriptEngineArg(QScriptEngine *arg);
+
+protected:
+ void connectNotify(const char *signal) {
+ m_connectedSignal = signal;
+ }
+ void disconnectNotify(const char *signal) {
+ m_disconnectedSignal = signal;
+ }
+
+protected:
+ int m_intValue;
+ QVariant m_variantValue;
+ QVariantList m_variantListValue;
+ QString m_stringValue;
+ QStringList m_stringListValue;
+ QByteArray m_byteArrayValue;
+ QBrush m_brushValue;
+ double m_hiddenValue;
+ int m_writeOnlyValue;
+ int m_readOnlyValue;
+ QKeySequence m_shortcut;
+ CustomType m_customType;
+ Policy m_enumValue;
+ int m_qtFunctionInvoked;
+ QVariantList m_actuals;
+ QByteArray m_connectedSignal;
+ QByteArray m_disconnectedSignal;
+};
+
+Q_DECLARE_METATYPE(MyQObject*)
+Q_DECLARE_METATYPE(MyQObject::Policy)
+
+class MyOtherQObject : public MyQObject
+{
+ Q_OBJECT
+public:
+ MyOtherQObject(QObject *parent = 0)
+ : MyQObject(parent)
+ { }
+public Q_SLOTS:
+ virtual int myVirtualSlot(int arg)
+ { m_qtFunctionInvoked = 59; return arg; }
+};
+
+class MyEnumTestQObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString p1 READ p1)
+ Q_PROPERTY(QString p2 READ p2)
+ Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
+ Q_PROPERTY(QString p4 READ p4)
+ Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
+ Q_PROPERTY(QString p6 READ p6)
+public:
+ MyEnumTestQObject(QObject *parent = 0)
+ : QObject(parent) { }
+ QString p1() const { return QLatin1String("p1"); }
+ QString p2() const { return QLatin1String("p2"); }
+ QString p3() const { return QLatin1String("p3"); }
+ QString p4() const { return QLatin1String("p4"); }
+ QString p5() const { return QLatin1String("p5"); }
+ QString p6() const { return QLatin1String("p5"); }
+public Q_SLOTS:
+ void mySlot() { }
+ void myOtherSlot() { }
+Q_SIGNALS:
+ void mySignal();
+};
+
+class tst_QScriptExtQObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QScriptExtQObject();
+ virtual ~tst_QScriptExtQObject();
+
+public slots:
+ void init();
+ void cleanup();
+
+protected slots:
+ void onSignalHandlerException(const QScriptValue &exception)
+ {
+ m_signalHandlerException = exception;
+ }
+
+private slots:
+ void getSetStaticProperty();
+ void getSetDynamicProperty();
+ void getSetChildren();
+ void callQtInvokable();
+ void connectAndDisconnect();
+ void cppConnectAndDisconnect();
+ void classEnums();
+ void classConstructor();
+ void overrideInvokable();
+ void transferInvokable();
+ void findChild();
+ void findChildren();
+ void overloadedSlots();
+ void enumerate_data();
+ void enumerate();
+ void enumerateSpecial();
+ void wrapOptions();
+ void prototypes();
+ void objectDeleted();
+ void connectToDestroyedSignal();
+
+private:
+ QScriptEngine *m_engine;
+ MyQObject *m_myObject;
+ QScriptValue m_signalHandlerException;
+};
+
+tst_QScriptExtQObject::tst_QScriptExtQObject()
+{
+}
+
+tst_QScriptExtQObject::~tst_QScriptExtQObject()
+{
+}
+
+void tst_QScriptExtQObject::init()
+{
+ m_engine = new QScriptEngine();
+ m_myObject = new MyQObject();
+ m_engine->globalObject().setProperty("myObject", m_engine->newQObject(m_myObject));
+ m_engine->globalObject().setProperty("global", m_engine->globalObject());
+}
+
+void tst_QScriptExtQObject::cleanup()
+{
+ delete m_engine;
+ delete m_myObject;
+}
+
+static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() != 0)
+ ctx->callee().setProperty("value", ctx->argument(0));
+ return ctx->callee().property("value");
+}
+
+static QScriptValue policyToScriptValue(QScriptEngine *engine, const MyQObject::Policy &policy)
+{
+ return qScriptValueFromValue(engine, policy);
+}
+
+static void policyFromScriptValue(const QScriptValue &value, MyQObject::Policy &policy)
+{
+ QString str = value.toString();
+ if (str == QLatin1String("red"))
+ policy = MyQObject::FooPolicy;
+ else if (str == QLatin1String("green"))
+ policy = MyQObject::BarPolicy;
+ else if (str == QLatin1String("blue"))
+ policy = MyQObject::BazPolicy;
+ else
+ policy = (MyQObject::Policy)-1;
+}
+
+void tst_QScriptExtQObject::getSetStaticProperty()
+{
+ QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true);
+
+ // initial value (set in MyQObject constructor)
+ QCOMPARE(m_engine->evaluate("myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123.0)), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantProperty")
+ .toVariant(), QVariant(QLatin1String("foo")));
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty").isArray(), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty.length")
+ .strictlyEquals(QScriptValue(m_engine, 2)), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty").isArray(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty.length")
+ .strictlyEquals(QScriptValue(m_engine, 2)), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
+ QLatin1String("zig"));
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
+ QLatin1String("zag"));
+
+ // default flags for "normal" properties
+ {
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+ QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::ReadOnly));
+ QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::Undeletable);
+ QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertyGetter);
+ QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertySetter);
+ QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::SkipInEnumeration));
+ QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
+
+ QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::ReadOnly));
+ QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::Undeletable));
+ QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::SkipInEnumeration));
+ QVERIFY(mobj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
+
+ // signature-based property
+ QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::ReadOnly));
+ QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::Undeletable));
+ QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::SkipInEnumeration));
+ QVERIFY(mobj.propertyFlags("mySlot()") & QScriptValue::QObjectMember);
+ }
+
+ // property change in C++ should be reflected in script
+ m_myObject->setIntProperty(456);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 456)), true);
+ m_myObject->setIntProperty(789);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 789)), true);
+
+ m_myObject->setVariantProperty(QLatin1String("bar"));
+ QVERIFY(m_engine->evaluate("myObject.variantProperty")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))));
+ m_myObject->setVariantProperty(42);
+ QCOMPARE(m_engine->evaluate("myObject.variantProperty")
+ .toVariant(), QVariant(42));
+ m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
+ QVERIFY(m_engine->evaluate("myObject.variantProperty").isVariant());
+
+ m_myObject->setStringProperty(QLatin1String("baz"));
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty")
+ .equals(QScriptValue(m_engine, QLatin1String("baz"))), true);
+ m_myObject->setStringProperty(QLatin1String("zab"));
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty")
+ .equals(QScriptValue(m_engine, QLatin1String("zab"))), true);
+
+ // property change in script should be reflected in C++
+ QCOMPARE(m_engine->evaluate("myObject.intProperty = 123")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(m_myObject->intProperty(), 123);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty = 'ciao!';"
+ "myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 0)), true);
+ QCOMPARE(m_myObject->intProperty(), 0);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty = '123';"
+ "myObject.intProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(m_myObject->intProperty(), 123);
+
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty = 'ciao'")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
+ QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
+ QCOMPARE(m_engine->evaluate("myObject.stringProperty = 123;"
+ "myObject.stringProperty")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("123"))), true);
+ QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
+ QVERIFY(m_engine->evaluate("myObject.stringProperty = null;"
+ "myObject.stringProperty")
+ .strictlyEquals(QScriptValue(m_engine, QString())));
+ QCOMPARE(m_myObject->stringProperty(), QString());
+ QVERIFY(m_engine->evaluate("myObject.stringProperty = undefined;"
+ "myObject.stringProperty")
+ .strictlyEquals(QScriptValue(m_engine, QString())));
+ QCOMPARE(m_myObject->stringProperty(), QString());
+
+ QCOMPARE(m_engine->evaluate("myObject.variantProperty = 'foo';"
+ "myObject.variantProperty.valueOf()").toString(), QLatin1String("foo"));
+ QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
+ QVERIFY(m_engine->evaluate("myObject.variantProperty = undefined;"
+ "myObject.variantProperty").isUndefined());
+ QVERIFY(!m_myObject->variantProperty().isValid());
+ QVERIFY(m_engine->evaluate("myObject.variantProperty = null;"
+ "myObject.variantProperty").isUndefined());
+ QVERIFY(!m_myObject->variantProperty().isValid());
+ QCOMPARE(m_engine->evaluate("myObject.variantProperty = 42;"
+ "myObject.variantProperty").toNumber(), 42.0);
+ QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
+
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty = [1, 'two', true];"
+ "myObject.variantListProperty.length")
+ .strictlyEquals(QScriptValue(m_engine, 3)), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
+ .strictlyEquals(QScriptValue(m_engine, 1)), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("two"))), true);
+ QCOMPARE(m_engine->evaluate("myObject.variantListProperty[2]")
+ .strictlyEquals(QScriptValue(m_engine, true)), true);
+ {
+ QVariantList vl = qscriptvalue_cast<QVariantList>(m_engine->evaluate("myObject.variantListProperty"));
+ QCOMPARE(vl, QVariantList()
+ << QVariant(1)
+ << QVariant(QLatin1String("two"))
+ << QVariant(true));
+ }
+
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty = [1, 'two', true];"
+ "myObject.stringListProperty.length")
+ .strictlyEquals(QScriptValue(m_engine, 3)), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
+ QLatin1String("1"));
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
+ QLatin1String("two"));
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").isString(), true);
+ QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").toString(),
+ QLatin1String("true"));
+ {
+ QStringList sl = qscriptvalue_cast<QStringList>(m_engine->evaluate("myObject.stringListProperty"));
+ QCOMPARE(sl, QStringList()
+ << QLatin1String("1")
+ << QLatin1String("two")
+ << QLatin1String("true"));
+ }
+
+ // test setting properties where we can't convert the type natively but where the
+ // types happen to be compatible variant types already
+ {
+ QKeySequence sequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_Delete);
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+
+ QVERIFY(m_myObject->shortcut().isEmpty());
+ mobj.setProperty("shortcut", m_engine->newVariant(sequence));
+ QVERIFY(m_myObject->shortcut() == sequence);
+ }
+ {
+ CustomType t; t.string = "hello";
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+
+ QVERIFY(m_myObject->propWithCustomType().string.isEmpty());
+ mobj.setProperty("propWithCustomType", m_engine->newVariant(qVariantFromValue(t)));
+ QVERIFY(m_myObject->propWithCustomType().string == t.string);
+ }
+
+ // test that we do value conversion if necessary when setting properties
+ {
+ QScriptValue br = m_engine->evaluate("myObject.brushProperty");
+ QVERIFY(br.isVariant());
+ QVERIFY(!br.strictlyEquals(m_engine->evaluate("myObject.brushProperty")));
+ QCOMPARE(qscriptvalue_cast<QBrush>(br), m_myObject->brushProperty());
+ QCOMPARE(qscriptvalue_cast<QColor>(br), m_myObject->brushProperty().color());
+
+ QColor newColor(40, 30, 20, 10);
+ QScriptValue val = qScriptValueFromValue(m_engine, newColor);
+ m_engine->globalObject().setProperty("myColor", val);
+ QScriptValue ret = m_engine->evaluate("myObject.brushProperty = myColor");
+ QCOMPARE(ret.strictlyEquals(val), true);
+ br = m_engine->evaluate("myObject.brushProperty");
+ QCOMPARE(qscriptvalue_cast<QBrush>(br), QBrush(newColor));
+ QCOMPARE(qscriptvalue_cast<QColor>(br), newColor);
+
+ m_engine->globalObject().setProperty("myColor", QScriptValue());
+ }
+
+ // try to delete
+ QCOMPARE(m_engine->evaluate("delete myObject.intProperty").toBoolean(), false);
+ QCOMPARE(m_engine->evaluate("myObject.intProperty").toNumber(), 123.0);
+
+ QCOMPARE(m_engine->evaluate("delete myObject.variantProperty").toBoolean(), false);
+ QCOMPARE(m_engine->evaluate("myObject.variantProperty").toNumber(), 42.0);
+
+ // non-scriptable property
+ QCOMPARE(m_myObject->hiddenProperty(), 456.0);
+ QCOMPARE(m_engine->evaluate("myObject.hiddenProperty").isUndefined(), true);
+ QCOMPARE(m_engine->evaluate("myObject.hiddenProperty = 123;"
+ "myObject.hiddenProperty").toInt32(), 123);
+ QCOMPARE(m_myObject->hiddenProperty(), 456.0);
+
+ // write-only property
+ QCOMPARE(m_myObject->writeOnlyProperty(), 789);
+ QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty").isUndefined(), true);
+ QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty = 123;"
+ "myObject.writeOnlyProperty").isUndefined(), true);
+ QCOMPARE(m_myObject->writeOnlyProperty(), 123);
+
+ // read-only property
+ QCOMPARE(m_myObject->readOnlyProperty(), 987);
+ QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty").toInt32(), 987);
+ QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty = 654;"
+ "myObject.readOnlyProperty").toInt32(), 987);
+ QCOMPARE(m_myObject->readOnlyProperty(), 987);
+ {
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+ QCOMPARE(mobj.propertyFlags("readOnlyProperty") & QScriptValue::ReadOnly,
+ QScriptValue::ReadOnly);
+ }
+
+ // enum property
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ {
+ QScriptValue val = m_engine->evaluate("myObject.enumProperty");
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), (int)MyQObject::BarPolicy);
+ }
+ m_engine->evaluate("myObject.enumProperty = 2");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'BarPolicy'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'ScoobyDoo'");
+ // ### ouch! Shouldn't QMetaProperty::write() rather not change the value...?
+ QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
+ // enum property with custom conversion
+ qScriptRegisterMetaType<MyQObject::Policy>(m_engine, policyToScriptValue, policyFromScriptValue);
+ m_engine->evaluate("myObject.enumProperty = 'red'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::FooPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'green'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'blue'");
+ QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
+ m_engine->evaluate("myObject.enumProperty = 'nada'");
+ QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
+
+ // auto-dereferencing of pointers
+ {
+ QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE);
+ QBrush *bp = &b;
+ QScriptValue bpValue = m_engine->newVariant(qVariantFromValue(bp));
+ m_engine->globalObject().setProperty("brushPointer", bpValue);
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.setBrushProperty(brushPointer)");
+ QCOMPARE(ret.isUndefined(), true);
+ QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
+ }
+ {
+ b = QColor(0xDE, 0xAD, 0xBE, 0xEF);
+ QScriptValue ret = m_engine->evaluate("myObject.brushProperty = brushPointer");
+ QCOMPARE(ret.strictlyEquals(bpValue), true);
+ QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
+ }
+ m_engine->globalObject().setProperty("brushPointer", QScriptValue());
+ }
+
+ // try to install custom property getter+setter
+ {
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setProperty() failed: "
+ "cannot set getter or setter of native property "
+ "`intProperty'");
+ mobj.setProperty("intProperty", m_engine->newFunction(getSetProperty),
+ QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ }
+
+ // method properties are persistent
+ {
+ QScriptValue slot = m_engine->evaluate("myObject.mySlot");
+ QVERIFY(slot.isFunction());
+ QScriptValue sameSlot = m_engine->evaluate("myObject.mySlot");
+ QVERIFY(sameSlot.strictlyEquals(slot));
+ sameSlot = m_engine->evaluate("myObject['mySlot()']");
+ QEXPECT_FAIL("", "Signature-based method lookup creates new function wrapper object", Continue);
+ QVERIFY(sameSlot.strictlyEquals(slot));
+ }
+}
+
+void tst_QScriptExtQObject::getSetDynamicProperty()
+{
+ // initially the object does not have the property
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
+ .strictlyEquals(QScriptValue(m_engine, false)), true);
+
+ // add a dynamic property in C++
+ QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
+ .strictlyEquals(QScriptValue(m_engine, true)), true);
+ QCOMPARE(m_engine->evaluate("myObject.dynamicProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+
+ // check the flags
+ {
+ QScriptValue mobj = m_engine->globalObject().property("myObject");
+ QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::ReadOnly));
+ QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::Undeletable));
+ QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::SkipInEnumeration));
+ QVERIFY(mobj.propertyFlags("dynamicProperty") & QScriptValue::QObjectMember);
+ }
+
+ // property change in script should be reflected in C++
+ QCOMPARE(m_engine->evaluate("myObject.dynamicProperty = 'foo';"
+ "myObject.dynamicProperty")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
+ QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
+
+ // delete the property
+ QCOMPARE(m_engine->evaluate("delete myObject.dynamicProperty").toBoolean(), true);
+ QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
+ QCOMPARE(m_engine->evaluate("myObject.dynamicProperty").isUndefined(), true);
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')").toBoolean(), false);
+}
+
+void tst_QScriptExtQObject::getSetChildren()
+{
+ // initially the object does not have the child
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
+ .strictlyEquals(QScriptValue(m_engine, false)), true);
+
+ // add a child
+ MyQObject *child = new MyQObject(m_myObject);
+ child->setObjectName("child");
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
+ .strictlyEquals(QScriptValue(m_engine, true)), true);
+
+ QScriptValue mobj = m_engine->evaluate("myObject");
+ QVERIFY(mobj.propertyFlags("child") & QScriptValue::ReadOnly);
+ QVERIFY(mobj.propertyFlags("child") & QScriptValue::Undeletable);
+ QVERIFY(mobj.propertyFlags("child") & QScriptValue::SkipInEnumeration);
+ QVERIFY(!(mobj.propertyFlags("child") & QScriptValue::QObjectMember));
+
+ {
+ QScriptValue scriptChild = m_engine->evaluate("myObject.child");
+ QVERIFY(scriptChild.isQObject());
+ QCOMPARE(scriptChild.toQObject(), (QObject*)child);
+ QScriptValue sameChild = m_engine->evaluate("myObject.child");
+ QVERIFY(sameChild.strictlyEquals(scriptChild));
+ }
+
+ // add a grandchild
+ MyQObject *grandChild = new MyQObject(child);
+ grandChild->setObjectName("grandChild");
+ QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
+ .strictlyEquals(QScriptValue(m_engine, true)), true);
+
+ // delete grandchild
+ delete grandChild;
+ QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
+ .strictlyEquals(QScriptValue(m_engine, false)), true);
+
+ // delete child
+ delete child;
+ QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
+ .strictlyEquals(QScriptValue(m_engine, false)), true);
+
+}
+
+Q_DECLARE_METATYPE(QVector<int>)
+Q_DECLARE_METATYPE(QVector<double>)
+Q_DECLARE_METATYPE(QVector<QString>)
+
+template <class T>
+static QScriptValue qobjectToScriptValue(QScriptEngine *engine, T* const &in)
+{ return engine->newQObject(in); }
+
+template <class T>
+static void qobjectFromScriptValue(const QScriptValue &object, T* &out)
+{ out = qobject_cast<T*>(object.toQObject()); }
+
+void tst_QScriptExtQObject::callQtInvokable()
+{
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokable()").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ // extra arguments should silently be ignored
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokable(10, 20, 30)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg('123')").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithLonglongArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithFloatArg(123.5)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithDoubleArg(123.5)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg('ciao')").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(null)").isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(undefined)").isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArgs(123, 456)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningInt()")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningLongLong()")
+ .strictlyEquals(QScriptValue(m_engine, 456)), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningString()")
+ .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableReturningVariant()")
+ .strictlyEquals(QScriptValue(m_engine, 123)));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 60);
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableReturningScriptValue()")
+ .strictlyEquals(QScriptValue(m_engine, 456)));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 61);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123, 456)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(123)").isError());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithAmbiguousArg(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(123, 'hello')");
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(456)");
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
+ }
+
+ {
+ QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithPointArg");
+ QVERIFY(fun.isFunction());
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = fun.call(m_engine->evaluate("myObject"),
+ QScriptValueList() << qScriptValueFromValue(m_engine, QPoint(10, 20)));
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 50);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPoint(), QPoint(10, 20));
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = fun.call(m_engine->evaluate("myObject"),
+ QScriptValueList() << qScriptValueFromValue(m_engine, QPointF(30, 40)));
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 51);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPointF(), QPointF(30, 40));
+ }
+ }
+
+ // calling function that returns (const)ref
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningRef()");
+ QVERIFY(ret.isUndefined());
+ QVERIFY(!m_engine->hasUncaughtException());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningConstRef()");
+ QVERIFY(ret.isUndefined());
+ QVERIFY(!m_engine->hasUncaughtException());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
+ }
+
+ // first time we expect failure because the metatype is not registered
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()").isError(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(0)").isError(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+
+ // now we register it, and it should work
+ qScriptRegisterSequenceMetaType<QVector<int> >(m_engine);
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()");
+ QCOMPARE(ret.isArray(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 11);
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(myObject.myInvokableReturningVectorOfInt())");
+ QCOMPARE(ret.isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 12);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQObjectStar()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(ret.isQObject(), true);
+ QCOMPARE(ret.toQObject(), (QObject *)m_myObject);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectListArg([myObject])");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(ret.isArray(), true);
+ QCOMPARE(ret.property(QLatin1String("length"))
+ .strictlyEquals(QScriptValue(m_engine, 1)), true);
+ QCOMPARE(ret.property(QLatin1String("0")).isQObject(), true);
+ QCOMPARE(ret.property(QLatin1String("0")).toQObject(), (QObject *)m_myObject);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ m_myObject->setVariantProperty(QVariant(123));
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
+ QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
+ QVERIFY(ret.isVariant());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
+ QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(123)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
+ QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg('ciao')");
+ QVERIFY(ret.isString());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(QString::fromLatin1("ciao")));
+ QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, QString::fromLatin1("ciao"))));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(null)");
+ QVERIFY(ret.isUndefined()); // invalid QVariant is converted to Undefined
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(undefined)");
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
+ }
+
+ m_engine->globalObject().setProperty("fishy", m_engine->newVariant(123));
+ m_engine->evaluate("myObject.myInvokableWithStringArg(fishy)");
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
+ QVariantMap vmap = qvariant_cast<QVariantMap>(v);
+ QCOMPARE(vmap.keys().size(), 2);
+ QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
+ QCOMPARE(vmap.value("a"), QVariant(123));
+ QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
+ QCOMPARE(vmap.value("b"), QVariant("ciao"));
+
+ QCOMPARE(ret.isObject(), true);
+ QCOMPARE(ret.property("a").strictlyEquals(QScriptValue(m_engine, 123)), true);
+ QCOMPARE(ret.property("b").strictlyEquals(QScriptValue(m_engine, "ciao")), true);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithListOfIntArg([1, 5])");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
+ QList<int> ilst = qvariant_cast<QList<int> >(v);
+ QCOMPARE(ilst.size(), 2);
+ QCOMPARE(ilst.at(0), 1);
+ QCOMPARE(ilst.at(1), 5);
+
+ QCOMPARE(ret.isArray(), true);
+ QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true);
+ QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(myObject)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
+ QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)m_myObject);
+
+ QCOMPARE(ret.isQObject(), true);
+ QCOMPARE(qscriptvalue_cast<QObject*>(ret), (QObject *)m_myObject);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ // no implicit conversion from integer to QObject*
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(123)");
+ QCOMPARE(ret.isError(), true);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithQBrushArg");
+ QVERIFY(fun.isFunction());
+ QColor color(10, 20, 30, 40);
+ // QColor should be converted to a QBrush
+ QScriptValue ret = fun.call(QScriptValue(), QScriptValueList()
+ << qScriptValueFromValue(m_engine, color));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QBrush));
+ QCOMPARE(qvariant_cast<QColor>(v), color);
+
+ QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
+ }
+
+ // private slots should not be part of the QObject binding
+ QCOMPARE(m_engine->evaluate("myObject.myPrivateSlot").isUndefined(), true);
+
+ // protected slots should be fine
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myProtectedSlot()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
+
+ // call with too few arguments
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithIntArg()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
+ }
+
+ // call function where not all types have been registered
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithBrushStyleArg(0)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): argument 1 has unknown type `Qt::BrushStyle' (register the type with qScriptRegisterMetaType())"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+
+ // call function with incompatible argument type
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQBrushArg(null)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+
+ // ability to call a slot with QObject-based arguments, even if those types haven't been registered
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithMyQObjectArg(myObject)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
+ }
+
+ // inability to call a slot returning QObject-based type, when that type hasn't been registered
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: cannot call myInvokableReturningMyQObject(): unknown return type `MyQObject*' (register the type with qScriptRegisterMetaType())"));
+ }
+
+ // ability to call a slot returning QObject-based type when that type has been registered
+ qRegisterMetaType<MyQObject*>("MyQObject*");
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 53);
+ QVERIFY(ret.isVariant());
+ QCOMPARE(*reinterpret_cast<MyQObject* const *>(ret.toVariant().constData()), m_myObject);
+ }
+
+ // ability to call a slot with QObject-based argument, when the argument is const
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithConstMyQObjectArg(myObject)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 54);
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
+ }
+
+ // QScriptValue arguments should be passed on without conversion
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg('ciao')");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(this)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(m_engine->globalObject()));
+ }
+
+ // the prototype specified by a conversion function should not be "down-graded"
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue qobjectProto = m_engine->newObject();
+ qScriptRegisterMetaType<QObject*>(m_engine, qobjectToScriptValue,
+ qobjectFromScriptValue, qobjectProto);
+ QScriptValue myQObjectProto = m_engine->newObject();
+ myQObjectProto.setPrototype(qobjectProto);
+ qScriptRegisterMetaType<MyQObject*>(m_engine, qobjectToScriptValue,
+ qobjectFromScriptValue, myQObjectProto);
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObjectAsQObject()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 57);
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.prototype().strictlyEquals(myQObjectProto));
+
+ qScriptRegisterMetaType<QObject*>(m_engine, 0, 0, QScriptValue());
+ qScriptRegisterMetaType<MyQObject*>(m_engine, 0, 0, QScriptValue());
+ }
+
+ // detect exceptions during argument conversion
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue (*dummy)(QScriptEngine *, const QDir &) = 0;
+ qScriptRegisterMetaType<QDir>(m_engine, dummy, dirFromScript);
+ {
+ QVERIFY(!m_engine->hasUncaughtException());
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({})");
+ QVERIFY(m_engine->hasUncaughtException());
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: No path"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+ m_engine->clearExceptions();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({path:'.'})");
+ QVERIFY(!m_engine->hasUncaughtException());
+ QVERIFY(ret.isUndefined());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 55);
+ }
+ }
+
+ // qscript_call()
+ {
+ m_myObject->resetQtFunctionInvoked();
+ QScriptValue ret = m_engine->evaluate("new myObject(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a constructor"));
+ }
+ {
+ m_myObject->resetQtFunctionInvoked();
+ QScriptValue ret = m_engine->evaluate("myObject(123)");
+ QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a function"));
+ }
+
+ // task 233624
+ {
+ MyNS::A a;
+ m_engine->globalObject().setProperty("anObject", m_engine->newQObject(&a));
+ QScriptValue ret = m_engine->evaluate("anObject.slotTakingScopedEnumArg(1)");
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1);
+ m_engine->globalObject().setProperty("anObject", QScriptValue());
+ }
+
+ // virtual slot redeclared in subclass (task 236467)
+ {
+ MyOtherQObject moq;
+ m_engine->globalObject().setProperty("myOtherQObject", m_engine->newQObject(&moq));
+ moq.resetQtFunctionInvoked();
+ QScriptValue ret = m_engine->evaluate("myOtherQObject.myVirtualSlot(123)");
+ QCOMPARE(moq.qtFunctionInvoked(), 59);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+}
+
+void tst_QScriptExtQObject::connectAndDisconnect()
+{
+ // connect(function)
+ QCOMPARE(m_engine->evaluate("myObject.mySignal.connect(123)").isError(), true);
+
+ m_engine->evaluate("myHandler = function() { global.gotSignal = true; global.signalArgs = arguments; global.slotThisObject = this; global.signalSender = __qt_sender__; }");
+
+ m_myObject->clearConnectedSignal();
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myHandler)").isUndefined());
+ QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal()));
+
+ m_engine->evaluate("gotSignal = false");
+ m_engine->evaluate("myObject.mySignal()");
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
+ QCOMPARE(m_engine->evaluate("signalSender").toQObject(), (QObject *)m_myObject);
+ QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->globalObject()));
+
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
+
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myHandler)").isUndefined());
+
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignalWithIntArg(123);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
+
+ m_myObject->clearDisconnectedSignal();
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isUndefined());
+ QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal()));
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isError());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
+
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal2(false);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), false);
+
+ m_engine->evaluate("gotSignal = false");
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), true);
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myHandler)").isUndefined());
+
+ QVERIFY(m_engine->evaluate("myObject['mySignal2()'].connect(myHandler)").isUndefined());
+
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal2();
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+
+ QVERIFY(m_engine->evaluate("myObject['mySignal2()'].disconnect(myHandler)").isUndefined());
+
+ // connecting to signal with default args should pick the most generic version (i.e. with all args)
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.connect(myHandler)").isUndefined());
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignalWithDefaultArgWithArg(456);
+ QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 456);
+
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignalWithDefaultArg();
+ QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 123);
+
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.disconnect(myHandler)").isUndefined());
+
+ m_engine->evaluate("gotSignal = false");
+ // connecting to overloaded signal should throw an error
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myOverloadedSignal.connect(myHandler)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOverloadedSignal(); candidates are\n"
+ " myOverloadedSignal(int)\n"
+ " myOverloadedSignal(QString)\n"
+ "Use e.g. object['myOverloadedSignal(QString)'].connect() to connect to a particular overload"));
+ }
+ m_myObject->emitMyOverloadedSignal(123);
+ QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
+ m_myObject->emitMyOverloadedSignal("ciao");
+ QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
+
+ m_engine->evaluate("gotSignal = false");
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myOtherOverloadedSignal.connect(myHandler)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOtherOverloadedSignal(); candidates are\n"
+ " myOtherOverloadedSignal(QString)\n"
+ " myOtherOverloadedSignal(int)\n"
+ "Use e.g. object['myOtherOverloadedSignal(int)'].connect() to connect to a particular overload"));
+ }
+ m_myObject->emitMyOtherOverloadedSignal("ciao");
+ QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
+ m_myObject->emitMyOtherOverloadedSignal(123);
+ QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
+
+ // signal with QVariant arg: argument conversion should work
+ m_myObject->clearConnectedSignal();
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.connect(myHandler)").isUndefined());
+ QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignalWithVariantArg(QVariant)));
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignalWithVariantArg(123);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.disconnect(myHandler)").isUndefined());
+
+ // signal with argument type that's unknown to the meta-type system
+ m_myObject->clearConnectedSignal();
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.connect(myHandler)").isUndefined());
+ QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignalWithScriptEngineArg(QScriptEngine*)));
+ m_engine->evaluate("gotSignal = false");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine: Unable to handle unregistered datatype 'QScriptEngine*' when invoking handler of signal MyQObject::mySignalWithScriptEngineArg(QScriptEngine*)");
+ m_myObject->emitMySignalWithScriptEngineArg(m_engine);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QVERIFY(m_engine->evaluate("signalArgs[0]").isUndefined());
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.disconnect(myHandler)").isUndefined());
+
+ // connect(object, function)
+ m_engine->evaluate("otherObject = { name:'foo' }");
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), false);
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isError());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
+ QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("otherObject")));
+ QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject")));
+ QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("foo"));
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
+
+ m_engine->evaluate("yetAnotherObject = { name:'bar', func : function() { } }");
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(yetAnotherObject, myHandler)").isUndefined());
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("yetAnotherObject")));
+ QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject")));
+ QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("bar"));
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)").isUndefined());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myObject, myHandler)").isUndefined());
+ m_engine->evaluate("gotSignal = false");
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
+ QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
+ QCOMPARE(m_engine->evaluate("slotThisObject").toQObject(), (QObject *)m_myObject);
+ QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject")));
+ QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myObject, myHandler)").isUndefined());
+
+ // connect(obj, string)
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(yetAnotherObject, 'func')").isUndefined());
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject, 'mySlot')").isUndefined());
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(yetAnotherObject, 'func')").isUndefined());
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject, 'mySlot')").isUndefined());
+
+ // check that emitting signals from script works
+
+ // no arguments
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignal()").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+ QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject.mySlot)").isUndefined());
+
+ // one argument
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)").isUndefined());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)").isUndefined());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)").isUndefined());
+
+ // connecting to overloaded slot
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)").isUndefined());
+
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(456)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
+ QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])").isUndefined());
+
+ // erroneous input
+ {
+ QScriptValue ret = m_engine->evaluate("(function() { }).connect()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("(function() { }).connect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(function() { })");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.mySignal.connect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: target is not a function"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("(function() { }).disconnect()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("(function() { }).disconnect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
+ }
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(function() { })");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(123)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: target is not a function"));
+ }
+
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(function() { })");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: failed to disconnect from MyQObject::mySignal()"));
+ }
+
+ // when the wrapper dies, the connection stays alive
+ QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
+ m_myObject->resetQtFunctionInvoked();
+ m_myObject->emitMySignal();
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+ m_engine->evaluate("myObject = null");
+ m_engine->collectGarbage();
+ m_myObject->resetQtFunctionInvoked();
+ m_myObject->emitMySignal();
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+}
+
+void tst_QScriptExtQObject::cppConnectAndDisconnect()
+{
+ QScriptEngine eng;
+ QLineEdit edit;
+ QLineEdit edit2;
+ QScriptValue fun = eng.evaluate("function fun(text) { signalObject = this; signalArg = text; }; fun");
+ QVERIFY(fun.isFunction());
+ for (int z = 0; z < 2; ++z) {
+ QScriptValue receiver;
+ if (z == 0)
+ receiver = QScriptValue();
+ else
+ receiver = eng.newObject();
+ for (int y = 0; y < 2; ++y) {
+ QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
+ QVERIFY(qScriptConnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
+ // check signal emission
+ for (int x = 0; x < 4; ++x) {
+ QLineEdit *ed = (x < 2) ? &edit : &edit2;
+ ed->setText((x % 2) ? "foo" : "bar");
+ {
+ QScriptValue ret = eng.globalObject().property("signalObject");
+ if (receiver.isObject())
+ QVERIFY(ret.strictlyEquals(receiver));
+ else
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
+ {
+ QScriptValue ret = eng.globalObject().property("signalArg");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), ed->text());
+ }
+ eng.collectGarbage();
+ }
+
+ // check disconnect
+ QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
+ eng.globalObject().setProperty("signalObject", QScriptValue());
+ eng.globalObject().setProperty("signalArg", QScriptValue());
+ edit.setText("something else");
+ QVERIFY(!eng.globalObject().property("signalObject").isValid());
+ QVERIFY(!eng.globalObject().property("signalArg").isValid());
+ QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
+
+ // other object's connection should remain
+ edit2.setText(edit.text());
+ {
+ QScriptValue ret = eng.globalObject().property("signalObject");
+ if (receiver.isObject())
+ QVERIFY(ret.strictlyEquals(receiver));
+ else
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
+ {
+ QScriptValue ret = eng.globalObject().property("signalArg");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), edit2.text());
+ }
+
+ // disconnect other object too
+ QVERIFY(qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
+ eng.globalObject().setProperty("signalObject", QScriptValue());
+ eng.globalObject().setProperty("signalArg", QScriptValue());
+ edit2.setText("even more different");
+ QVERIFY(!eng.globalObject().property("signalObject").isValid());
+ QVERIFY(!eng.globalObject().property("signalArg").isValid());
+ QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
+ }
+ }
+
+ // make sure we don't crash when engine is deleted
+ {
+ QScriptEngine *eng2 = new QScriptEngine;
+ QScriptValue fun2 = eng2->evaluate("function(text) { signalObject = this; signalArg = text; }");
+ QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
+ delete eng2;
+ edit.setText("ciao");
+ QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
+ }
+
+ // mixing script-side and C++-side connect
+ {
+ eng.globalObject().setProperty("edit", eng.newQObject(&edit));
+ QVERIFY(eng.evaluate("edit.textChanged.connect(fun)").isUndefined());
+ QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
+
+ QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
+ QVERIFY(eng.evaluate("edit.textChanged.disconnect(fun)").isUndefined());
+ }
+
+ // signalHandlerException()
+ {
+ connect(&eng, SIGNAL(signalHandlerException(QScriptValue)),
+ this, SLOT(onSignalHandlerException(QScriptValue)));
+
+ eng.globalObject().setProperty("edit", eng.newQObject(&edit));
+ QScriptValue fun = eng.evaluate("function() { nonExistingFunction(); }");
+ QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
+
+ m_signalHandlerException = QScriptValue();
+ QScriptValue ret = eng.evaluate("edit.text = 'trigger a signal handler exception from script'");
+ QVERIFY(ret.isError());
+ QVERIFY(m_signalHandlerException.strictlyEquals(ret));
+
+ m_signalHandlerException = QScriptValue();
+ edit.setText("trigger a signal handler exception from C++");
+ QVERIFY(m_signalHandlerException.isError());
+
+ QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
+
+ m_signalHandlerException = QScriptValue();
+ eng.evaluate("edit.text = 'no more exception from script'");
+ QVERIFY(!m_signalHandlerException.isValid());
+ edit.setText("no more exception from C++");
+ QVERIFY(!m_signalHandlerException.isValid());
+
+ disconnect(&eng, SIGNAL(signalHandlerException(QScriptValue)),
+ this, SLOT(onSignalHandlerException(QScriptValue)));
+ }
+
+ // check that connectNotify() and disconnectNotify() are called (task 232987)
+ {
+ m_myObject->clearConnectedSignal();
+ QVERIFY(qScriptConnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
+ QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal()));
+
+ m_myObject->clearDisconnectedSignal();
+ QVERIFY(qScriptDisconnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
+ QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal()));
+ }
+
+ // bad args
+ QVERIFY(!qScriptConnect(0, SIGNAL(foo()), QScriptValue(), fun));
+ QVERIFY(!qScriptConnect(&edit, 0, QScriptValue(), fun));
+ QVERIFY(!qScriptConnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
+ QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
+ QVERIFY(!qScriptDisconnect(0, SIGNAL(foo()), QScriptValue(), fun));
+ QVERIFY(!qScriptDisconnect(&edit, 0, QScriptValue(), fun));
+ QVERIFY(!qScriptDisconnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
+ QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
+ {
+ QScriptEngine eng2;
+ QScriptValue receiverInDifferentEngine = eng2.newObject();
+ QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
+ QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
+ }
+}
+
+void tst_QScriptExtQObject::classEnums()
+{
+ QScriptValue myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
+ m_engine->globalObject().setProperty("MyQObject", myClass);
+
+ QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.FooPolicy").toInt32()),
+ MyQObject::FooPolicy);
+ QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BarPolicy").toInt32()),
+ MyQObject::BarPolicy);
+ QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BazPolicy").toInt32()),
+ MyQObject::BazPolicy);
+
+ QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.FooStrategy").toInt32()),
+ MyQObject::FooStrategy);
+ QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BarStrategy").toInt32()),
+ MyQObject::BarStrategy);
+ QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BazStrategy").toInt32()),
+ MyQObject::BazStrategy);
+
+ QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.NoAbility").toInt32()),
+ MyQObject::NoAbility);
+ QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.FooAbility").toInt32()),
+ MyQObject::FooAbility);
+ QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BarAbility").toInt32()),
+ MyQObject::BarAbility);
+ QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BazAbility").toInt32()),
+ MyQObject::BazAbility);
+ QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.AllAbility").toInt32()),
+ MyQObject::AllAbility);
+
+ QScriptValue::PropertyFlags expectedEnumFlags = QScriptValue::ReadOnly | QScriptValue::Undeletable;
+ QCOMPARE(myClass.propertyFlags("FooPolicy"), expectedEnumFlags);
+ QCOMPARE(myClass.propertyFlags("BarPolicy"), expectedEnumFlags);
+ QCOMPARE(myClass.propertyFlags("BazPolicy"), expectedEnumFlags);
+
+ // enums from Qt are inherited through prototype
+ QCOMPARE(static_cast<Qt::FocusPolicy>(m_engine->evaluate("MyQObject.StrongFocus").toInt32()),
+ Qt::StrongFocus);
+ QCOMPARE(static_cast<Qt::Key>(m_engine->evaluate("MyQObject.Key_Left").toInt32()),
+ Qt::Key_Left);
+
+ QCOMPARE(m_engine->evaluate("MyQObject.className()").toString(), QLatin1String("MyQObject"));
+
+ qRegisterMetaType<MyQObject::Policy>("Policy");
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg('BarPolicy')").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BarPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ QVERIFY(m_engine->evaluate("myObject.myInvokableWithEnumArg('NoSuchPolicy')").isError());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningEnum()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(ret.isVariant(), true);
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQualifiedEnum()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(ret.isNumber(), true);
+ }
+
+ // enum properties are not deletable or writable
+ QVERIFY(!m_engine->evaluate("delete MyQObject.BazPolicy").toBool());
+ myClass.setProperty("BazPolicy", QScriptValue());
+ QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
+ MyQObject::BazPolicy);
+ myClass.setProperty("BazPolicy", MyQObject::FooPolicy);
+ QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
+ MyQObject::BazPolicy);
+}
+
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(MyQObject, QObject*)
+Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
+QT_END_NAMESPACE
+
+class ConstructorTest : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE ConstructorTest(QObject *parent)
+ : QObject(parent)
+ {
+ setProperty("ctorIndex", 0);
+ }
+ Q_INVOKABLE ConstructorTest(int arg, QObject *parent = 0)
+ : QObject(parent)
+ {
+ setProperty("ctorIndex", 1);
+ setProperty("arg", arg);
+ }
+ Q_INVOKABLE ConstructorTest(const QString &arg, QObject *parent = 0)
+ : QObject(parent)
+ {
+ setProperty("ctorIndex", 2);
+ setProperty("arg", arg);
+ }
+ Q_INVOKABLE ConstructorTest(int arg, const QString &arg2, QObject *parent = 0)
+ : QObject(parent)
+ {
+ setProperty("ctorIndex", 3);
+ setProperty("arg", arg);
+ setProperty("arg2", arg2);
+ }
+ Q_INVOKABLE ConstructorTest(const QBrush &arg, QObject *parent = 0)
+ : QObject(parent)
+ {
+ setProperty("ctorIndex", 4);
+ setProperty("arg", arg);
+ }
+};
+
+void tst_QScriptExtQObject::classConstructor()
+{
+ QScriptValue myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
+ m_engine->globalObject().setProperty("MyQObject", myClass);
+
+ QScriptValue myObj = m_engine->evaluate("myObj = MyQObject()");
+ QObject *qobj = myObj.toQObject();
+ QVERIFY(qobj != 0);
+ QCOMPARE(qobj->metaObject()->className(), "MyQObject");
+ QCOMPARE(qobj->parent(), (QObject *)0);
+
+ QScriptValue qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
+ m_engine->globalObject().setProperty("QObject", qobjectClass);
+
+ QScriptValue otherObj = m_engine->evaluate("otherObj = QObject(myObj)");
+ QObject *qqobj = otherObj.toQObject();
+ QVERIFY(qqobj != 0);
+ QCOMPARE(qqobj->metaObject()->className(), "QObject");
+ QCOMPARE(qqobj->parent(), qobj);
+
+ delete qobj;
+
+ // Q_INVOKABLE constructors
+ {
+ QScriptValue klazz = m_engine->newQMetaObject(&ConstructorTest::staticMetaObject);
+ {
+ QScriptValue obj = klazz.construct();
+ QVERIFY(obj.isError());
+ QCOMPARE(obj.toString(), QString::fromLatin1("SyntaxError: too few arguments in call to ConstructorTest(); candidates are\n"
+ " ConstructorTest(QBrush)\n"
+ " ConstructorTest(QBrush,QObject*)\n"
+ " ConstructorTest(int,QString)\n"
+ " ConstructorTest(int,QString,QObject*)\n"
+ " ConstructorTest(QString)\n"
+ " ConstructorTest(QString,QObject*)\n"
+ " ConstructorTest(int)\n"
+ " ConstructorTest(int,QObject*)\n"
+ " ConstructorTest(QObject*)"));
+ }
+ {
+ QObject objobj;
+ QScriptValue arg = m_engine->newQObject(&objobj);
+ QScriptValue obj = klazz.construct(QScriptValueList() << arg);
+ QVERIFY(!obj.isError());
+ QVERIFY(obj.instanceOf(klazz));
+ QVERIFY(obj.property("ctorIndex").isNumber());
+ QCOMPARE(obj.property("ctorIndex").toInt32(), 0);
+ }
+ {
+ int arg = 123;
+ QScriptValue obj = klazz.construct(QScriptValueList() << arg);
+ QVERIFY(!obj.isError());
+ QVERIFY(obj.instanceOf(klazz));
+ QVERIFY(obj.property("ctorIndex").isNumber());
+ QCOMPARE(obj.property("ctorIndex").toInt32(), 1);
+ QVERIFY(obj.property("arg").isNumber());
+ QCOMPARE(obj.property("arg").toInt32(), arg);
+ }
+ {
+ QString arg = "foo";
+ QScriptValue obj = klazz.construct(QScriptValueList() << arg);
+ QVERIFY(!obj.isError());
+ QVERIFY(obj.instanceOf(klazz));
+ QVERIFY(obj.property("ctorIndex").isNumber());
+ QCOMPARE(obj.property("ctorIndex").toInt32(), 2);
+ QVERIFY(obj.property("arg").isString());
+ QCOMPARE(obj.property("arg").toString(), arg);
+ }
+ {
+ int arg = 123;
+ QString arg2 = "foo";
+ QScriptValue obj = klazz.construct(QScriptValueList() << arg << arg2);
+ QVERIFY(!obj.isError());
+ QVERIFY(obj.instanceOf(klazz));
+ QVERIFY(obj.property("ctorIndex").isNumber());
+ QCOMPARE(obj.property("ctorIndex").toInt32(), 3);
+ QVERIFY(obj.property("arg").isNumber());
+ QCOMPARE(obj.property("arg").toInt32(), arg);
+ QVERIFY(obj.property("arg2").isString());
+ QCOMPARE(obj.property("arg2").toString(), arg2);
+ }
+ {
+ QBrush arg(Qt::red);
+ QScriptValue obj = klazz.construct(QScriptValueList() << qScriptValueFromValue(m_engine, arg));
+ QVERIFY(!obj.isError());
+ QVERIFY(obj.instanceOf(klazz));
+ QVERIFY(obj.property("ctorIndex").isNumber());
+ QCOMPARE(obj.property("ctorIndex").toInt32(), 4);
+ QVERIFY(obj.property("arg").isVariant());
+ QCOMPARE(qvariant_cast<QBrush>(obj.property("arg").toVariant()), arg);
+ }
+ {
+ QDir arg;
+ QScriptValue obj = klazz.construct(QScriptValueList()
+ << qScriptValueFromValue(m_engine, arg));
+ QVERIFY(obj.isError());
+ QCOMPARE(obj.toString(), QString::fromLatin1("TypeError: ambiguous call of overloaded function ConstructorTest(); candidates were\n"
+ " ConstructorTest(int)\n"
+ " ConstructorTest(QString)"));
+ }
+ }
+}
+
+void tst_QScriptExtQObject::overrideInvokable()
+{
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myInvokable = function() { global.a = 123; }");
+ m_engine->evaluate("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ QCOMPARE(m_engine->evaluate("global.a").toNumber(), 123.0);
+
+ m_engine->evaluate("myObject.myInvokable = function() { global.a = 456; }");
+ m_engine->evaluate("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ QCOMPARE(m_engine->evaluate("global.a").toNumber(), 456.0);
+
+ m_engine->evaluate("delete myObject.myInvokable");
+ m_engine->evaluate("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg");
+ m_engine->evaluate("myObject.myInvokable(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+
+ m_engine->evaluate("delete myObject.myInvokable");
+ m_myObject->resetQtFunctionInvoked();
+ // this form (with the '()') is read-only
+ m_engine->evaluate("myObject['myInvokable()'] = function() { global.a = 123; }");
+ m_engine->evaluate("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+}
+
+void tst_QScriptExtQObject::transferInvokable()
+{
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.foozball = myObject.myInvokable");
+ m_engine->evaluate("myObject.foozball()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.foozball = myObject.myInvokableWithIntArg");
+ m_engine->evaluate("myObject.foozball(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg");
+ m_engine->evaluate("myObject.myInvokable(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+
+ MyOtherQObject other;
+ m_engine->globalObject().setProperty(
+ "myOtherObject", m_engine->newQObject(&other));
+ m_engine->evaluate("myOtherObject.foo = myObject.foozball");
+ other.resetQtFunctionInvoked();
+ m_engine->evaluate("myOtherObject.foo(456)");
+ QCOMPARE(other.qtFunctionInvoked(), 1);
+}
+
+void tst_QScriptExtQObject::findChild()
+{
+ QObject *child = new QObject(m_myObject);
+ child->setObjectName(QLatin1String("myChildObject"));
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChild('noSuchChild')");
+ QCOMPARE(result.isNull(), true);
+ }
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChild('myChildObject')");
+ QCOMPARE(result.isQObject(), true);
+ QCOMPARE(result.toQObject(), child);
+ }
+
+ delete child;
+}
+
+void tst_QScriptExtQObject::findChildren()
+{
+ QObject *child = new QObject(m_myObject);
+ child->setObjectName(QLatin1String("myChildObject"));
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren('noSuchChild')");
+ QCOMPARE(result.isArray(), true);
+ QCOMPARE(result.property(QLatin1String("length")).toNumber(), 0.0);
+ }
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray(), true);
+ QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
+ }
+
+ QObject *namelessChild = new QObject(m_myObject);
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray(), true);
+ QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
+ }
+
+ QObject *anotherChild = new QObject(m_myObject);
+ anotherChild->setObjectName(QLatin1String("anotherChildObject"));
+
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren('anotherChildObject')");
+ QCOMPARE(result.isArray(), true);
+ QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
+ }
+
+ anotherChild->setObjectName(QLatin1String("myChildObject"));
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray(), true);
+ QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0);
+ QObject *o1 = result.property(QLatin1String("0")).toQObject();
+ QObject *o2 = result.property(QLatin1String("1")).toQObject();
+ if (o1 != child) {
+ QCOMPARE(o1, anotherChild);
+ QCOMPARE(o2, child);
+ } else {
+ QCOMPARE(o1, child);
+ QCOMPARE(o2, anotherChild);
+ }
+ }
+
+ // find all
+ {
+ QScriptValue result = m_engine->evaluate("myObject.findChildren()");
+ QVERIFY(result.isArray());
+ int count = 3;
+ QCOMPARE(result.property("length").toInt32(), count);
+ for (int i = 0; i < 3; ++i) {
+ QObject *o = result.property(i).toQObject();
+ if (o == namelessChild || o == child || o == anotherChild)
+ --count;
+ }
+ QVERIFY(count == 0);
+ }
+
+ delete anotherChild;
+ delete namelessChild;
+ delete child;
+}
+
+void tst_QScriptExtQObject::overloadedSlots()
+{
+ // should pick myOverloadedSlot(double)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(10)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
+
+ // should pick myOverloadedSlot(double)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(10.0)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
+
+ // should pick myOverloadedSlot(QString)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot('10')");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
+
+ // should pick myOverloadedSlot(bool)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(true)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
+
+ // should pick myOverloadedSlot(QDateTime)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(new Date())");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
+
+ // should pick myOverloadedSlot(QRegExp)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(new RegExp())");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
+
+ // should pick myOverloadedSlot(QVariant)
+ m_myObject->resetQtFunctionInvoked();
+ QScriptValue f = m_engine->evaluate("myObject.myOverloadedSlot");
+ f.call(QScriptValue(), QScriptValueList() << m_engine->newVariant(QVariant("ciao")));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
+
+ // should pick myOverloadedSlot(QObject*)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(myObject)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
+
+ // should pick myOverloadedSlot(QObject*)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(null)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
+
+ // should pick myOverloadedSlot(QStringList)
+ m_myObject->resetQtFunctionInvoked();
+ m_engine->evaluate("myObject.myOverloadedSlot(['hello'])");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
+}
+
+void tst_QScriptExtQObject::enumerate_data()
+{
+ QTest::addColumn<int>("wrapOptions");
+ QTest::addColumn<QStringList>("expectedNames");
+
+ QTest::newRow( "enumerate all" )
+ << 0
+ << (QStringList()
+ // meta-object-defined properties:
+ // inherited
+ << "objectName"
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // inherited slots
+ << "destroyed(QObject*)" << "destroyed()"
+ << "deleteLater()"
+ // not included because it's private:
+ // << "_q_reregisterTimers(void*)"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+
+ QTest::newRow( "don't enumerate inherited properties" )
+ << int(QScriptEngine::ExcludeSuperClassProperties)
+ << (QStringList()
+ // meta-object-defined properties:
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // inherited slots
+ << "destroyed(QObject*)" << "destroyed()"
+ << "deleteLater()"
+ // not included because it's private:
+ // << "_q_reregisterTimers(void*)"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+
+ QTest::newRow( "don't enumerate inherited methods" )
+ << int(QScriptEngine::ExcludeSuperClassMethods)
+ << (QStringList()
+ // meta-object-defined properties:
+ // inherited
+ << "objectName"
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+
+ QTest::newRow( "don't enumerate inherited members" )
+ << int(QScriptEngine::ExcludeSuperClassMethods
+ | QScriptEngine::ExcludeSuperClassProperties)
+ << (QStringList()
+ // meta-object-defined properties
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+
+ QTest::newRow( "enumerate properties, not methods" )
+ << int(QScriptEngine::SkipMethodsInEnumeration)
+ << (QStringList()
+ // meta-object-defined properties:
+ // inherited
+ << "objectName"
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3");
+
+ QTest::newRow( "don't enumerate inherited properties + methods" )
+ << int(QScriptEngine::ExcludeSuperClassProperties
+ | QScriptEngine::SkipMethodsInEnumeration)
+ << (QStringList()
+ // meta-object-defined properties:
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3");
+
+ QTest::newRow( "don't enumerate inherited members" )
+ << int(QScriptEngine::ExcludeSuperClassContents)
+ << (QStringList()
+ // meta-object-defined properties
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+
+ QTest::newRow( "don't enumerate deleteLater()" )
+ << int(QScriptEngine::ExcludeDeleteLater)
+ << (QStringList()
+ // meta-object-defined properties:
+ // inherited
+ << "objectName"
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // inherited slots
+ << "destroyed(QObject*)" << "destroyed()"
+ // not included because it's private:
+ // << "_q_reregisterTimers(void*)"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+}
+
+void tst_QScriptExtQObject::enumerate()
+{
+ QFETCH( int, wrapOptions );
+ QFETCH( QStringList, expectedNames );
+
+ QScriptEngine eng;
+ MyEnumTestQObject enumQObject;
+ // give it some dynamic properties
+ enumQObject.setProperty("dp1", "dp1");
+ enumQObject.setProperty("dp2", "dp2");
+ enumQObject.setProperty("dp3", "dp3");
+ QScriptValue obj = eng.newQObject(&enumQObject, QScriptEngine::QtOwnership,
+ QScriptEngine::QObjectWrapOptions(wrapOptions));
+
+ // enumerate in script
+ {
+ eng.globalObject().setProperty("myEnumObject", obj);
+ eng.evaluate("var enumeratedProperties = []");
+ eng.evaluate("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
+ QStringList result = qscriptvalue_cast<QStringList>(eng.evaluate("enumeratedProperties"));
+ QCOMPARE(result.size(), expectedNames.size());
+ for (int i = 0; i < expectedNames.size(); ++i)
+ QCOMPARE(result.at(i), expectedNames.at(i));
+ }
+ // enumerate in C++
+ {
+ QScriptValueIterator it(obj);
+ QStringList result;
+ while (it.hasNext()) {
+ it.next();
+ QCOMPARE(it.flags(), obj.propertyFlags(it.name()));
+ result.append(it.name());
+ }
+ QCOMPARE(result.size(), expectedNames.size());
+ for (int i = 0; i < expectedNames.size(); ++i)
+ QCOMPARE(result.at(i), expectedNames.at(i));
+ }
+}
+
+class SpecialEnumTestObject : public QObject
+{
+ Q_OBJECT
+ // overriding a property in the super-class to make it non-scriptable
+ Q_PROPERTY(QString objectName READ objectName SCRIPTABLE false)
+public:
+ SpecialEnumTestObject(QObject *parent = 0)
+ : QObject(parent) {}
+};
+
+class SpecialEnumTestObject2 : public QObject
+{
+ Q_OBJECT
+ // overriding a property in the super-class to make it non-designable (but still scriptable)
+ Q_PROPERTY(QString objectName READ objectName DESIGNABLE false)
+public:
+ SpecialEnumTestObject2(QObject *parent = 0)
+ : QObject(parent) {}
+};
+
+void tst_QScriptExtQObject::enumerateSpecial()
+{
+ QScriptEngine eng;
+ {
+ SpecialEnumTestObject testObj;
+ QScriptValueIterator it(eng.newQObject(&testObj));
+ bool objectNameEncountered = false;
+ while (it.hasNext()) {
+ it.next();
+ if (it.name() == QLatin1String("objectName")) {
+ objectNameEncountered = true;
+ break;
+ }
+ }
+ QVERIFY(!objectNameEncountered);
+ }
+ {
+ SpecialEnumTestObject2 testObj;
+ testObj.setObjectName("foo");
+ QScriptValueList values;
+ QScriptValueIterator it(eng.newQObject(&testObj));
+ while (it.hasNext()) {
+ it.next();
+ if (it.name() == "objectName")
+ values.append(it.value());
+ }
+ QCOMPARE(values.size(), 1);
+ QCOMPARE(values.at(0).toString(), QString::fromLatin1("foo"));
+ }
+}
+
+void tst_QScriptExtQObject::wrapOptions()
+{
+ QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
+ MyQObject *child = new MyQObject(m_myObject);
+ child->setObjectName("child");
+ // exclude child objects
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeChildObjects);
+ QCOMPARE(obj.property("child").isValid(), false);
+ obj.setProperty("child", QScriptValue(m_engine, 123));
+ QCOMPARE(obj.property("child")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ }
+ // don't auto-create dynamic properties
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject);
+ QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
+ obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123));
+ QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
+ QCOMPARE(obj.property("anotherDynamicProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ }
+ // auto-create dynamic properties
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::AutoCreateDynamicProperties);
+ QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
+ obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123));
+ QVERIFY(m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
+ QCOMPARE(obj.property("anotherDynamicProperty")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ // task 236685
+ {
+ QScriptValue obj2 = m_engine->newObject();
+ obj2.setProperty("notADynamicProperty", 456);
+ obj.setPrototype(obj2);
+ QScriptValue ret = obj.property("notADynamicProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(obj2.property("notADynamicProperty")));
+ }
+ }
+ // don't exclude super-class properties
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject);
+ QVERIFY(obj.property("objectName").isValid());
+ QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
+ }
+ // exclude super-class properties
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeSuperClassProperties);
+ QVERIFY(!obj.property("objectName").isValid());
+ QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("intProperty").isValid());
+ QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
+ }
+ // don't exclude super-class methods
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject);
+ QVERIFY(obj.property("deleteLater").isValid());
+ QVERIFY(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember);
+ }
+ // exclude super-class methods
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeSuperClassMethods);
+ QVERIFY(!obj.property("deleteLater").isValid());
+ QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("mySlot").isValid());
+ QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
+ }
+ // exclude all super-class contents
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeSuperClassContents);
+ QVERIFY(!obj.property("deleteLater").isValid());
+ QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("mySlot").isValid());
+ QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
+
+ QVERIFY(!obj.property("objectName").isValid());
+ QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("intProperty").isValid());
+ QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
+ }
+ // exclude deleteLater()
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeDeleteLater);
+ QVERIFY(!obj.property("deleteLater").isValid());
+ QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("mySlot").isValid());
+ QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
+
+ QVERIFY(obj.property("objectName").isValid());
+ QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
+ QVERIFY(obj.property("intProperty").isValid());
+ QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
+ }
+ // exclude all that we can
+ {
+ QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
+ QScriptEngine::ExcludeSuperClassMethods
+ | QScriptEngine::ExcludeSuperClassProperties
+ | QScriptEngine::ExcludeChildObjects);
+ QVERIFY(!obj.property("deleteLater").isValid());
+ QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("mySlot").isValid());
+ QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
+
+ QVERIFY(!obj.property("objectName").isValid());
+ QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
+ QVERIFY(obj.property("intProperty").isValid());
+ QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
+
+ QCOMPARE(obj.property("child").isValid(), false);
+ obj.setProperty("child", QScriptValue(m_engine, 123));
+ QCOMPARE(obj.property("child")
+ .strictlyEquals(QScriptValue(m_engine, 123)), true);
+ }
+
+ delete child;
+}
+
+Q_DECLARE_METATYPE(QWidget*)
+Q_DECLARE_METATYPE(QPushButton*)
+
+void tst_QScriptExtQObject::prototypes()
+{
+ QScriptEngine eng;
+ QScriptValue widgetProto = eng.newQObject(new QWidget(), QScriptEngine::ScriptOwnership);
+ eng.setDefaultPrototype(qMetaTypeId<QWidget*>(), widgetProto);
+ QPushButton *pbp = new QPushButton();
+ QScriptValue buttonProto = eng.newQObject(pbp, QScriptEngine::ScriptOwnership);
+ buttonProto.setPrototype(widgetProto);
+ eng.setDefaultPrototype(qMetaTypeId<QPushButton*>(), buttonProto);
+ QPushButton *pb = new QPushButton();
+ QScriptValue button = eng.newQObject(pb, QScriptEngine::ScriptOwnership);
+ QVERIFY(button.prototype().strictlyEquals(buttonProto));
+
+ buttonProto.setProperty("text", QScriptValue(&eng, "prototype button"));
+ QCOMPARE(pbp->text(), QLatin1String("prototype button"));
+ button.setProperty("text", QScriptValue(&eng, "not the prototype button"));
+ QCOMPARE(pb->text(), QLatin1String("not the prototype button"));
+ QCOMPARE(pbp->text(), QLatin1String("prototype button"));
+
+ buttonProto.setProperty("objectName", QScriptValue(&eng, "prototype button"));
+ QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
+ button.setProperty("objectName", QScriptValue(&eng, "not the prototype button"));
+ QCOMPARE(pb->objectName(), QLatin1String("not the prototype button"));
+ QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
+}
+
+void tst_QScriptExtQObject::objectDeleted()
+{
+ QScriptEngine eng;
+ MyQObject *qobj = new MyQObject();
+ QScriptValue v = eng.newQObject(qobj);
+ v.setProperty("objectName", QScriptValue(&eng, "foo"));
+ QCOMPARE(qobj->objectName(), QLatin1String("foo"));
+ v.setProperty("intProperty", QScriptValue(&eng, 123));
+ QCOMPARE(qobj->intProperty(), 123);
+ qobj->resetQtFunctionInvoked();
+ v.property("myInvokable").call(v);
+ QCOMPARE(qobj->qtFunctionInvoked(), 0);
+
+ // now delete the object
+ delete qobj;
+
+ // the documented behavior is: isQObject() should still return true,
+ // but toQObject() should return 0
+ QVERIFY(v.isQObject());
+ QCOMPARE(v.toQObject(), (QObject *)0);
+
+ // any attempt to access properties of the object should result in an exception
+ {
+ QScriptValue ret = v.property("objectName");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+ {
+ eng.evaluate("Object");
+ QVERIFY(!eng.hasUncaughtException());
+ v.setProperty("objectName", QScriptValue(&eng, "foo"));
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().isError());
+ QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+
+ {
+ QScriptValue ret = v.call();
+ QVERIFY(!ret.isValid());
+ }
+
+ // myInvokable is stored in member table (since we've accessed it before deletion)
+ QVERIFY(v.property("myInvokable").isFunction());
+ {
+ QScriptValue ret = v.property("myInvokable").call(v);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject"));
+ }
+ // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
+ {
+ QScriptValue ret = v.property("myInvokableWithIntArg");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
+ }
+
+ // access from script
+ eng.globalObject().setProperty("o", v);
+ {
+ QScriptValue ret = eng.evaluate("o()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: o is not a function"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("o.objectName");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("o.myInvokable()");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("o.myInvokableWithIntArg(10)");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
+ }
+}
+
+void tst_QScriptExtQObject::connectToDestroyedSignal()
+{
+ // ### the following test currently depends on signal emission order
+#if 0
+ {
+ // case 1: deleted when the engine is not doing GC
+ QScriptEngine eng;
+ QObject *obj = new QObject();
+ eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::QtOwnership));
+ eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
+ eng.evaluate("wasDestroyed = false");
+ delete obj;
+ QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
+ }
+ {
+ // case 2: deleted when the engine is doing GC
+ QScriptEngine eng;
+ QObject *obj = new QObject();
+ eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
+ eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
+ eng.evaluate("wasDestroyed = false");
+ eng.evaluate("o = null");
+ eng.collectGarbage();
+ QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
+ }
+ {
+ // case 3: deleted when the engine is destroyed
+ QScriptEngine eng;
+ QObject *obj = new QObject();
+ eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
+ eng.evaluate("o.destroyed.connect(function() { })");
+ // the signal handler won't get called -- we don't want to crash
+ }
+#endif
+}
+
+QTEST_MAIN(tst_QScriptExtQObject)
+#include "tst_qscriptextqobject.moc"