tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <qscriptengine.h>
       
    46 #include <qscriptcontext.h>
       
    47 #include <qscriptvalueiterator.h>
       
    48 #include <qwidget.h>
       
    49 #include <qpushbutton.h>
       
    50 #include <qlineedit.h>
       
    51 
       
    52 //TESTED_CLASS=
       
    53 //TESTED_FILES=script/qscriptextqobject_p.h script/qscriptextqobject.cpp
       
    54 
       
    55 struct CustomType
       
    56 {
       
    57 #if defined (Q_CC_NOKIAX86)
       
    58     // Compiler crash workaround
       
    59     CustomType() {}
       
    60 #endif
       
    61     QString string;
       
    62 };
       
    63 Q_DECLARE_METATYPE(CustomType)
       
    64 
       
    65 Q_DECLARE_METATYPE(QBrush*)
       
    66 Q_DECLARE_METATYPE(QObjectList)
       
    67 Q_DECLARE_METATYPE(QList<int>)
       
    68 Q_DECLARE_METATYPE(Qt::BrushStyle)
       
    69 Q_DECLARE_METATYPE(QDir)
       
    70 
       
    71 static void dirFromScript(const QScriptValue &in, QDir &out)
       
    72 {
       
    73     QScriptValue path = in.property("path");
       
    74     if (!path.isValid())
       
    75         in.engine()->currentContext()->throwError("No path");
       
    76     else
       
    77         out.setPath(path.toString());
       
    78 }
       
    79 
       
    80 namespace MyNS
       
    81 {
       
    82     class A : public QObject
       
    83     {
       
    84         Q_OBJECT
       
    85     public:
       
    86         enum Type {
       
    87             Foo,
       
    88             Bar
       
    89         };
       
    90         Q_ENUMS(Type)
       
    91     public Q_SLOTS:
       
    92         int slotTakingScopedEnumArg(MyNS::A::Type t) {
       
    93             return t;
       
    94         }
       
    95     };
       
    96 }
       
    97 
       
    98 class MyQObject : public QObject
       
    99 {
       
   100     Q_OBJECT
       
   101 
       
   102     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
       
   103     Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
       
   104     Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
       
   105     Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
       
   106     Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
       
   107     Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
       
   108     Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
       
   109     Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
       
   110     Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
       
   111     Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
       
   112     Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
       
   113     Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
       
   114     Q_PROPERTY(Policy enumProperty READ enumProperty WRITE setEnumProperty)
       
   115     Q_ENUMS(Policy Strategy)
       
   116     Q_FLAGS(Ability)
       
   117 
       
   118 public:
       
   119     enum Policy {
       
   120         FooPolicy = 0,
       
   121         BarPolicy,
       
   122         BazPolicy
       
   123     };
       
   124 
       
   125     enum Strategy {
       
   126         FooStrategy = 10,
       
   127         BarStrategy,
       
   128         BazStrategy
       
   129     };
       
   130 
       
   131     enum AbilityFlag {
       
   132         NoAbility  = 0x000,
       
   133         FooAbility = 0x001,
       
   134         BarAbility = 0x080,
       
   135         BazAbility = 0x200,
       
   136         AllAbility = FooAbility | BarAbility | BazAbility
       
   137     };
       
   138 
       
   139     Q_DECLARE_FLAGS(Ability, AbilityFlag)
       
   140 
       
   141     MyQObject(QObject *parent = 0)
       
   142         : QObject(parent),
       
   143           m_intValue(123),
       
   144           m_variantValue(QLatin1String("foo")),
       
   145           m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
       
   146           m_stringValue(QLatin1String("bar")),
       
   147           m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
       
   148           m_brushValue(QColor(10, 20, 30, 40)),
       
   149           m_hiddenValue(456.0),
       
   150           m_writeOnlyValue(789),
       
   151           m_readOnlyValue(987),
       
   152           m_enumValue(BarPolicy),
       
   153           m_qtFunctionInvoked(-1)
       
   154         { }
       
   155 
       
   156     int intProperty() const
       
   157         { return m_intValue; }
       
   158     void setIntProperty(int value)
       
   159         { m_intValue = value; }
       
   160 
       
   161     QVariant variantProperty() const
       
   162         { return m_variantValue; }
       
   163     void setVariantProperty(const QVariant &value)
       
   164         { m_variantValue = value; }
       
   165 
       
   166     QVariantList variantListProperty() const
       
   167         { return m_variantListValue; }
       
   168     void setVariantListProperty(const QVariantList &value)
       
   169         { m_variantListValue = value; }
       
   170 
       
   171     QString stringProperty() const
       
   172         { return m_stringValue; }
       
   173     void setStringProperty(const QString &value)
       
   174         { m_stringValue = value; }
       
   175 
       
   176     QStringList stringListProperty() const
       
   177         { return m_stringListValue; }
       
   178     void setStringListProperty(const QStringList &value)
       
   179         { m_stringListValue = value; }
       
   180 
       
   181     QByteArray byteArrayProperty() const
       
   182         { return m_byteArrayValue; }
       
   183     void setByteArrayProperty(const QByteArray &value)
       
   184         { m_byteArrayValue = value; }
       
   185 
       
   186     QBrush brushProperty() const
       
   187         { return m_brushValue; }
       
   188     Q_INVOKABLE void setBrushProperty(const QBrush &value)
       
   189         { m_brushValue = value; }
       
   190 
       
   191     double hiddenProperty() const
       
   192         { return m_hiddenValue; }
       
   193     void setHiddenProperty(double value)
       
   194         { m_hiddenValue = value; }
       
   195 
       
   196     int writeOnlyProperty() const
       
   197         { return m_writeOnlyValue; }
       
   198     void setWriteOnlyProperty(int value)
       
   199         { m_writeOnlyValue = value; }
       
   200 
       
   201     int readOnlyProperty() const
       
   202         { return m_readOnlyValue; }
       
   203 
       
   204     QKeySequence shortcut() const
       
   205         { return m_shortcut; }
       
   206     void setShortcut(const QKeySequence &seq)
       
   207         { m_shortcut = seq; }
       
   208 
       
   209     CustomType propWithCustomType() const
       
   210         { return m_customType; }
       
   211     void setPropWithCustomType(const CustomType &c)
       
   212         { m_customType = c; }
       
   213 
       
   214     Policy enumProperty() const
       
   215         { return m_enumValue; }
       
   216     void setEnumProperty(Policy policy)
       
   217         { m_enumValue = policy; }
       
   218 
       
   219     int qtFunctionInvoked() const
       
   220         { return m_qtFunctionInvoked; }
       
   221 
       
   222     QVariantList qtFunctionActuals() const
       
   223         { return m_actuals; }
       
   224 
       
   225     void resetQtFunctionInvoked()
       
   226         { m_qtFunctionInvoked = -1; m_actuals.clear(); }
       
   227 
       
   228     void clearConnectedSignal()
       
   229         { m_connectedSignal = QByteArray(); }
       
   230     void clearDisconnectedSignal()
       
   231         { m_disconnectedSignal = QByteArray(); }
       
   232     QByteArray connectedSignal() const
       
   233         { return m_connectedSignal; }
       
   234     QByteArray disconnectedSignal() const
       
   235         { return m_disconnectedSignal; }
       
   236 
       
   237     Q_INVOKABLE void myInvokable()
       
   238         { m_qtFunctionInvoked = 0; }
       
   239     Q_INVOKABLE void myInvokableWithIntArg(int arg)
       
   240         { m_qtFunctionInvoked = 1; m_actuals << arg; }
       
   241     Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg)
       
   242         { m_qtFunctionInvoked = 2; m_actuals << arg; }
       
   243     Q_INVOKABLE void myInvokableWithFloatArg(float arg)
       
   244         { m_qtFunctionInvoked = 3; m_actuals << arg; }
       
   245     Q_INVOKABLE void myInvokableWithDoubleArg(double arg)
       
   246         { m_qtFunctionInvoked = 4; m_actuals << arg; }
       
   247     Q_INVOKABLE void myInvokableWithStringArg(const QString &arg)
       
   248         { m_qtFunctionInvoked = 5; m_actuals << arg; }
       
   249     Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2)
       
   250         { m_qtFunctionInvoked = 6; m_actuals << arg1 << arg2; }
       
   251     Q_INVOKABLE int myInvokableReturningInt()
       
   252         { m_qtFunctionInvoked = 7; return 123; }
       
   253     Q_INVOKABLE qlonglong myInvokableReturningLongLong()
       
   254         { m_qtFunctionInvoked = 39; return 456; }
       
   255     Q_INVOKABLE QString myInvokableReturningString()
       
   256         { m_qtFunctionInvoked = 8; return QLatin1String("ciao"); }
       
   257     Q_INVOKABLE QVariant myInvokableReturningVariant()
       
   258         { m_qtFunctionInvoked = 60; return 123; }
       
   259     Q_INVOKABLE QScriptValue myInvokableReturningScriptValue()
       
   260         { m_qtFunctionInvoked = 61; return 456; }
       
   261     Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // overload
       
   262         { m_qtFunctionInvoked = 9; m_actuals << arg1 << arg2; }
       
   263     Q_INVOKABLE void myInvokableWithEnumArg(Policy policy)
       
   264         { m_qtFunctionInvoked = 10; m_actuals << policy; }
       
   265     Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy)
       
   266         { m_qtFunctionInvoked = 36; m_actuals << policy; }
       
   267     Q_INVOKABLE Policy myInvokableReturningEnum()
       
   268         { m_qtFunctionInvoked = 37; return BazPolicy; }
       
   269     Q_INVOKABLE MyQObject::Strategy myInvokableReturningQualifiedEnum()
       
   270         { m_qtFunctionInvoked = 38; return BazStrategy; }
       
   271     Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt()
       
   272         { m_qtFunctionInvoked = 11; return QVector<int>(); }
       
   273     Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &)
       
   274         { m_qtFunctionInvoked = 12; }
       
   275     Q_INVOKABLE QObject *myInvokableReturningQObjectStar()
       
   276         { m_qtFunctionInvoked = 13; return this; }
       
   277     Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst)
       
   278         { m_qtFunctionInvoked = 14; m_actuals << qVariantFromValue(lst); return lst; }
       
   279     Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v)
       
   280         { m_qtFunctionInvoked = 15; m_actuals << v; return v; }
       
   281     Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm)
       
   282         { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; }
       
   283     Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst)
       
   284         { m_qtFunctionInvoked = 17; m_actuals << qVariantFromValue(lst); return lst; }
       
   285     Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj)
       
   286         { m_qtFunctionInvoked = 18; m_actuals << qVariantFromValue(obj); return obj; }
       
   287     Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush)
       
   288         { m_qtFunctionInvoked = 19; m_actuals << qVariantFromValue(brush); return brush; }
       
   289     Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style)
       
   290         { m_qtFunctionInvoked = 43; m_actuals << qVariantFromValue(style); }
       
   291     Q_INVOKABLE void myInvokableWithVoidStarArg(void *arg)
       
   292         { m_qtFunctionInvoked = 44; m_actuals << qVariantFromValue(arg); }
       
   293     Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg)
       
   294         { m_qtFunctionInvoked = 45; m_actuals << qVariantFromValue(arg); }
       
   295     Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg)
       
   296         { m_qtFunctionInvoked = 46; m_actuals << qVariantFromValue(arg); }
       
   297     Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "")
       
   298         { m_qtFunctionInvoked = 47; m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2); }
       
   299     Q_INVOKABLE QObject& myInvokableReturningRef()
       
   300         { m_qtFunctionInvoked = 48; return *this; }
       
   301     Q_INVOKABLE const QObject& myInvokableReturningConstRef() const
       
   302         { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49; return *this; }
       
   303     Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg)
       
   304         { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50; m_actuals << qVariantFromValue(arg); }
       
   305     Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg)
       
   306         { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51; m_actuals << qVariantFromValue(arg); }
       
   307     Q_INVOKABLE void myInvokableWithMyQObjectArg(MyQObject *arg)
       
   308         { m_qtFunctionInvoked = 52; m_actuals << qVariantFromValue((QObject*)arg); }
       
   309     Q_INVOKABLE MyQObject* myInvokableReturningMyQObject()
       
   310         { m_qtFunctionInvoked = 53; return this; }
       
   311     Q_INVOKABLE void myInvokableWithConstMyQObjectArg(const MyQObject *arg)
       
   312         { m_qtFunctionInvoked = 54; m_actuals << qVariantFromValue((QObject*)arg); }
       
   313     Q_INVOKABLE void myInvokableWithQDirArg(const QDir &arg)
       
   314         { m_qtFunctionInvoked = 55; m_actuals << qVariantFromValue(arg); }
       
   315     Q_INVOKABLE QScriptValue myInvokableWithScriptValueArg(const QScriptValue &arg)
       
   316         { m_qtFunctionInvoked = 56; return arg; }
       
   317     Q_INVOKABLE QObject* myInvokableReturningMyQObjectAsQObject()
       
   318         { m_qtFunctionInvoked = 57; return this; }
       
   319 
       
   320     Q_INVOKABLE QObjectList findObjects() const
       
   321     {  return findChildren<QObject *>();  }
       
   322     Q_INVOKABLE QList<int> myInvokableNumbers() const
       
   323     {  return QList<int>() << 1 << 2 << 3; }
       
   324 
       
   325     void emitMySignal()
       
   326         { emit mySignal(); }
       
   327     void emitMySignalWithIntArg(int arg)
       
   328         { emit mySignalWithIntArg(arg); }
       
   329     void emitMySignal2(bool arg)
       
   330         { emit mySignal2(arg); }
       
   331     void emitMySignal2()
       
   332         { emit mySignal2(); }
       
   333     void emitMyOverloadedSignal(int arg)
       
   334         { emit myOverloadedSignal(arg); }
       
   335     void emitMyOverloadedSignal(const QString &arg)
       
   336         { emit myOverloadedSignal(arg); }
       
   337     void emitMyOtherOverloadedSignal(const QString &arg)
       
   338         { emit myOtherOverloadedSignal(arg); }
       
   339     void emitMyOtherOverloadedSignal(int arg)
       
   340         { emit myOtherOverloadedSignal(arg); }
       
   341     void emitMySignalWithDefaultArgWithArg(int arg)
       
   342         { emit mySignalWithDefaultArg(arg); }
       
   343     void emitMySignalWithDefaultArg()
       
   344         { emit mySignalWithDefaultArg(); }
       
   345     void emitMySignalWithVariantArg(const QVariant &arg)
       
   346         { emit mySignalWithVariantArg(arg); }
       
   347     void emitMySignalWithScriptEngineArg(QScriptEngine *arg)
       
   348         { emit mySignalWithScriptEngineArg(arg); }
       
   349 
       
   350 public Q_SLOTS:
       
   351     void mySlot()
       
   352         { m_qtFunctionInvoked = 20; }
       
   353     void mySlotWithIntArg(int arg)
       
   354         { m_qtFunctionInvoked = 21; m_actuals << arg; }
       
   355     void mySlotWithDoubleArg(double arg)
       
   356         { m_qtFunctionInvoked = 22; m_actuals << arg; }
       
   357     void mySlotWithStringArg(const QString &arg)
       
   358         { m_qtFunctionInvoked = 23; m_actuals << arg; }
       
   359 
       
   360     void myOverloadedSlot()
       
   361         { m_qtFunctionInvoked = 24; }
       
   362     void myOverloadedSlot(QObject *arg)
       
   363         { m_qtFunctionInvoked = 41; m_actuals << qVariantFromValue(arg); }
       
   364     void myOverloadedSlot(bool arg)
       
   365         { m_qtFunctionInvoked = 25; m_actuals << arg; }
       
   366     void myOverloadedSlot(const QStringList &arg)
       
   367         { m_qtFunctionInvoked = 42; m_actuals << arg; }
       
   368     void myOverloadedSlot(double arg)
       
   369         { m_qtFunctionInvoked = 26; m_actuals << arg; }
       
   370     void myOverloadedSlot(float arg)
       
   371         { m_qtFunctionInvoked = 27; m_actuals << arg; }
       
   372     void myOverloadedSlot(int arg)
       
   373         { m_qtFunctionInvoked = 28; m_actuals << arg; }
       
   374     void myOverloadedSlot(const QString &arg)
       
   375         { m_qtFunctionInvoked = 29; m_actuals << arg; }
       
   376     void myOverloadedSlot(const QColor &arg)
       
   377         { m_qtFunctionInvoked = 30; m_actuals << arg; }
       
   378     void myOverloadedSlot(const QBrush &arg)
       
   379         { m_qtFunctionInvoked = 31; m_actuals << arg; }
       
   380     void myOverloadedSlot(const QDateTime &arg)
       
   381         { m_qtFunctionInvoked = 32; m_actuals << arg; }
       
   382     void myOverloadedSlot(const QDate &arg)
       
   383         { m_qtFunctionInvoked = 33; m_actuals << arg; }
       
   384     void myOverloadedSlot(const QRegExp &arg)
       
   385         { m_qtFunctionInvoked = 34; m_actuals << arg; }
       
   386     void myOverloadedSlot(const QVariant &arg)
       
   387         { m_qtFunctionInvoked = 35; m_actuals << arg; }
       
   388 
       
   389     virtual int myVirtualSlot(int arg)
       
   390         { m_qtFunctionInvoked = 58; return arg; }
       
   391 
       
   392     void qscript_call(int arg)
       
   393         { m_qtFunctionInvoked = 40; m_actuals << arg; }
       
   394 
       
   395 protected Q_SLOTS:
       
   396     void myProtectedSlot() { m_qtFunctionInvoked = 36; }
       
   397 
       
   398 private Q_SLOTS:
       
   399     void myPrivateSlot() { }
       
   400 
       
   401 Q_SIGNALS:
       
   402     void mySignal();
       
   403     void mySignalWithIntArg(int arg);
       
   404     void mySignalWithDoubleArg(double arg);
       
   405     void mySignal2(bool arg = false);
       
   406     void myOverloadedSignal(int arg);
       
   407     void myOverloadedSignal(const QString &arg);
       
   408     void myOtherOverloadedSignal(const QString &arg);
       
   409     void myOtherOverloadedSignal(int arg);
       
   410     void mySignalWithDefaultArg(int arg = 123);
       
   411     void mySignalWithVariantArg(const QVariant &arg);
       
   412     void mySignalWithScriptEngineArg(QScriptEngine *arg);
       
   413 
       
   414 protected:
       
   415     void connectNotify(const char *signal) {
       
   416         m_connectedSignal = signal;
       
   417     }
       
   418     void disconnectNotify(const char *signal) {
       
   419         m_disconnectedSignal = signal;
       
   420     }
       
   421 
       
   422 protected:
       
   423     int m_intValue;
       
   424     QVariant m_variantValue;
       
   425     QVariantList m_variantListValue;
       
   426     QString m_stringValue;
       
   427     QStringList m_stringListValue;
       
   428     QByteArray m_byteArrayValue;
       
   429     QBrush m_brushValue;
       
   430     double m_hiddenValue;
       
   431     int m_writeOnlyValue;
       
   432     int m_readOnlyValue;
       
   433     QKeySequence m_shortcut;
       
   434     CustomType m_customType;
       
   435     Policy m_enumValue;
       
   436     int m_qtFunctionInvoked;
       
   437     QVariantList m_actuals;
       
   438     QByteArray m_connectedSignal;
       
   439     QByteArray m_disconnectedSignal;
       
   440 };
       
   441 
       
   442 Q_DECLARE_METATYPE(MyQObject*)
       
   443 Q_DECLARE_METATYPE(MyQObject::Policy)
       
   444 
       
   445 class MyOtherQObject : public MyQObject
       
   446 {
       
   447     Q_OBJECT
       
   448 public:
       
   449     MyOtherQObject(QObject *parent = 0)
       
   450         : MyQObject(parent)
       
   451         { }
       
   452 public Q_SLOTS:
       
   453     virtual int myVirtualSlot(int arg)
       
   454         { m_qtFunctionInvoked = 59; return arg; }
       
   455 };
       
   456 
       
   457 class MyEnumTestQObject : public QObject
       
   458 {
       
   459     Q_OBJECT
       
   460     Q_PROPERTY(QString p1 READ p1)
       
   461     Q_PROPERTY(QString p2 READ p2)
       
   462     Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
       
   463     Q_PROPERTY(QString p4 READ p4)
       
   464     Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
       
   465     Q_PROPERTY(QString p6 READ p6)
       
   466 public:
       
   467     MyEnumTestQObject(QObject *parent = 0)
       
   468         : QObject(parent) { }
       
   469     QString p1() const { return QLatin1String("p1"); }
       
   470     QString p2() const { return QLatin1String("p2"); }
       
   471     QString p3() const { return QLatin1String("p3"); }
       
   472     QString p4() const { return QLatin1String("p4"); }
       
   473     QString p5() const { return QLatin1String("p5"); }
       
   474     QString p6() const { return QLatin1String("p5"); }
       
   475 public Q_SLOTS:
       
   476     void mySlot() { }
       
   477     void myOtherSlot() { }
       
   478 Q_SIGNALS:
       
   479     void mySignal();
       
   480 };
       
   481 
       
   482 class tst_QScriptExtQObject : public QObject
       
   483 {
       
   484     Q_OBJECT
       
   485 
       
   486 public:
       
   487     tst_QScriptExtQObject();
       
   488     virtual ~tst_QScriptExtQObject();
       
   489 
       
   490 public slots:
       
   491     void init();
       
   492     void cleanup();
       
   493 
       
   494 protected slots:
       
   495     void onSignalHandlerException(const QScriptValue &exception)
       
   496     {
       
   497         m_signalHandlerException = exception;
       
   498     }
       
   499 
       
   500 private slots:
       
   501     void registeredTypes();
       
   502     void getSetStaticProperty();
       
   503     void getSetDynamicProperty();
       
   504     void getSetChildren();
       
   505     void callQtInvokable();
       
   506     void connectAndDisconnect();
       
   507     void connectAndDisconnectWithBadArgs();
       
   508     void cppConnectAndDisconnect();
       
   509     void classEnums();
       
   510     void classConstructor();
       
   511     void overrideInvokable();
       
   512     void transferInvokable();
       
   513     void findChild();
       
   514     void findChildren();
       
   515     void overloadedSlots();
       
   516     void enumerate_data();
       
   517     void enumerate();
       
   518     void enumerateSpecial();
       
   519     void wrapOptions();
       
   520     void prototypes();
       
   521     void objectDeleted();
       
   522     void connectToDestroyedSignal();
       
   523 
       
   524 private:
       
   525     QScriptEngine *m_engine;
       
   526     MyQObject *m_myObject;
       
   527     QScriptValue m_signalHandlerException;
       
   528 };
       
   529 
       
   530 tst_QScriptExtQObject::tst_QScriptExtQObject()
       
   531 {
       
   532 }
       
   533 
       
   534 tst_QScriptExtQObject::~tst_QScriptExtQObject()
       
   535 {
       
   536 }
       
   537 
       
   538 void tst_QScriptExtQObject::init()
       
   539 {
       
   540     m_engine = new QScriptEngine();
       
   541     m_myObject = new MyQObject();
       
   542     m_engine->globalObject().setProperty("myObject", m_engine->newQObject(m_myObject));
       
   543     m_engine->globalObject().setProperty("global", m_engine->globalObject());
       
   544 }
       
   545 
       
   546 void tst_QScriptExtQObject::cleanup()
       
   547 {
       
   548     delete m_engine;
       
   549     delete m_myObject;
       
   550 }
       
   551 
       
   552 // this test has to be first and test that some types are automatically registered
       
   553 void tst_QScriptExtQObject::registeredTypes()
       
   554 {
       
   555     QScriptEngine e;
       
   556     QObject *t = new MyQObject;
       
   557     QObject *c = new QObject(t);
       
   558     c->setObjectName ("child1");
       
   559 
       
   560     e.globalObject().setProperty("MyTest", e.newQObject(t));
       
   561 
       
   562     QScriptValue v1 = e.evaluate("MyTest.findObjects()[0].objectName;");
       
   563     QCOMPARE(v1.toString(), c->objectName());
       
   564 
       
   565     QScriptValue v2 = e.evaluate("MyTest.myInvokableNumbers()");
       
   566     QCOMPARE(qscriptvalue_cast<QList<int> >(v2), (QList<int>() << 1 << 2 << 3));
       
   567 }
       
   568 
       
   569 
       
   570 static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *)
       
   571 {
       
   572     if (ctx->argumentCount() != 0)
       
   573         ctx->callee().setProperty("value", ctx->argument(0));
       
   574     return ctx->callee().property("value");
       
   575 }
       
   576 
       
   577 static QScriptValue policyToScriptValue(QScriptEngine *engine, const MyQObject::Policy &policy)
       
   578 {
       
   579     return qScriptValueFromValue(engine, policy);
       
   580 }
       
   581 
       
   582 static void policyFromScriptValue(const QScriptValue &value, MyQObject::Policy &policy)
       
   583 {
       
   584     QString str = value.toString();
       
   585     if (str == QLatin1String("red"))
       
   586         policy = MyQObject::FooPolicy;
       
   587     else if (str == QLatin1String("green"))
       
   588         policy = MyQObject::BarPolicy;
       
   589     else if (str == QLatin1String("blue"))
       
   590         policy = MyQObject::BazPolicy;
       
   591     else
       
   592         policy = (MyQObject::Policy)-1;
       
   593 }
       
   594 
       
   595 void tst_QScriptExtQObject::getSetStaticProperty()
       
   596 {
       
   597     QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true);
       
   598 
       
   599     // initial value (set in MyQObject constructor)
       
   600     QCOMPARE(m_engine->evaluate("myObject.intProperty")
       
   601              .strictlyEquals(QScriptValue(m_engine, 123.0)), true);
       
   602     QCOMPARE(m_engine->evaluate("myObject.variantProperty")
       
   603              .toVariant(), QVariant(QLatin1String("foo")));
       
   604     QCOMPARE(m_engine->evaluate("myObject.stringProperty")
       
   605              .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))), true);
       
   606     QCOMPARE(m_engine->evaluate("myObject.variantListProperty").isArray(), true);
       
   607     QCOMPARE(m_engine->evaluate("myObject.variantListProperty.length")
       
   608              .strictlyEquals(QScriptValue(m_engine, 2)), true);
       
   609     QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
       
   610              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
   611     QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
       
   612              .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
       
   613     QCOMPARE(m_engine->evaluate("myObject.stringListProperty").isArray(), true);
       
   614     QCOMPARE(m_engine->evaluate("myObject.stringListProperty.length")
       
   615              .strictlyEquals(QScriptValue(m_engine, 2)), true);
       
   616     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
       
   617     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
       
   618              QLatin1String("zig"));
       
   619     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
       
   620     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
       
   621              QLatin1String("zag"));
       
   622 
       
   623     // default flags for "normal" properties
       
   624     {
       
   625         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   626         QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::ReadOnly));
       
   627         QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::Undeletable);
       
   628         QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertyGetter);
       
   629         QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertySetter);
       
   630         QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::SkipInEnumeration));
       
   631         QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
       
   632 
       
   633         QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::ReadOnly));
       
   634         QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::Undeletable));
       
   635         QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::SkipInEnumeration));
       
   636         QVERIFY(mobj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
       
   637 
       
   638         // signature-based property
       
   639         QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::ReadOnly));
       
   640         QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::Undeletable));
       
   641         QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::SkipInEnumeration));
       
   642         QVERIFY(mobj.propertyFlags("mySlot()") & QScriptValue::QObjectMember);
       
   643     }
       
   644 
       
   645     // property change in C++ should be reflected in script
       
   646     m_myObject->setIntProperty(456);
       
   647     QCOMPARE(m_engine->evaluate("myObject.intProperty")
       
   648              .strictlyEquals(QScriptValue(m_engine, 456)), true);
       
   649     m_myObject->setIntProperty(789);
       
   650     QCOMPARE(m_engine->evaluate("myObject.intProperty")
       
   651              .strictlyEquals(QScriptValue(m_engine, 789)), true);
       
   652 
       
   653     m_myObject->setVariantProperty(QLatin1String("bar"));
       
   654     QVERIFY(m_engine->evaluate("myObject.variantProperty")
       
   655             .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))));
       
   656     m_myObject->setVariantProperty(42);
       
   657     QCOMPARE(m_engine->evaluate("myObject.variantProperty")
       
   658              .toVariant(), QVariant(42));
       
   659     m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
       
   660     QVERIFY(m_engine->evaluate("myObject.variantProperty").isVariant());
       
   661 
       
   662     m_myObject->setStringProperty(QLatin1String("baz"));
       
   663     QCOMPARE(m_engine->evaluate("myObject.stringProperty")
       
   664              .equals(QScriptValue(m_engine, QLatin1String("baz"))), true);
       
   665     m_myObject->setStringProperty(QLatin1String("zab"));
       
   666     QCOMPARE(m_engine->evaluate("myObject.stringProperty")
       
   667              .equals(QScriptValue(m_engine, QLatin1String("zab"))), true);
       
   668 
       
   669     // property change in script should be reflected in C++
       
   670     QCOMPARE(m_engine->evaluate("myObject.intProperty = 123")
       
   671              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
   672     QCOMPARE(m_engine->evaluate("myObject.intProperty")
       
   673              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
   674     QCOMPARE(m_myObject->intProperty(), 123);
       
   675     QCOMPARE(m_engine->evaluate("myObject.intProperty = 'ciao!';"
       
   676                                 "myObject.intProperty")
       
   677              .strictlyEquals(QScriptValue(m_engine, 0)), true);
       
   678     QCOMPARE(m_myObject->intProperty(), 0);
       
   679     QCOMPARE(m_engine->evaluate("myObject.intProperty = '123';"
       
   680                                 "myObject.intProperty")
       
   681              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
   682     QCOMPARE(m_myObject->intProperty(), 123);
       
   683 
       
   684     QCOMPARE(m_engine->evaluate("myObject.stringProperty = 'ciao'")
       
   685              .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
       
   686     QCOMPARE(m_engine->evaluate("myObject.stringProperty")
       
   687              .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
       
   688     QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
       
   689     QCOMPARE(m_engine->evaluate("myObject.stringProperty = 123;"
       
   690                                 "myObject.stringProperty")
       
   691              .strictlyEquals(QScriptValue(m_engine, QLatin1String("123"))), true);
       
   692     QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
       
   693     QVERIFY(m_engine->evaluate("myObject.stringProperty = null;"
       
   694                                "myObject.stringProperty")
       
   695             .strictlyEquals(QScriptValue(m_engine, QString())));
       
   696     QCOMPARE(m_myObject->stringProperty(), QString());
       
   697     QVERIFY(m_engine->evaluate("myObject.stringProperty = undefined;"
       
   698                                "myObject.stringProperty")
       
   699             .strictlyEquals(QScriptValue(m_engine, QString())));
       
   700     QCOMPARE(m_myObject->stringProperty(), QString());
       
   701 
       
   702     QCOMPARE(m_engine->evaluate("myObject.variantProperty = 'foo';"
       
   703                                 "myObject.variantProperty.valueOf()").toString(), QLatin1String("foo"));
       
   704     QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
       
   705     QVERIFY(m_engine->evaluate("myObject.variantProperty = undefined;"
       
   706                                "myObject.variantProperty").isUndefined());
       
   707     QVERIFY(!m_myObject->variantProperty().isValid());
       
   708     QVERIFY(m_engine->evaluate("myObject.variantProperty = null;"
       
   709                                "myObject.variantProperty").isUndefined());
       
   710     QVERIFY(!m_myObject->variantProperty().isValid());
       
   711     QCOMPARE(m_engine->evaluate("myObject.variantProperty = 42;"
       
   712                                 "myObject.variantProperty").toNumber(), 42.0);
       
   713     QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
       
   714 
       
   715     QCOMPARE(m_engine->evaluate("myObject.variantListProperty = [1, 'two', true];"
       
   716                                 "myObject.variantListProperty.length")
       
   717              .strictlyEquals(QScriptValue(m_engine, 3)), true);
       
   718     QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
       
   719              .strictlyEquals(QScriptValue(m_engine, 1)), true);
       
   720     QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
       
   721              .strictlyEquals(QScriptValue(m_engine, QLatin1String("two"))), true);
       
   722     QCOMPARE(m_engine->evaluate("myObject.variantListProperty[2]")
       
   723              .strictlyEquals(QScriptValue(m_engine, true)), true);
       
   724     {
       
   725         QVariantList vl = qscriptvalue_cast<QVariantList>(m_engine->evaluate("myObject.variantListProperty"));
       
   726         QCOMPARE(vl, QVariantList()
       
   727                  << QVariant(1)
       
   728                  << QVariant(QLatin1String("two"))
       
   729                  << QVariant(true));
       
   730     }
       
   731 
       
   732     QCOMPARE(m_engine->evaluate("myObject.stringListProperty = [1, 'two', true];"
       
   733                                 "myObject.stringListProperty.length")
       
   734              .strictlyEquals(QScriptValue(m_engine, 3)), true);
       
   735     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
       
   736     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
       
   737              QLatin1String("1"));
       
   738     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
       
   739     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
       
   740              QLatin1String("two"));
       
   741     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").isString(), true);
       
   742     QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").toString(),
       
   743              QLatin1String("true"));
       
   744     {
       
   745         QStringList sl = qscriptvalue_cast<QStringList>(m_engine->evaluate("myObject.stringListProperty"));
       
   746         QCOMPARE(sl, QStringList()
       
   747                  << QLatin1String("1")
       
   748                  << QLatin1String("two")
       
   749                  << QLatin1String("true"));
       
   750     }
       
   751 
       
   752     // test setting properties where we can't convert the type natively but where the
       
   753     // types happen to be compatible variant types already
       
   754     {
       
   755         QKeySequence sequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_Delete);
       
   756         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   757 
       
   758         QVERIFY(m_myObject->shortcut().isEmpty());
       
   759         mobj.setProperty("shortcut", m_engine->newVariant(sequence));
       
   760         QVERIFY(m_myObject->shortcut() == sequence);
       
   761     }
       
   762     {
       
   763         CustomType t; t.string = "hello";
       
   764         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   765 
       
   766         QVERIFY(m_myObject->propWithCustomType().string.isEmpty());
       
   767         mobj.setProperty("propWithCustomType", m_engine->newVariant(qVariantFromValue(t)));
       
   768         QVERIFY(m_myObject->propWithCustomType().string == t.string);
       
   769     }
       
   770 
       
   771     // test that we do value conversion if necessary when setting properties
       
   772     {
       
   773         QScriptValue br = m_engine->evaluate("myObject.brushProperty");
       
   774         QVERIFY(br.isVariant());
       
   775         QVERIFY(!br.strictlyEquals(m_engine->evaluate("myObject.brushProperty")));
       
   776         QCOMPARE(qscriptvalue_cast<QBrush>(br), m_myObject->brushProperty());
       
   777         QCOMPARE(qscriptvalue_cast<QColor>(br), m_myObject->brushProperty().color());
       
   778 
       
   779         QColor newColor(40, 30, 20, 10);
       
   780         QScriptValue val = qScriptValueFromValue(m_engine, newColor);
       
   781         m_engine->globalObject().setProperty("myColor", val);
       
   782         QScriptValue ret = m_engine->evaluate("myObject.brushProperty = myColor");
       
   783         QCOMPARE(ret.strictlyEquals(val), true);
       
   784         br = m_engine->evaluate("myObject.brushProperty");
       
   785         QCOMPARE(qscriptvalue_cast<QBrush>(br), QBrush(newColor));
       
   786         QCOMPARE(qscriptvalue_cast<QColor>(br), newColor);
       
   787 
       
   788         m_engine->globalObject().setProperty("myColor", QScriptValue());
       
   789     }
       
   790 
       
   791     // try to delete
       
   792     QCOMPARE(m_engine->evaluate("delete myObject.intProperty").toBoolean(), false);
       
   793     QCOMPARE(m_engine->evaluate("myObject.intProperty").toNumber(), 123.0);
       
   794 
       
   795     QCOMPARE(m_engine->evaluate("delete myObject.variantProperty").toBoolean(), false);
       
   796     QCOMPARE(m_engine->evaluate("myObject.variantProperty").toNumber(), 42.0);
       
   797 
       
   798     // non-scriptable property
       
   799     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
       
   800     QCOMPARE(m_engine->evaluate("myObject.hiddenProperty").isUndefined(), true);
       
   801     QCOMPARE(m_engine->evaluate("myObject.hiddenProperty = 123;"
       
   802                                 "myObject.hiddenProperty").toInt32(), 123);
       
   803     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
       
   804 
       
   805     // write-only property
       
   806     QCOMPARE(m_myObject->writeOnlyProperty(), 789);
       
   807     QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty").isUndefined(), true);
       
   808     QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty = 123;"
       
   809                                 "myObject.writeOnlyProperty").isUndefined(), true);
       
   810     QCOMPARE(m_myObject->writeOnlyProperty(), 123);
       
   811 
       
   812     // read-only property
       
   813     QCOMPARE(m_myObject->readOnlyProperty(), 987);
       
   814     QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty").toInt32(), 987);
       
   815     QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty = 654;"
       
   816                                 "myObject.readOnlyProperty").toInt32(), 987);
       
   817     QCOMPARE(m_myObject->readOnlyProperty(), 987);
       
   818     {
       
   819         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   820         QCOMPARE(mobj.propertyFlags("readOnlyProperty") & QScriptValue::ReadOnly,
       
   821                  QScriptValue::ReadOnly);
       
   822     }
       
   823 
       
   824     // enum property
       
   825     QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
       
   826     {
       
   827         QScriptValue val = m_engine->evaluate("myObject.enumProperty");
       
   828         QVERIFY(val.isNumber());
       
   829         QCOMPARE(val.toInt32(), (int)MyQObject::BarPolicy);
       
   830     }
       
   831     m_engine->evaluate("myObject.enumProperty = 2");
       
   832     QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
       
   833     m_engine->evaluate("myObject.enumProperty = 'BarPolicy'");
       
   834     QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
       
   835     m_engine->evaluate("myObject.enumProperty = 'ScoobyDoo'");
       
   836     // ### ouch! Shouldn't QMetaProperty::write() rather not change the value...?
       
   837     QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
       
   838     // enum property with custom conversion
       
   839     qScriptRegisterMetaType<MyQObject::Policy>(m_engine, policyToScriptValue, policyFromScriptValue);
       
   840     m_engine->evaluate("myObject.enumProperty = 'red'");
       
   841     QCOMPARE(m_myObject->enumProperty(), MyQObject::FooPolicy);
       
   842     m_engine->evaluate("myObject.enumProperty = 'green'");
       
   843     QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
       
   844     m_engine->evaluate("myObject.enumProperty = 'blue'");
       
   845     QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
       
   846     m_engine->evaluate("myObject.enumProperty = 'nada'");
       
   847     QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
       
   848 
       
   849     // auto-dereferencing of pointers
       
   850     {
       
   851         QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE);
       
   852         QBrush *bp = &b;
       
   853         QScriptValue bpValue = m_engine->newVariant(qVariantFromValue(bp));
       
   854         m_engine->globalObject().setProperty("brushPointer", bpValue);
       
   855         {
       
   856             QScriptValue ret = m_engine->evaluate("myObject.setBrushProperty(brushPointer)");
       
   857             QCOMPARE(ret.isUndefined(), true);
       
   858             QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
       
   859         }
       
   860         {
       
   861             b = QColor(0xDE, 0xAD, 0xBE, 0xEF);
       
   862             QScriptValue ret = m_engine->evaluate("myObject.brushProperty = brushPointer");
       
   863             QCOMPARE(ret.strictlyEquals(bpValue), true);
       
   864             QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
       
   865         }
       
   866         m_engine->globalObject().setProperty("brushPointer", QScriptValue());
       
   867     }
       
   868 
       
   869     // install custom property getter+setter
       
   870     {
       
   871         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   872         mobj.setProperty("intProperty", m_engine->newFunction(getSetProperty),
       
   873                          QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
       
   874         QVERIFY(mobj.property("intProperty").toInt32() != 321);
       
   875         mobj.setProperty("intProperty", 321);
       
   876         QCOMPARE(mobj.property("intProperty").toInt32(), 321);
       
   877     }
       
   878 
       
   879     // method properties are persistent
       
   880     {
       
   881         QScriptValue slot = m_engine->evaluate("myObject.mySlot");
       
   882         QVERIFY(slot.isFunction());
       
   883         QScriptValue sameSlot = m_engine->evaluate("myObject.mySlot");
       
   884         QVERIFY(sameSlot.strictlyEquals(slot));
       
   885         sameSlot = m_engine->evaluate("myObject[mySlot()]");
       
   886         QEXPECT_FAIL("", "Signature-based method lookup creates new function wrapper object", Continue);
       
   887         QVERIFY(sameSlot.strictlyEquals(slot));
       
   888     }
       
   889 }
       
   890 
       
   891 void tst_QScriptExtQObject::getSetDynamicProperty()
       
   892 {
       
   893     // initially the object does not have the property
       
   894     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
       
   895              .strictlyEquals(QScriptValue(m_engine, false)), true);
       
   896 
       
   897     // add a dynamic property in C++
       
   898     QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
       
   899     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
       
   900              .strictlyEquals(QScriptValue(m_engine, true)), true);
       
   901     QCOMPARE(m_engine->evaluate("myObject.dynamicProperty")
       
   902              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
   903 
       
   904     // check the flags
       
   905     {
       
   906         QScriptValue mobj = m_engine->globalObject().property("myObject");
       
   907         QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::ReadOnly));
       
   908         QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::Undeletable));
       
   909         QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::SkipInEnumeration));
       
   910         QVERIFY(mobj.propertyFlags("dynamicProperty") & QScriptValue::QObjectMember);
       
   911     }
       
   912 
       
   913     // property change in script should be reflected in C++
       
   914     QCOMPARE(m_engine->evaluate("myObject.dynamicProperty = 'foo';"
       
   915                                 "myObject.dynamicProperty")
       
   916              .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
       
   917     QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
       
   918 
       
   919     // delete the property
       
   920     QCOMPARE(m_engine->evaluate("delete myObject.dynamicProperty").toBoolean(), true);
       
   921     QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
       
   922     QCOMPARE(m_engine->evaluate("myObject.dynamicProperty").isUndefined(), true);
       
   923     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')").toBoolean(), false);
       
   924 }
       
   925 
       
   926 void tst_QScriptExtQObject::getSetChildren()
       
   927 {
       
   928     QScriptValue mobj = m_engine->evaluate("myObject");
       
   929 
       
   930     // initially the object does not have the child
       
   931     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
       
   932              .strictlyEquals(QScriptValue(m_engine, false)), true);
       
   933 
       
   934     // add a child
       
   935     MyQObject *child = new MyQObject(m_myObject);
       
   936     child->setObjectName("child");
       
   937     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
       
   938              .strictlyEquals(QScriptValue(m_engine, true)), true);
       
   939 
       
   940     QVERIFY(mobj.propertyFlags("child") & QScriptValue::ReadOnly);
       
   941     QVERIFY(mobj.propertyFlags("child") & QScriptValue::Undeletable);
       
   942     QVERIFY(mobj.propertyFlags("child") & QScriptValue::SkipInEnumeration);
       
   943     QVERIFY(!(mobj.propertyFlags("child") & QScriptValue::QObjectMember));
       
   944 
       
   945     {
       
   946         QScriptValue scriptChild = m_engine->evaluate("myObject.child");
       
   947         QVERIFY(scriptChild.isQObject());
       
   948         QCOMPARE(scriptChild.toQObject(), (QObject*)child);
       
   949         QScriptValue sameChild = m_engine->evaluate("myObject.child");
       
   950         QVERIFY(sameChild.strictlyEquals(scriptChild));
       
   951     }
       
   952 
       
   953     // add a grandchild
       
   954     MyQObject *grandChild = new MyQObject(child);
       
   955     grandChild->setObjectName("grandChild");
       
   956     QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
       
   957              .strictlyEquals(QScriptValue(m_engine, true)), true);
       
   958 
       
   959     // delete grandchild
       
   960     delete grandChild;
       
   961     QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
       
   962              .strictlyEquals(QScriptValue(m_engine, false)), true);
       
   963 
       
   964     // delete child
       
   965     delete child;
       
   966     QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
       
   967              .strictlyEquals(QScriptValue(m_engine, false)), true);
       
   968 
       
   969 }
       
   970 
       
   971 Q_DECLARE_METATYPE(QVector<int>)
       
   972 Q_DECLARE_METATYPE(QVector<double>)
       
   973 Q_DECLARE_METATYPE(QVector<QString>)
       
   974 
       
   975 template <class T>
       
   976 static QScriptValue qobjectToScriptValue(QScriptEngine *engine, T* const &in)
       
   977 { return engine->newQObject(in); }
       
   978 
       
   979 template <class T>
       
   980 static void qobjectFromScriptValue(const QScriptValue &object, T* &out)
       
   981 { out = qobject_cast<T*>(object.toQObject()); }
       
   982 
       
   983 void tst_QScriptExtQObject::callQtInvokable()
       
   984 {
       
   985     m_myObject->resetQtFunctionInvoked();
       
   986     QCOMPARE(m_engine->evaluate("myObject.myInvokable()").isUndefined(), true);
       
   987     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
   988     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
   989 
       
   990     // extra arguments should silently be ignored
       
   991     m_myObject->resetQtFunctionInvoked();
       
   992     QCOMPARE(m_engine->evaluate("myObject.myInvokable(10, 20, 30)").isUndefined(), true);
       
   993     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
   994     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
   995 
       
   996     m_myObject->resetQtFunctionInvoked();
       
   997     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123)").isUndefined(), true);
       
   998     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
   999     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1000     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1001 
       
  1002     m_myObject->resetQtFunctionInvoked();
       
  1003     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg('123')").isUndefined(), true);
       
  1004     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1005     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1006     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1007 
       
  1008     m_myObject->resetQtFunctionInvoked();
       
  1009     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithLonglongArg(123)").isUndefined(), true);
       
  1010     QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
       
  1011     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1012     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
       
  1013 
       
  1014     m_myObject->resetQtFunctionInvoked();
       
  1015     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithFloatArg(123.5)").isUndefined(), true);
       
  1016     QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
       
  1017     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1018     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
       
  1019 
       
  1020     m_myObject->resetQtFunctionInvoked();
       
  1021     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithDoubleArg(123.5)").isUndefined(), true);
       
  1022     QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
       
  1023     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1024     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
       
  1025 
       
  1026     m_myObject->resetQtFunctionInvoked();
       
  1027     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg('ciao')").isUndefined(), true);
       
  1028     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1029     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1030     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
       
  1031 
       
  1032     m_myObject->resetQtFunctionInvoked();
       
  1033     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg(123)").isUndefined(), true);
       
  1034     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1035     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1036     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
       
  1037 
       
  1038     m_myObject->resetQtFunctionInvoked();
       
  1039     QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(null)").isUndefined());
       
  1040     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1041     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1042     QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
       
  1043     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
       
  1044 
       
  1045     m_myObject->resetQtFunctionInvoked();
       
  1046     QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(undefined)").isUndefined());
       
  1047     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1048     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1049     QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
       
  1050     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
       
  1051 
       
  1052     m_myObject->resetQtFunctionInvoked();
       
  1053     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArgs(123, 456)").isUndefined(), true);
       
  1054     QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
       
  1055     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1056     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1057     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
       
  1058 
       
  1059     m_myObject->resetQtFunctionInvoked();
       
  1060     QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningInt()")
       
  1061              .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  1062     QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
       
  1063     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1064 
       
  1065     m_myObject->resetQtFunctionInvoked();
       
  1066     QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningLongLong()")
       
  1067              .strictlyEquals(QScriptValue(m_engine, 456)), true);
       
  1068     QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
       
  1069     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1070 
       
  1071     m_myObject->resetQtFunctionInvoked();
       
  1072     QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningString()")
       
  1073              .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
       
  1074     QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
       
  1075     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1076 
       
  1077     m_myObject->resetQtFunctionInvoked();
       
  1078     QVERIFY(m_engine->evaluate("myObject.myInvokableReturningVariant()")
       
  1079              .strictlyEquals(QScriptValue(m_engine, 123)));
       
  1080     QCOMPARE(m_myObject->qtFunctionInvoked(), 60);
       
  1081 
       
  1082     m_myObject->resetQtFunctionInvoked();
       
  1083     QVERIFY(m_engine->evaluate("myObject.myInvokableReturningScriptValue()")
       
  1084              .strictlyEquals(QScriptValue(m_engine, 456)));
       
  1085     QCOMPARE(m_myObject->qtFunctionInvoked(), 61);
       
  1086 
       
  1087     m_myObject->resetQtFunctionInvoked();
       
  1088     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123, 456)").isUndefined(), true);
       
  1089     QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
       
  1090     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1091     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1092     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
       
  1093 
       
  1094     m_myObject->resetQtFunctionInvoked();
       
  1095     QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined());
       
  1096     QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
       
  1097     m_myObject->resetQtFunctionInvoked();
       
  1098     QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(123)").isError());
       
  1099     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1100 
       
  1101     m_myObject->resetQtFunctionInvoked();
       
  1102     {
       
  1103         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithAmbiguousArg(123)");
       
  1104         QVERIFY(ret.isError());
       
  1105         QCOMPARE(ret.toString(), QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n    myInvokableWithAmbiguousArg(int)\n    myInvokableWithAmbiguousArg(uint)"));
       
  1106     }
       
  1107 
       
  1108     m_myObject->resetQtFunctionInvoked();
       
  1109     {
       
  1110         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(123, 'hello')");
       
  1111         QVERIFY(ret.isUndefined());
       
  1112         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
       
  1113         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1114         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1115         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
       
  1116     }
       
  1117 
       
  1118     m_myObject->resetQtFunctionInvoked();
       
  1119     {
       
  1120         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(456)");
       
  1121         QVERIFY(ret.isUndefined());
       
  1122         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
       
  1123         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1124         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
       
  1125         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
       
  1126     }
       
  1127 
       
  1128     {
       
  1129         QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithPointArg");
       
  1130         QVERIFY(fun.isFunction());
       
  1131         m_myObject->resetQtFunctionInvoked();
       
  1132         {
       
  1133             QScriptValue ret = fun.call(m_engine->evaluate("myObject"),
       
  1134                                         QScriptValueList() << qScriptValueFromValue(m_engine, QPoint(10, 20)));
       
  1135             QVERIFY(ret.isUndefined());
       
  1136             QCOMPARE(m_myObject->qtFunctionInvoked(), 50);
       
  1137             QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1138             QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPoint(), QPoint(10, 20));
       
  1139         }
       
  1140         m_myObject->resetQtFunctionInvoked();
       
  1141         {
       
  1142             QScriptValue ret = fun.call(m_engine->evaluate("myObject"),
       
  1143                                         QScriptValueList() << qScriptValueFromValue(m_engine, QPointF(30, 40)));
       
  1144             QVERIFY(ret.isUndefined());
       
  1145             QCOMPARE(m_myObject->qtFunctionInvoked(), 51);
       
  1146             QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1147             QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPointF(), QPointF(30, 40));
       
  1148         }
       
  1149     }
       
  1150 
       
  1151     // calling function that returns (const)ref
       
  1152     m_myObject->resetQtFunctionInvoked();
       
  1153     {
       
  1154         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningRef()");
       
  1155         QVERIFY(ret.isUndefined());
       
  1156         QVERIFY(!m_engine->hasUncaughtException());
       
  1157         QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
       
  1158     }
       
  1159     m_myObject->resetQtFunctionInvoked();
       
  1160     {
       
  1161         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningConstRef()");
       
  1162         QVERIFY(ret.isUndefined());
       
  1163         QVERIFY(!m_engine->hasUncaughtException());
       
  1164         QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
       
  1165     }
       
  1166 
       
  1167     // first time we expect failure because the metatype is not registered
       
  1168     m_myObject->resetQtFunctionInvoked();
       
  1169     QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()").isError(), true);
       
  1170     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1171 
       
  1172     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(0)").isError(), true);
       
  1173     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1174 
       
  1175     // now we register it, and it should work
       
  1176     qScriptRegisterSequenceMetaType<QVector<int> >(m_engine);
       
  1177     {
       
  1178         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()");
       
  1179         QCOMPARE(ret.isArray(), true);
       
  1180         QCOMPARE(m_myObject->qtFunctionInvoked(), 11);
       
  1181     }
       
  1182 
       
  1183     {
       
  1184         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(myObject.myInvokableReturningVectorOfInt())");
       
  1185         QCOMPARE(ret.isUndefined(), true);
       
  1186         QCOMPARE(m_myObject->qtFunctionInvoked(), 12);
       
  1187     }
       
  1188 
       
  1189     m_myObject->resetQtFunctionInvoked();
       
  1190     {
       
  1191         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQObjectStar()");
       
  1192         QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
       
  1193         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  1194         QCOMPARE(ret.isQObject(), true);
       
  1195         QCOMPARE(ret.toQObject(), (QObject *)m_myObject);
       
  1196     }
       
  1197 
       
  1198     m_myObject->resetQtFunctionInvoked();
       
  1199     {
       
  1200         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectListArg([myObject])");
       
  1201         QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
       
  1202         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1203         QCOMPARE(ret.isArray(), true);
       
  1204         QCOMPARE(ret.property(QLatin1String("length"))
       
  1205                  .strictlyEquals(QScriptValue(m_engine, 1)), true);
       
  1206         QCOMPARE(ret.property(QLatin1String("0")).isQObject(), true);
       
  1207         QCOMPARE(ret.property(QLatin1String("0")).toQObject(), (QObject *)m_myObject);
       
  1208     }
       
  1209 
       
  1210     m_myObject->resetQtFunctionInvoked();
       
  1211     {
       
  1212         m_myObject->setVariantProperty(QVariant(123));
       
  1213         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
       
  1214         QVERIFY(ret.isNumber());
       
  1215         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1216         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1217         QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
       
  1218         QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
       
  1219     }
       
  1220 
       
  1221     m_myObject->resetQtFunctionInvoked();
       
  1222     {
       
  1223         m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
       
  1224         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
       
  1225         QVERIFY(ret.isVariant());
       
  1226         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1227         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1228         QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
       
  1229         QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
       
  1230     }
       
  1231 
       
  1232     m_myObject->resetQtFunctionInvoked();
       
  1233     {
       
  1234         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(123)");
       
  1235         QVERIFY(ret.isNumber());
       
  1236         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1237         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1238         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
       
  1239         QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
       
  1240     }
       
  1241 
       
  1242     m_myObject->resetQtFunctionInvoked();
       
  1243     {
       
  1244         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg('ciao')");
       
  1245         QVERIFY(ret.isString());
       
  1246         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1247         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1248         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(QString::fromLatin1("ciao")));
       
  1249         QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, QString::fromLatin1("ciao"))));
       
  1250     }
       
  1251 
       
  1252     m_myObject->resetQtFunctionInvoked();
       
  1253     {
       
  1254         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(null)");
       
  1255         QVERIFY(ret.isUndefined()); // invalid QVariant is converted to Undefined
       
  1256         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1257         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1258         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
       
  1259     }
       
  1260 
       
  1261     m_myObject->resetQtFunctionInvoked();
       
  1262     {
       
  1263         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(undefined)");
       
  1264         QVERIFY(ret.isUndefined());
       
  1265         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1266         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1267         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
       
  1268     }
       
  1269 
       
  1270     m_engine->globalObject().setProperty("fishy", m_engine->newVariant(123));
       
  1271     m_engine->evaluate("myObject.myInvokableWithStringArg(fishy)");
       
  1272 
       
  1273     m_myObject->resetQtFunctionInvoked();
       
  1274     {
       
  1275         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })");
       
  1276         QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
       
  1277         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1278         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1279         QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
       
  1280         QVariantMap vmap = qvariant_cast<QVariantMap>(v);
       
  1281         QCOMPARE(vmap.keys().size(), 2);
       
  1282         QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
       
  1283         QCOMPARE(vmap.value("a"), QVariant(123));
       
  1284         QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
       
  1285         QCOMPARE(vmap.value("b"), QVariant("ciao"));
       
  1286 
       
  1287         QCOMPARE(ret.isObject(), true);
       
  1288         QCOMPARE(ret.property("a").strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  1289         QCOMPARE(ret.property("b").strictlyEquals(QScriptValue(m_engine, "ciao")), true);
       
  1290     }
       
  1291 
       
  1292     m_myObject->resetQtFunctionInvoked();
       
  1293     {
       
  1294         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithListOfIntArg([1, 5])");
       
  1295         QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
       
  1296         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1297         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1298         QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
       
  1299         QList<int> ilst = qvariant_cast<QList<int> >(v);
       
  1300         QCOMPARE(ilst.size(), 2);
       
  1301         QCOMPARE(ilst.at(0), 1);
       
  1302         QCOMPARE(ilst.at(1), 5);
       
  1303 
       
  1304         QCOMPARE(ret.isArray(), true);
       
  1305         QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true);
       
  1306         QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true);
       
  1307     }
       
  1308 
       
  1309     m_myObject->resetQtFunctionInvoked();
       
  1310     {
       
  1311         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(myObject)");
       
  1312         QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
       
  1313         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1314         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1315         QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
       
  1316         QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)m_myObject);
       
  1317 
       
  1318         QCOMPARE(ret.isQObject(), true);
       
  1319         QCOMPARE(qscriptvalue_cast<QObject*>(ret), (QObject *)m_myObject);
       
  1320     }
       
  1321 
       
  1322     m_myObject->resetQtFunctionInvoked();
       
  1323     {
       
  1324         // no implicit conversion from integer to QObject*
       
  1325         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(123)");
       
  1326         QCOMPARE(ret.isError(), true);
       
  1327     }
       
  1328 
       
  1329     m_myObject->resetQtFunctionInvoked();
       
  1330     {
       
  1331         QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithQBrushArg");
       
  1332         QVERIFY(fun.isFunction());
       
  1333         QColor color(10, 20, 30, 40);
       
  1334         // QColor should be converted to a QBrush
       
  1335         QScriptValue ret = fun.call(QScriptValue(), QScriptValueList()
       
  1336                                     << qScriptValueFromValue(m_engine, color));
       
  1337         QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
       
  1338         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1339         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1340         QCOMPARE(v.userType(), int(QMetaType::QBrush));
       
  1341         QCOMPARE(qvariant_cast<QColor>(v), color);
       
  1342 
       
  1343         QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
       
  1344     }
       
  1345 
       
  1346     // private slots should not be part of the QObject binding
       
  1347     QCOMPARE(m_engine->evaluate("myObject.myPrivateSlot").isUndefined(), true);
       
  1348 
       
  1349     // protected slots should be fine
       
  1350     m_myObject->resetQtFunctionInvoked();
       
  1351     m_engine->evaluate("myObject.myProtectedSlot()");
       
  1352     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
       
  1353 
       
  1354     // call with too few arguments
       
  1355     {
       
  1356         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithIntArg()");
       
  1357         QVERIFY(ret.isError());
       
  1358         QCOMPARE(ret.toString(), QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n    myInvokableWithIntArg(int,int)\n    myInvokableWithIntArg(int)"));
       
  1359     }
       
  1360 
       
  1361     // call function where not all types have been registered
       
  1362     m_myObject->resetQtFunctionInvoked();
       
  1363     {
       
  1364         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithBrushStyleArg(0)");
       
  1365         QVERIFY(ret.isError());
       
  1366         QCOMPARE(ret.toString(), QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): argument 1 has unknown type `Qt::BrushStyle' (register the type with qScriptRegisterMetaType())"));
       
  1367         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1368     }
       
  1369 
       
  1370     // call function with incompatible argument type
       
  1371     m_myObject->resetQtFunctionInvoked();
       
  1372     {
       
  1373         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQBrushArg(null)");
       
  1374         QVERIFY(ret.isError());
       
  1375         QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n    myInvokableWithQBrushArg(QBrush)"));
       
  1376         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1377     }
       
  1378 
       
  1379     // ability to call a slot with QObject-based arguments, even if those types haven't been registered
       
  1380     m_myObject->resetQtFunctionInvoked();
       
  1381     {
       
  1382         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithMyQObjectArg(myObject)");
       
  1383         QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
       
  1384         QVERIFY(ret.isUndefined());
       
  1385         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1386         QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
       
  1387     }
       
  1388 
       
  1389     // inability to call a slot returning QObject-based type, when that type hasn't been registered
       
  1390     m_myObject->resetQtFunctionInvoked();
       
  1391     {
       
  1392         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()");
       
  1393         QVERIFY(ret.isError());
       
  1394         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: cannot call myInvokableReturningMyQObject(): unknown return type `MyQObject*' (register the type with qScriptRegisterMetaType())"));
       
  1395     }
       
  1396 
       
  1397     // ability to call a slot returning QObject-based type when that type has been registered
       
  1398     qRegisterMetaType<MyQObject*>("MyQObject*");
       
  1399     m_myObject->resetQtFunctionInvoked();
       
  1400     {
       
  1401         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()");
       
  1402         QCOMPARE(m_myObject->qtFunctionInvoked(), 53);
       
  1403         QVERIFY(ret.isVariant());
       
  1404         QCOMPARE(*reinterpret_cast<MyQObject* const *>(ret.toVariant().constData()), m_myObject);
       
  1405     }
       
  1406 
       
  1407     // ability to call a slot with QObject-based argument, when the argument is const
       
  1408     m_myObject->resetQtFunctionInvoked();
       
  1409     {
       
  1410         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithConstMyQObjectArg(myObject)");
       
  1411         QCOMPARE(m_myObject->qtFunctionInvoked(), 54);
       
  1412         QVERIFY(ret.isUndefined());
       
  1413         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1414         QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
       
  1415     }
       
  1416 
       
  1417     // QScriptValue arguments should be passed on without conversion
       
  1418     m_myObject->resetQtFunctionInvoked();
       
  1419     {
       
  1420         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(123)");
       
  1421         QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
       
  1422         QVERIFY(ret.isNumber());
       
  1423         QCOMPARE(ret.toInt32(), 123);
       
  1424     }
       
  1425     m_myObject->resetQtFunctionInvoked();
       
  1426     {
       
  1427         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg('ciao')");
       
  1428         QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
       
  1429         QVERIFY(ret.isString());
       
  1430         QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
       
  1431     }
       
  1432     m_myObject->resetQtFunctionInvoked();
       
  1433     {
       
  1434         QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(this)");
       
  1435         QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
       
  1436         QVERIFY(ret.isObject());
       
  1437         QVERIFY(ret.strictlyEquals(m_engine->globalObject()));
       
  1438     }
       
  1439 
       
  1440     // the prototype specified by a conversion function should not be "down-graded"
       
  1441     m_myObject->resetQtFunctionInvoked();
       
  1442     {
       
  1443         QScriptValue qobjectProto = m_engine->newObject();
       
  1444         qScriptRegisterMetaType<QObject*>(m_engine, qobjectToScriptValue,
       
  1445                                           qobjectFromScriptValue, qobjectProto);
       
  1446         QScriptValue myQObjectProto = m_engine->newObject();
       
  1447         myQObjectProto.setPrototype(qobjectProto);
       
  1448         qScriptRegisterMetaType<MyQObject*>(m_engine, qobjectToScriptValue,
       
  1449                                           qobjectFromScriptValue, myQObjectProto);
       
  1450         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObjectAsQObject()");
       
  1451         QCOMPARE(m_myObject->qtFunctionInvoked(), 57);
       
  1452         QVERIFY(ret.isQObject());
       
  1453         QVERIFY(ret.prototype().strictlyEquals(myQObjectProto));
       
  1454 
       
  1455         qScriptRegisterMetaType<QObject*>(m_engine, 0, 0, QScriptValue());
       
  1456         qScriptRegisterMetaType<MyQObject*>(m_engine, 0, 0, QScriptValue());
       
  1457     }
       
  1458 
       
  1459     // detect exceptions during argument conversion
       
  1460     m_myObject->resetQtFunctionInvoked();
       
  1461     {
       
  1462         QScriptValue (*dummy)(QScriptEngine *, const QDir &) = 0;
       
  1463         qScriptRegisterMetaType<QDir>(m_engine, dummy, dirFromScript);
       
  1464         {
       
  1465             QVERIFY(!m_engine->hasUncaughtException());
       
  1466             QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({})");
       
  1467             QVERIFY(m_engine->hasUncaughtException());
       
  1468             QVERIFY(ret.isError());
       
  1469             QCOMPARE(ret.toString(), QString::fromLatin1("Error: No path"));
       
  1470             QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1471         }
       
  1472         m_engine->clearExceptions();
       
  1473         {
       
  1474             QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({path:'.'})");
       
  1475             QVERIFY(!m_engine->hasUncaughtException());
       
  1476             QVERIFY(ret.isUndefined());
       
  1477             QCOMPARE(m_myObject->qtFunctionInvoked(), 55);
       
  1478         }
       
  1479     }
       
  1480 
       
  1481     // qscript_call()
       
  1482     {
       
  1483         m_myObject->resetQtFunctionInvoked();
       
  1484         QScriptValue ret = m_engine->evaluate("new myObject(123)");
       
  1485         QVERIFY(ret.isError());
       
  1486         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'myObject' [MyQObject(name = \"\")] is not a constructor."));
       
  1487     }
       
  1488     {
       
  1489         m_myObject->resetQtFunctionInvoked();
       
  1490         QScriptValue ret = m_engine->evaluate("myObject(123)");
       
  1491         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'myObject' [MyQObject(name = \"\")] is not a function."));
       
  1492     }
       
  1493 
       
  1494     // task 233624
       
  1495     {
       
  1496         MyNS::A a;
       
  1497         m_engine->globalObject().setProperty("anObject", m_engine->newQObject(&a));
       
  1498         QScriptValue ret = m_engine->evaluate("anObject.slotTakingScopedEnumArg(1)");
       
  1499         QVERIFY(!ret.isError());
       
  1500         QVERIFY(ret.isNumber());
       
  1501         QCOMPARE(ret.toInt32(), 1);
       
  1502         m_engine->globalObject().setProperty("anObject", QScriptValue());
       
  1503     }
       
  1504 
       
  1505     // virtual slot redeclared in subclass (task 236467)
       
  1506     {
       
  1507         MyOtherQObject moq;
       
  1508         m_engine->globalObject().setProperty("myOtherQObject", m_engine->newQObject(&moq));
       
  1509         moq.resetQtFunctionInvoked();
       
  1510         QScriptValue ret = m_engine->evaluate("myOtherQObject.myVirtualSlot(123)");
       
  1511         QCOMPARE(moq.qtFunctionInvoked(), 59);
       
  1512         QVERIFY(!ret.isError());
       
  1513         QVERIFY(ret.isNumber());
       
  1514         QCOMPARE(ret.toInt32(), 123);
       
  1515     }
       
  1516 }
       
  1517 
       
  1518 void tst_QScriptExtQObject::connectAndDisconnect()
       
  1519 {
       
  1520     // connect(function)
       
  1521     QCOMPARE(m_engine->evaluate("myObject.mySignal.connect(123)").isError(), true);
       
  1522 
       
  1523     m_engine->evaluate("myHandler = function() { global.gotSignal = true; global.signalArgs = arguments; global.slotThisObject = this; }");
       
  1524 
       
  1525     m_myObject->clearConnectedSignal();
       
  1526     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myHandler)").isUndefined());
       
  1527     QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal()));
       
  1528 
       
  1529     m_engine->evaluate("gotSignal = false");
       
  1530     m_engine->evaluate("myObject.mySignal()");
       
  1531     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1532     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
       
  1533     QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->globalObject()));
       
  1534 
       
  1535     m_engine->evaluate("gotSignal = false");
       
  1536     m_myObject->emitMySignal();
       
  1537     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1538     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
       
  1539 
       
  1540     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myHandler)").isUndefined());
       
  1541 
       
  1542     m_engine->evaluate("gotSignal = false");
       
  1543     m_myObject->emitMySignalWithIntArg(123);
       
  1544     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1545     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1546     QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
       
  1547 
       
  1548     m_myObject->clearDisconnectedSignal();
       
  1549     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isUndefined());
       
  1550     QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal()));
       
  1551 
       
  1552     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isError());
       
  1553 
       
  1554     QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
       
  1555     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myHandler)").isUndefined());
       
  1556 
       
  1557     m_engine->evaluate("gotSignal = false");
       
  1558     m_myObject->emitMySignal2(false);
       
  1559     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1560     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1561     QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), false);
       
  1562 
       
  1563     m_engine->evaluate("gotSignal = false");
       
  1564     QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
       
  1565     m_myObject->emitMySignal2(true);
       
  1566     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1567     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1568     QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), true);
       
  1569 
       
  1570     QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myHandler)").isUndefined());
       
  1571 
       
  1572     QVERIFY(m_engine->evaluate("myObject['mySignal2()'].connect(myHandler)").isUndefined());
       
  1573 
       
  1574     m_engine->evaluate("gotSignal = false");
       
  1575     m_myObject->emitMySignal2();
       
  1576     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1577 
       
  1578     QVERIFY(m_engine->evaluate("myObject['mySignal2()'].disconnect(myHandler)").isUndefined());
       
  1579 
       
  1580     // connecting to signal with default args should pick the most generic version (i.e. with all args)
       
  1581     QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.connect(myHandler)").isUndefined());
       
  1582     m_engine->evaluate("gotSignal = false");
       
  1583     m_myObject->emitMySignalWithDefaultArgWithArg(456);
       
  1584     QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
       
  1585     QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
       
  1586     QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 456);
       
  1587 
       
  1588     m_engine->evaluate("gotSignal = false");
       
  1589     m_myObject->emitMySignalWithDefaultArg();
       
  1590     QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
       
  1591     QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
       
  1592     QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 123);
       
  1593 
       
  1594     QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.disconnect(myHandler)").isUndefined());
       
  1595 
       
  1596     m_engine->evaluate("gotSignal = false");
       
  1597     // connecting to overloaded signal should throw an error
       
  1598     {
       
  1599         QScriptValue ret = m_engine->evaluate("myObject.myOverloadedSignal.connect(myHandler)");
       
  1600         QVERIFY(ret.isError());
       
  1601         QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOverloadedSignal(); candidates are\n"
       
  1602                                                      "    myOverloadedSignal(int)\n"
       
  1603                                                      "    myOverloadedSignal(QString)\n"
       
  1604                                                      "Use e.g. object['myOverloadedSignal(QString)'].connect() to connect to a particular overload"));
       
  1605     }
       
  1606     m_myObject->emitMyOverloadedSignal(123);
       
  1607     QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
       
  1608     m_myObject->emitMyOverloadedSignal("ciao");
       
  1609     QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
       
  1610 
       
  1611     m_engine->evaluate("gotSignal = false");
       
  1612     {
       
  1613         QScriptValue ret = m_engine->evaluate("myObject.myOtherOverloadedSignal.connect(myHandler)");
       
  1614         QVERIFY(ret.isError());
       
  1615         QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOtherOverloadedSignal(); candidates are\n"
       
  1616                                                      "    myOtherOverloadedSignal(QString)\n"
       
  1617                                                      "    myOtherOverloadedSignal(int)\n"
       
  1618                                                      "Use e.g. object['myOtherOverloadedSignal(int)'].connect() to connect to a particular overload"));
       
  1619     }
       
  1620     m_myObject->emitMyOtherOverloadedSignal("ciao");
       
  1621     QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
       
  1622     m_myObject->emitMyOtherOverloadedSignal(123);
       
  1623     QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
       
  1624 
       
  1625     // signal with QVariant arg: argument conversion should work
       
  1626     m_myObject->clearConnectedSignal();
       
  1627     QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.connect(myHandler)").isUndefined());
       
  1628     QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignalWithVariantArg(QVariant)));
       
  1629     m_engine->evaluate("gotSignal = false");
       
  1630     m_myObject->emitMySignalWithVariantArg(123);
       
  1631     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1632     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1633     QVERIFY(m_engine->evaluate("signalArgs[0]").isNumber());
       
  1634     QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
       
  1635     QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.disconnect(myHandler)").isUndefined());
       
  1636 
       
  1637     // signal with argument type that's unknown to the meta-type system
       
  1638     m_myObject->clearConnectedSignal();
       
  1639     QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.connect(myHandler)").isUndefined());
       
  1640     QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignalWithScriptEngineArg(QScriptEngine*)));
       
  1641     m_engine->evaluate("gotSignal = false");
       
  1642     QTest::ignoreMessage(QtWarningMsg, "QScriptEngine: Unable to handle unregistered datatype 'QScriptEngine*' when invoking handler of signal MyQObject::mySignalWithScriptEngineArg(QScriptEngine*)");
       
  1643     m_myObject->emitMySignalWithScriptEngineArg(m_engine);
       
  1644     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1645     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1646     QVERIFY(m_engine->evaluate("signalArgs[0]").isUndefined());
       
  1647     QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.disconnect(myHandler)").isUndefined());
       
  1648 
       
  1649     // connect(object, function)
       
  1650     m_engine->evaluate("otherObject = { name:'foo' }");
       
  1651     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
       
  1652     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
       
  1653     m_engine->evaluate("gotSignal = false");
       
  1654     m_myObject->emitMySignal();
       
  1655     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), false);
       
  1656 
       
  1657     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isError());
       
  1658 
       
  1659     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
       
  1660     m_engine->evaluate("gotSignal = false");
       
  1661     m_myObject->emitMySignal();
       
  1662     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1663     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
       
  1664     QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("otherObject")));
       
  1665     QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("foo"));
       
  1666     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
       
  1667 
       
  1668     m_engine->evaluate("yetAnotherObject = { name:'bar', func : function() { } }");
       
  1669     QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(yetAnotherObject, myHandler)").isUndefined());
       
  1670     m_engine->evaluate("gotSignal = false");
       
  1671     m_myObject->emitMySignal2(true);
       
  1672     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1673     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1674     QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("yetAnotherObject")));
       
  1675     QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("bar"));
       
  1676     QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)").isUndefined());
       
  1677 
       
  1678     QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myObject, myHandler)").isUndefined());
       
  1679     m_engine->evaluate("gotSignal = false");
       
  1680     m_myObject->emitMySignal2(true);
       
  1681     QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
       
  1682     QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
       
  1683     QCOMPARE(m_engine->evaluate("slotThisObject").toQObject(), (QObject *)m_myObject);
       
  1684     QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myObject, myHandler)").isUndefined());
       
  1685 
       
  1686     // connect(obj, string)
       
  1687     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(yetAnotherObject, 'func')").isUndefined());
       
  1688     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject, 'mySlot')").isUndefined());
       
  1689     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(yetAnotherObject, 'func')").isUndefined());
       
  1690     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject, 'mySlot')").isUndefined());
       
  1691 
       
  1692     // check that emitting signals from script works
       
  1693 
       
  1694     // no arguments
       
  1695     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
       
  1696     m_myObject->resetQtFunctionInvoked();
       
  1697     QCOMPARE(m_engine->evaluate("myObject.mySignal()").isUndefined(), true);
       
  1698     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1699     QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject.mySlot)").isUndefined());
       
  1700 
       
  1701     // one argument
       
  1702     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)").isUndefined());
       
  1703     m_myObject->resetQtFunctionInvoked();
       
  1704     QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
       
  1705     QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
       
  1706     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1707     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1708     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)").isUndefined());
       
  1709 
       
  1710     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)").isUndefined());
       
  1711     m_myObject->resetQtFunctionInvoked();
       
  1712     QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
       
  1713     QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
       
  1714     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1715     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
       
  1716     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)").isUndefined());
       
  1717 
       
  1718     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)").isUndefined());
       
  1719     m_myObject->resetQtFunctionInvoked();
       
  1720     QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
       
  1721     QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
       
  1722     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1723     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
       
  1724     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)").isUndefined());
       
  1725 
       
  1726     // connecting to overloaded slot
       
  1727     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)").isUndefined());
       
  1728     m_myObject->resetQtFunctionInvoked();
       
  1729     QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
       
  1730     QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
       
  1731     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1732     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1733     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)").isUndefined());
       
  1734 
       
  1735     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])").isUndefined());
       
  1736     m_myObject->resetQtFunctionInvoked();
       
  1737     QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(456)").isUndefined(), true);
       
  1738     QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
       
  1739     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1740     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
       
  1741     QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])").isUndefined());
       
  1742 
       
  1743     // when the wrapper dies, the connection stays alive
       
  1744     QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
       
  1745     m_myObject->resetQtFunctionInvoked();
       
  1746     m_myObject->emitMySignal();
       
  1747     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1748     m_engine->evaluate("myObject = null");
       
  1749     m_engine->collectGarbage();
       
  1750     m_myObject->resetQtFunctionInvoked();
       
  1751     m_myObject->emitMySignal();
       
  1752     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1753 }
       
  1754 
       
  1755 void tst_QScriptExtQObject::connectAndDisconnectWithBadArgs()
       
  1756 {
       
  1757     {
       
  1758         QScriptValue ret = m_engine->evaluate("(function() { }).connect()");
       
  1759         QVERIFY(ret.isError());
       
  1760         QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
       
  1761     }
       
  1762     {
       
  1763         QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect;  o.connect()");
       
  1764         QVERIFY(ret.isError());
       
  1765         QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
       
  1766     }
       
  1767 
       
  1768     {
       
  1769         QScriptValue ret = m_engine->evaluate("(function() { }).connect(123)");
       
  1770         QVERIFY(ret.isError());
       
  1771         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
       
  1772     }
       
  1773     {
       
  1774         QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect;  o.connect(123)");
       
  1775         QVERIFY(ret.isError());
       
  1776         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
       
  1777     }
       
  1778 
       
  1779     {
       
  1780         QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(123)");
       
  1781         QVERIFY(ret.isError());
       
  1782         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
       
  1783     }
       
  1784     {
       
  1785         QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(function() { })");
       
  1786         QVERIFY(ret.isError());
       
  1787         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
       
  1788     }
       
  1789 
       
  1790     {
       
  1791         QScriptValue ret = m_engine->evaluate("myObject.mySignal.connect(123)");
       
  1792         QVERIFY(ret.isError());
       
  1793         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: target is not a function"));
       
  1794     }
       
  1795 
       
  1796     {
       
  1797         QScriptValue ret = m_engine->evaluate("(function() { }).disconnect()");
       
  1798         QVERIFY(ret.isError());
       
  1799         QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
       
  1800     }
       
  1801     {
       
  1802         QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect;  o.disconnect()");
       
  1803         QVERIFY(ret.isError());
       
  1804         QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
       
  1805     }
       
  1806 
       
  1807     {
       
  1808         QScriptValue ret = m_engine->evaluate("(function() { }).disconnect(123)");
       
  1809         QVERIFY(ret.isError());
       
  1810         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
       
  1811     }
       
  1812     {
       
  1813         QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect;  o.disconnect(123)");
       
  1814         QVERIFY(ret.isError());
       
  1815         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
       
  1816     }
       
  1817 
       
  1818     {
       
  1819         QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(123)");
       
  1820         QVERIFY(ret.isError());
       
  1821         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
       
  1822     }
       
  1823     {
       
  1824         QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(function() { })");
       
  1825         QVERIFY(ret.isError());
       
  1826         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
       
  1827     }
       
  1828 
       
  1829     {
       
  1830         QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(123)");
       
  1831         QVERIFY(ret.isError());
       
  1832         QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: target is not a function"));
       
  1833     }
       
  1834 
       
  1835     {
       
  1836         QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(function() { })");
       
  1837         QVERIFY(ret.isError());
       
  1838         QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: failed to disconnect from MyQObject::mySignal()"));
       
  1839     }
       
  1840 }
       
  1841 
       
  1842 void tst_QScriptExtQObject::cppConnectAndDisconnect()
       
  1843 {
       
  1844     QScriptEngine eng;
       
  1845     QLineEdit edit;
       
  1846     QLineEdit edit2;
       
  1847     QScriptValue fun = eng.evaluate("function fun(text) { signalObject = this; signalArg = text; }; fun");
       
  1848     QVERIFY(fun.isFunction());
       
  1849     for (int z = 0; z < 2; ++z) {
       
  1850         QScriptValue receiver;
       
  1851         if (z == 0)
       
  1852             receiver = QScriptValue();
       
  1853         else
       
  1854             receiver = eng.newObject();
       
  1855         for (int y = 0; y < 2; ++y) {
       
  1856             QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1857             QVERIFY(qScriptConnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1858             // check signal emission
       
  1859             for (int x = 0; x < 4; ++x) {
       
  1860                 QLineEdit *ed = (x < 2) ? &edit : &edit2;
       
  1861                 ed->setText((x % 2) ? "foo" : "bar");
       
  1862                 {
       
  1863                     QScriptValue ret = eng.globalObject().property("signalObject");
       
  1864                     if (receiver.isObject())
       
  1865                         QVERIFY(ret.strictlyEquals(receiver));
       
  1866                     else
       
  1867                         QVERIFY(ret.strictlyEquals(eng.globalObject()));
       
  1868                 }
       
  1869                 {
       
  1870                     QScriptValue ret = eng.globalObject().property("signalArg");
       
  1871                     QVERIFY(ret.isString());
       
  1872                     QCOMPARE(ret.toString(), ed->text());
       
  1873                 }
       
  1874                 eng.collectGarbage();
       
  1875             }
       
  1876 
       
  1877             // check disconnect
       
  1878             QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1879             eng.globalObject().setProperty("signalObject", QScriptValue());
       
  1880             eng.globalObject().setProperty("signalArg", QScriptValue());
       
  1881             edit.setText("something else");
       
  1882             QVERIFY(!eng.globalObject().property("signalObject").isValid());
       
  1883             QVERIFY(!eng.globalObject().property("signalArg").isValid());
       
  1884             QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1885 
       
  1886             // other object's connection should remain
       
  1887             edit2.setText(edit.text());
       
  1888             {
       
  1889                 QScriptValue ret = eng.globalObject().property("signalObject");
       
  1890                 if (receiver.isObject())
       
  1891                     QVERIFY(ret.strictlyEquals(receiver));
       
  1892                 else
       
  1893                     QVERIFY(ret.strictlyEquals(eng.globalObject()));
       
  1894             }
       
  1895             {
       
  1896                 QScriptValue ret = eng.globalObject().property("signalArg");
       
  1897                 QVERIFY(ret.isString());
       
  1898                 QCOMPARE(ret.toString(), edit2.text());
       
  1899             }
       
  1900 
       
  1901             // disconnect other object too
       
  1902             QVERIFY(qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1903             eng.globalObject().setProperty("signalObject", QScriptValue());
       
  1904             eng.globalObject().setProperty("signalArg", QScriptValue());
       
  1905             edit2.setText("even more different");
       
  1906             QVERIFY(!eng.globalObject().property("signalObject").isValid());
       
  1907             QVERIFY(!eng.globalObject().property("signalArg").isValid());
       
  1908             QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
       
  1909         }
       
  1910     }
       
  1911 
       
  1912     // make sure we don't crash when engine is deleted
       
  1913     {
       
  1914         QScriptEngine *eng2 = new QScriptEngine;
       
  1915         QScriptValue fun2 = eng2->evaluate("(function(text) { signalObject = this; signalArg = text; })");
       
  1916         QVERIFY(fun2.isFunction());
       
  1917         QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
       
  1918         delete eng2;
       
  1919         edit.setText("ciao");
       
  1920         QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
       
  1921     }
       
  1922 
       
  1923     // mixing script-side and C++-side connect
       
  1924     {
       
  1925         eng.globalObject().setProperty("edit", eng.newQObject(&edit));
       
  1926         QVERIFY(eng.evaluate("edit.textChanged.connect(fun)").isUndefined());
       
  1927         QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
       
  1928 
       
  1929         QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
       
  1930         QVERIFY(eng.evaluate("edit.textChanged.disconnect(fun)").isUndefined());
       
  1931     }
       
  1932 
       
  1933     // signalHandlerException()
       
  1934     {
       
  1935         connect(&eng, SIGNAL(signalHandlerException(QScriptValue)),
       
  1936                 this, SLOT(onSignalHandlerException(QScriptValue)));
       
  1937 
       
  1938         eng.globalObject().setProperty("edit", eng.newQObject(&edit));
       
  1939         QScriptValue fun = eng.evaluate("(function() { nonExistingFunction(); })");
       
  1940         QVERIFY(fun.isFunction());
       
  1941         QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
       
  1942 
       
  1943         m_signalHandlerException = QScriptValue();
       
  1944         QScriptValue ret = eng.evaluate("edit.text = 'trigger a signal handler exception from script'");
       
  1945         QVERIFY(ret.isError());
       
  1946         QVERIFY(m_signalHandlerException.strictlyEquals(ret));
       
  1947 
       
  1948         m_signalHandlerException = QScriptValue();
       
  1949         edit.setText("trigger a signal handler exception from C++");
       
  1950         QVERIFY(m_signalHandlerException.isError());
       
  1951 
       
  1952         QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
       
  1953 
       
  1954         m_signalHandlerException = QScriptValue();
       
  1955         eng.evaluate("edit.text = 'no more exception from script'");
       
  1956         QVERIFY(!m_signalHandlerException.isValid());
       
  1957         edit.setText("no more exception from C++");
       
  1958         QVERIFY(!m_signalHandlerException.isValid());
       
  1959 
       
  1960         disconnect(&eng, SIGNAL(signalHandlerException(QScriptValue)),
       
  1961                    this, SLOT(onSignalHandlerException(QScriptValue)));
       
  1962     }
       
  1963 
       
  1964     // check that connectNotify() and disconnectNotify() are called (task 232987)
       
  1965     {
       
  1966         m_myObject->clearConnectedSignal();
       
  1967         QVERIFY(qScriptConnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
       
  1968         QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal()));
       
  1969 
       
  1970         m_myObject->clearDisconnectedSignal();
       
  1971         QVERIFY(qScriptDisconnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
       
  1972         QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal()));
       
  1973     }
       
  1974 
       
  1975     // bad args
       
  1976     QVERIFY(!qScriptConnect(0, SIGNAL(foo()), QScriptValue(), fun));
       
  1977     QVERIFY(!qScriptConnect(&edit, 0, QScriptValue(), fun));
       
  1978     QVERIFY(!qScriptConnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
       
  1979     QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
       
  1980     QVERIFY(!qScriptDisconnect(0, SIGNAL(foo()), QScriptValue(), fun));
       
  1981     QVERIFY(!qScriptDisconnect(&edit, 0, QScriptValue(), fun));
       
  1982     QVERIFY(!qScriptDisconnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
       
  1983     QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
       
  1984     {
       
  1985         QScriptEngine eng2;
       
  1986         QScriptValue receiverInDifferentEngine = eng2.newObject();
       
  1987         QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
       
  1988         QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
       
  1989     }
       
  1990 }
       
  1991 
       
  1992 void tst_QScriptExtQObject::classEnums()
       
  1993 {
       
  1994     QScriptValue myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
       
  1995     m_engine->globalObject().setProperty("MyQObject", myClass);
       
  1996 
       
  1997     QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.FooPolicy").toInt32()),
       
  1998              MyQObject::FooPolicy);
       
  1999     QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BarPolicy").toInt32()),
       
  2000              MyQObject::BarPolicy);
       
  2001     QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BazPolicy").toInt32()),
       
  2002              MyQObject::BazPolicy);
       
  2003 
       
  2004     QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.FooStrategy").toInt32()),
       
  2005              MyQObject::FooStrategy);
       
  2006     QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BarStrategy").toInt32()),
       
  2007              MyQObject::BarStrategy);
       
  2008     QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BazStrategy").toInt32()),
       
  2009              MyQObject::BazStrategy);
       
  2010 
       
  2011     QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.NoAbility").toInt32()),
       
  2012              MyQObject::NoAbility);
       
  2013     QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.FooAbility").toInt32()),
       
  2014              MyQObject::FooAbility);
       
  2015     QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BarAbility").toInt32()),
       
  2016              MyQObject::BarAbility);
       
  2017     QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BazAbility").toInt32()),
       
  2018              MyQObject::BazAbility);
       
  2019     QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.AllAbility").toInt32()),
       
  2020              MyQObject::AllAbility);
       
  2021 
       
  2022     QScriptValue::PropertyFlags expectedEnumFlags = QScriptValue::ReadOnly | QScriptValue::Undeletable;
       
  2023     QCOMPARE(myClass.propertyFlags("FooPolicy"), expectedEnumFlags);
       
  2024     QCOMPARE(myClass.propertyFlags("BarPolicy"), expectedEnumFlags);
       
  2025     QCOMPARE(myClass.propertyFlags("BazPolicy"), expectedEnumFlags);
       
  2026 
       
  2027     // enums from Qt are inherited through prototype
       
  2028     QCOMPARE(static_cast<Qt::FocusPolicy>(m_engine->evaluate("MyQObject.StrongFocus").toInt32()),
       
  2029              Qt::StrongFocus);
       
  2030     QCOMPARE(static_cast<Qt::Key>(m_engine->evaluate("MyQObject.Key_Left").toInt32()),
       
  2031              Qt::Key_Left);
       
  2032 
       
  2033     QCOMPARE(m_engine->evaluate("MyQObject.className()").toString(), QLatin1String("MyQObject"));
       
  2034 
       
  2035     qRegisterMetaType<MyQObject::Policy>("Policy");
       
  2036 
       
  2037     m_myObject->resetQtFunctionInvoked();
       
  2038     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
       
  2039     QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
       
  2040     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  2041     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
       
  2042 
       
  2043     m_myObject->resetQtFunctionInvoked();
       
  2044     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg('BarPolicy')").isUndefined(), true);
       
  2045     QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
       
  2046     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  2047     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BarPolicy));
       
  2048 
       
  2049     m_myObject->resetQtFunctionInvoked();
       
  2050     QVERIFY(m_engine->evaluate("myObject.myInvokableWithEnumArg('NoSuchPolicy')").isError());
       
  2051     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  2052 
       
  2053     m_myObject->resetQtFunctionInvoked();
       
  2054     QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
       
  2055     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
       
  2056     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  2057     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
       
  2058 
       
  2059     m_myObject->resetQtFunctionInvoked();
       
  2060     {
       
  2061         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningEnum()");
       
  2062         QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
       
  2063         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  2064         QCOMPARE(ret.isVariant(), true);
       
  2065     }
       
  2066     m_myObject->resetQtFunctionInvoked();
       
  2067     {
       
  2068         QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQualifiedEnum()");
       
  2069         QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
       
  2070         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  2071         QCOMPARE(ret.isNumber(), true);
       
  2072     }
       
  2073 
       
  2074     // enum properties are not deletable or writable
       
  2075     QVERIFY(!m_engine->evaluate("delete MyQObject.BazPolicy").toBool());
       
  2076     myClass.setProperty("BazPolicy", QScriptValue());
       
  2077     QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
       
  2078              MyQObject::BazPolicy);
       
  2079     myClass.setProperty("BazPolicy", MyQObject::FooPolicy);
       
  2080     QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
       
  2081              MyQObject::BazPolicy);
       
  2082 }
       
  2083 
       
  2084 QT_BEGIN_NAMESPACE
       
  2085 Q_SCRIPT_DECLARE_QMETAOBJECT(MyQObject, QObject*)
       
  2086 Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
       
  2087 QT_END_NAMESPACE
       
  2088 
       
  2089 class ConstructorTest : public QObject
       
  2090 {
       
  2091     Q_OBJECT
       
  2092 public:
       
  2093     Q_INVOKABLE ConstructorTest(QObject *parent)
       
  2094         : QObject(parent)
       
  2095     {
       
  2096         setProperty("ctorIndex", 0);
       
  2097     }
       
  2098     Q_INVOKABLE ConstructorTest(int arg, QObject *parent = 0)
       
  2099         : QObject(parent)
       
  2100     {
       
  2101         setProperty("ctorIndex", 1);
       
  2102         setProperty("arg", arg);
       
  2103     }
       
  2104     Q_INVOKABLE ConstructorTest(const QString &arg, QObject *parent = 0)
       
  2105         : QObject(parent)
       
  2106     {
       
  2107         setProperty("ctorIndex", 2);
       
  2108         setProperty("arg", arg);
       
  2109     }
       
  2110     Q_INVOKABLE ConstructorTest(int arg, const QString &arg2, QObject *parent = 0)
       
  2111         : QObject(parent)
       
  2112     {
       
  2113         setProperty("ctorIndex", 3);
       
  2114         setProperty("arg", arg);
       
  2115         setProperty("arg2", arg2);
       
  2116     }
       
  2117     Q_INVOKABLE ConstructorTest(const QBrush &arg, QObject *parent = 0)
       
  2118         : QObject(parent)
       
  2119     {
       
  2120         setProperty("ctorIndex", 4);
       
  2121         setProperty("arg", arg);
       
  2122     }
       
  2123 };
       
  2124 
       
  2125 void tst_QScriptExtQObject::classConstructor()
       
  2126 {
       
  2127     QScriptValue myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
       
  2128     m_engine->globalObject().setProperty("MyQObject", myClass);
       
  2129 
       
  2130     QScriptValue myObj = m_engine->evaluate("myObj = MyQObject()");
       
  2131     QObject *qobj = myObj.toQObject();
       
  2132     QVERIFY(qobj != 0);
       
  2133     QCOMPARE(qobj->metaObject()->className(), "MyQObject");
       
  2134     QCOMPARE(qobj->parent(), (QObject *)0);
       
  2135 
       
  2136     QScriptValue qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
       
  2137     m_engine->globalObject().setProperty("QObject", qobjectClass);
       
  2138 
       
  2139     QScriptValue otherObj = m_engine->evaluate("otherObj = QObject(myObj)");
       
  2140     QObject *qqobj = otherObj.toQObject();
       
  2141     QVERIFY(qqobj != 0);
       
  2142     QCOMPARE(qqobj->metaObject()->className(), "QObject");
       
  2143     QCOMPARE(qqobj->parent(), qobj);
       
  2144 
       
  2145     delete qobj;
       
  2146 
       
  2147     // Q_INVOKABLE constructors
       
  2148     {
       
  2149         QScriptValue klazz = m_engine->newQMetaObject(&ConstructorTest::staticMetaObject);
       
  2150         {
       
  2151             QScriptValue obj = klazz.construct();
       
  2152             QVERIFY(obj.isError());
       
  2153             QCOMPARE(obj.toString(), QString::fromLatin1("SyntaxError: too few arguments in call to ConstructorTest(); candidates are\n"
       
  2154                                                          "    ConstructorTest(QBrush)\n"
       
  2155                                                          "    ConstructorTest(QBrush,QObject*)\n"
       
  2156                                                          "    ConstructorTest(int,QString)\n"
       
  2157                                                          "    ConstructorTest(int,QString,QObject*)\n"
       
  2158                                                          "    ConstructorTest(QString)\n"
       
  2159                                                          "    ConstructorTest(QString,QObject*)\n"
       
  2160                                                          "    ConstructorTest(int)\n"
       
  2161                                                          "    ConstructorTest(int,QObject*)\n"
       
  2162                                                          "    ConstructorTest(QObject*)"));
       
  2163         }
       
  2164         {
       
  2165             QObject objobj;
       
  2166             QScriptValue arg = m_engine->newQObject(&objobj);
       
  2167             QScriptValue obj = klazz.construct(QScriptValueList() << arg);
       
  2168             QVERIFY(!obj.isError());
       
  2169             QVERIFY(obj.instanceOf(klazz));
       
  2170             QVERIFY(obj.property("ctorIndex").isNumber());
       
  2171             QCOMPARE(obj.property("ctorIndex").toInt32(), 0);
       
  2172         }
       
  2173         {
       
  2174             int arg = 123;
       
  2175             QScriptValue obj = klazz.construct(QScriptValueList() << arg);
       
  2176             QVERIFY(!obj.isError());
       
  2177             QVERIFY(obj.instanceOf(klazz));
       
  2178             QVERIFY(obj.property("ctorIndex").isNumber());
       
  2179             QCOMPARE(obj.property("ctorIndex").toInt32(), 1);
       
  2180             QVERIFY(obj.property("arg").isNumber());
       
  2181             QCOMPARE(obj.property("arg").toInt32(), arg);
       
  2182         }
       
  2183         {
       
  2184             QString arg = "foo";
       
  2185             QScriptValue obj = klazz.construct(QScriptValueList() << arg);
       
  2186             QVERIFY(!obj.isError());
       
  2187             QVERIFY(obj.instanceOf(klazz));
       
  2188             QVERIFY(obj.property("ctorIndex").isNumber());
       
  2189             QCOMPARE(obj.property("ctorIndex").toInt32(), 2);
       
  2190             QVERIFY(obj.property("arg").isString());
       
  2191             QCOMPARE(obj.property("arg").toString(), arg);
       
  2192         }
       
  2193         {
       
  2194             int arg = 123;
       
  2195             QString arg2 = "foo";
       
  2196             QScriptValue obj = klazz.construct(QScriptValueList() << arg << arg2);
       
  2197             QVERIFY(!obj.isError());
       
  2198             QVERIFY(obj.instanceOf(klazz));
       
  2199             QVERIFY(obj.property("ctorIndex").isNumber());
       
  2200             QCOMPARE(obj.property("ctorIndex").toInt32(), 3);
       
  2201             QVERIFY(obj.property("arg").isNumber());
       
  2202             QCOMPARE(obj.property("arg").toInt32(), arg);
       
  2203             QVERIFY(obj.property("arg2").isString());
       
  2204             QCOMPARE(obj.property("arg2").toString(), arg2);
       
  2205         }
       
  2206         {
       
  2207             QBrush arg(Qt::red);
       
  2208             QScriptValue obj = klazz.construct(QScriptValueList() << qScriptValueFromValue(m_engine, arg));
       
  2209             QVERIFY(!obj.isError());
       
  2210             QVERIFY(obj.instanceOf(klazz));
       
  2211             QVERIFY(obj.property("ctorIndex").isNumber());
       
  2212             QCOMPARE(obj.property("ctorIndex").toInt32(), 4);
       
  2213             QVERIFY(obj.property("arg").isVariant());
       
  2214             QCOMPARE(qvariant_cast<QBrush>(obj.property("arg").toVariant()), arg);
       
  2215         }
       
  2216         {
       
  2217             QDir arg;
       
  2218             QScriptValue obj = klazz.construct(QScriptValueList()
       
  2219                                                << qScriptValueFromValue(m_engine, arg));
       
  2220             QVERIFY(obj.isError());
       
  2221             QCOMPARE(obj.toString(), QString::fromLatin1("TypeError: ambiguous call of overloaded function ConstructorTest(); candidates were\n"
       
  2222                                                          "    ConstructorTest(int)\n"
       
  2223                                                          "    ConstructorTest(QString)"));
       
  2224         }
       
  2225     }
       
  2226 }
       
  2227 
       
  2228 void tst_QScriptExtQObject::overrideInvokable()
       
  2229 {
       
  2230     m_myObject->resetQtFunctionInvoked();
       
  2231     m_engine->evaluate("myObject.myInvokable()");
       
  2232     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  2233 
       
  2234     m_myObject->resetQtFunctionInvoked();
       
  2235     m_engine->evaluate("myObject.myInvokable = function() { global.a = 123; }");
       
  2236     m_engine->evaluate("myObject.myInvokable()");
       
  2237     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  2238     QCOMPARE(m_engine->evaluate("global.a").toNumber(), 123.0);
       
  2239 
       
  2240     m_engine->evaluate("myObject.myInvokable = function() { global.a = 456; }");
       
  2241     m_engine->evaluate("myObject.myInvokable()");
       
  2242     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  2243     QCOMPARE(m_engine->evaluate("global.a").toNumber(), 456.0);
       
  2244 
       
  2245     m_engine->evaluate("delete myObject.myInvokable");
       
  2246     m_engine->evaluate("myObject.myInvokable()");
       
  2247     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  2248 
       
  2249     m_myObject->resetQtFunctionInvoked();
       
  2250     m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg");
       
  2251     m_engine->evaluate("myObject.myInvokable(123)");
       
  2252     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  2253 
       
  2254     m_engine->evaluate("delete myObject.myInvokable");
       
  2255     m_myObject->resetQtFunctionInvoked();
       
  2256     // this form (with the '()') is read-only
       
  2257     m_engine->evaluate("myObject['myInvokable()'] = function() { global.a = 123; }");
       
  2258     m_engine->evaluate("myObject.myInvokable()");
       
  2259     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  2260 }
       
  2261 
       
  2262 void tst_QScriptExtQObject::transferInvokable()
       
  2263 {
       
  2264     m_myObject->resetQtFunctionInvoked();
       
  2265     m_engine->evaluate("myObject.foozball = myObject.myInvokable");
       
  2266     m_engine->evaluate("myObject.foozball()");
       
  2267     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  2268     m_myObject->resetQtFunctionInvoked();
       
  2269     m_engine->evaluate("myObject.foozball = myObject.myInvokableWithIntArg");
       
  2270     m_engine->evaluate("myObject.foozball(123)");
       
  2271     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  2272     m_myObject->resetQtFunctionInvoked();
       
  2273     m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg");
       
  2274     m_engine->evaluate("myObject.myInvokable(123)");
       
  2275     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  2276 
       
  2277     MyOtherQObject other;
       
  2278     m_engine->globalObject().setProperty(
       
  2279         "myOtherObject", m_engine->newQObject(&other));
       
  2280     m_engine->evaluate("myOtherObject.foo = myObject.foozball");
       
  2281     other.resetQtFunctionInvoked();
       
  2282     m_engine->evaluate("myOtherObject.foo(456)");
       
  2283     QCOMPARE(other.qtFunctionInvoked(), 1);
       
  2284 }
       
  2285 
       
  2286 void tst_QScriptExtQObject::findChild()
       
  2287 {
       
  2288     QObject *child = new QObject(m_myObject);
       
  2289     child->setObjectName(QLatin1String("myChildObject"));
       
  2290 
       
  2291     {
       
  2292         QScriptValue result = m_engine->evaluate("myObject.findChild('noSuchChild')");
       
  2293         QCOMPARE(result.isNull(), true);
       
  2294     }
       
  2295 
       
  2296     {
       
  2297         QScriptValue result = m_engine->evaluate("myObject.findChild('myChildObject')");
       
  2298         QCOMPARE(result.isQObject(), true);
       
  2299         QCOMPARE(result.toQObject(), child);
       
  2300     }
       
  2301 
       
  2302     delete child;
       
  2303 }
       
  2304 
       
  2305 void tst_QScriptExtQObject::findChildren()
       
  2306 {
       
  2307     QObject *child = new QObject(m_myObject);
       
  2308     child->setObjectName(QLatin1String("myChildObject"));
       
  2309 
       
  2310     {
       
  2311         QScriptValue result = m_engine->evaluate("myObject.findChildren('noSuchChild')");
       
  2312         QCOMPARE(result.isArray(), true);
       
  2313         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 0.0);
       
  2314     }
       
  2315 
       
  2316     {
       
  2317         QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
       
  2318         QCOMPARE(result.isArray(), true);
       
  2319         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
       
  2320         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
       
  2321     }
       
  2322 
       
  2323     QObject *namelessChild = new QObject(m_myObject);
       
  2324 
       
  2325     {
       
  2326         QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
       
  2327         QCOMPARE(result.isArray(), true);
       
  2328         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
       
  2329         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
       
  2330     }
       
  2331 
       
  2332     QObject *anotherChild = new QObject(m_myObject);
       
  2333     anotherChild->setObjectName(QLatin1String("anotherChildObject"));
       
  2334 
       
  2335     {
       
  2336         QScriptValue result = m_engine->evaluate("myObject.findChildren('anotherChildObject')");
       
  2337         QCOMPARE(result.isArray(), true);
       
  2338         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
       
  2339         QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
       
  2340     }
       
  2341 
       
  2342     anotherChild->setObjectName(QLatin1String("myChildObject"));
       
  2343     {
       
  2344         QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')");
       
  2345         QCOMPARE(result.isArray(), true);
       
  2346         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0);
       
  2347         QObject *o1 = result.property(QLatin1String("0")).toQObject();
       
  2348         QObject *o2 = result.property(QLatin1String("1")).toQObject();
       
  2349         if (o1 != child) {
       
  2350             QCOMPARE(o1, anotherChild);
       
  2351             QCOMPARE(o2, child);
       
  2352         } else {
       
  2353             QCOMPARE(o1, child);
       
  2354             QCOMPARE(o2, anotherChild);
       
  2355         }
       
  2356     }
       
  2357 
       
  2358     // find all
       
  2359     {
       
  2360         QScriptValue result = m_engine->evaluate("myObject.findChildren()");
       
  2361         QVERIFY(result.isArray());
       
  2362         int count = 3;
       
  2363         QCOMPARE(result.property("length").toInt32(), count);
       
  2364         for (int i = 0; i < 3; ++i) {
       
  2365             QObject *o = result.property(i).toQObject();
       
  2366             if (o == namelessChild || o == child || o == anotherChild)
       
  2367                 --count;
       
  2368         }
       
  2369         QVERIFY(count == 0);
       
  2370     }
       
  2371 
       
  2372     // matchall regexp
       
  2373     {
       
  2374         QScriptValue result = m_engine->evaluate("myObject.findChildren(/.*/)");
       
  2375         QVERIFY(result.isArray());
       
  2376         int count = 3;
       
  2377         QCOMPARE(result.property("length").toInt32(), count);
       
  2378         for (int i = 0; i < 3; ++i) {
       
  2379             QObject *o = result.property(i).toQObject();
       
  2380             if (o == namelessChild || o == child || o == anotherChild)
       
  2381                 --count;
       
  2382         }
       
  2383         QVERIFY(count == 0);
       
  2384     }
       
  2385 
       
  2386     // matchall regexp my*
       
  2387     {
       
  2388         QScriptValue result = m_engine->evaluate("myObject.findChildren(new RegExp(\"^my.*\"))");
       
  2389         QCOMPARE(result.isArray(), true);
       
  2390         QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0);
       
  2391         QObject *o1 = result.property(QLatin1String("0")).toQObject();
       
  2392         QObject *o2 = result.property(QLatin1String("1")).toQObject();
       
  2393         if (o1 != child) {
       
  2394             QCOMPARE(o1, anotherChild);
       
  2395             QCOMPARE(o2, child);
       
  2396         } else {
       
  2397             QCOMPARE(o1, child);
       
  2398             QCOMPARE(o2, anotherChild);
       
  2399         }
       
  2400     }
       
  2401     delete anotherChild;
       
  2402     delete namelessChild;
       
  2403     delete child;
       
  2404 }
       
  2405 
       
  2406 void tst_QScriptExtQObject::overloadedSlots()
       
  2407 {
       
  2408     // should pick myOverloadedSlot(double)
       
  2409     m_myObject->resetQtFunctionInvoked();
       
  2410     m_engine->evaluate("myObject.myOverloadedSlot(10)");
       
  2411     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
       
  2412 
       
  2413     // should pick myOverloadedSlot(double)
       
  2414     m_myObject->resetQtFunctionInvoked();
       
  2415     m_engine->evaluate("myObject.myOverloadedSlot(10.0)");
       
  2416     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
       
  2417 
       
  2418     // should pick myOverloadedSlot(QString)
       
  2419     m_myObject->resetQtFunctionInvoked();
       
  2420     m_engine->evaluate("myObject.myOverloadedSlot('10')");
       
  2421     QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
       
  2422 
       
  2423     // should pick myOverloadedSlot(bool)
       
  2424     m_myObject->resetQtFunctionInvoked();
       
  2425     m_engine->evaluate("myObject.myOverloadedSlot(true)");
       
  2426     QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
       
  2427 
       
  2428     // should pick myOverloadedSlot(QDateTime)
       
  2429     m_myObject->resetQtFunctionInvoked();
       
  2430     m_engine->evaluate("myObject.myOverloadedSlot(new Date())");
       
  2431     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
       
  2432 
       
  2433     // should pick myOverloadedSlot(QRegExp)
       
  2434     m_myObject->resetQtFunctionInvoked();
       
  2435     m_engine->evaluate("myObject.myOverloadedSlot(new RegExp())");
       
  2436     QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
       
  2437 
       
  2438     // should pick myOverloadedSlot(QVariant)
       
  2439     m_myObject->resetQtFunctionInvoked();
       
  2440     QScriptValue f = m_engine->evaluate("myObject.myOverloadedSlot");
       
  2441     f.call(QScriptValue(), QScriptValueList() << m_engine->newVariant(QVariant("ciao")));
       
  2442     QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
       
  2443 
       
  2444     // should pick myOverloadedSlot(QObject*)
       
  2445     m_myObject->resetQtFunctionInvoked();
       
  2446     m_engine->evaluate("myObject.myOverloadedSlot(myObject)");
       
  2447     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
       
  2448 
       
  2449     // should pick myOverloadedSlot(QObject*)
       
  2450     m_myObject->resetQtFunctionInvoked();
       
  2451     m_engine->evaluate("myObject.myOverloadedSlot(null)");
       
  2452     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
       
  2453 
       
  2454     // should pick myOverloadedSlot(QStringList)
       
  2455     m_myObject->resetQtFunctionInvoked();
       
  2456     m_engine->evaluate("myObject.myOverloadedSlot(['hello'])");
       
  2457     QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
       
  2458 }
       
  2459 
       
  2460 void tst_QScriptExtQObject::enumerate_data()
       
  2461 {
       
  2462     QTest::addColumn<int>("wrapOptions");
       
  2463     QTest::addColumn<QStringList>("expectedNames");
       
  2464 
       
  2465     QTest::newRow( "enumerate all" )
       
  2466         << 0
       
  2467         << (QStringList()
       
  2468             // meta-object-defined properties:
       
  2469             //   inherited
       
  2470             << "objectName"
       
  2471             //   non-inherited
       
  2472             << "p1" << "p2" << "p4" << "p6"
       
  2473             // dynamic properties
       
  2474             << "dp1" << "dp2" << "dp3"
       
  2475             // inherited slots
       
  2476             << "destroyed(QObject*)" << "destroyed()"
       
  2477             << "deleteLater()"
       
  2478             // not included because it's private:
       
  2479             // << "_q_reregisterTimers(void*)"
       
  2480             // signals
       
  2481             << "mySignal()"
       
  2482             // slots
       
  2483             << "mySlot()" << "myOtherSlot()");
       
  2484 
       
  2485     QTest::newRow( "don't enumerate inherited properties" )
       
  2486         << int(QScriptEngine::ExcludeSuperClassProperties)
       
  2487         << (QStringList()
       
  2488             // meta-object-defined properties:
       
  2489             //   non-inherited
       
  2490             << "p1" << "p2" << "p4" << "p6"
       
  2491             // dynamic properties
       
  2492             << "dp1" << "dp2" << "dp3"
       
  2493             // inherited slots
       
  2494             << "destroyed(QObject*)" << "destroyed()"
       
  2495             << "deleteLater()"
       
  2496             // not included because it's private:
       
  2497             // << "_q_reregisterTimers(void*)"
       
  2498             // signals
       
  2499             << "mySignal()"
       
  2500             // slots
       
  2501             << "mySlot()" << "myOtherSlot()");
       
  2502 
       
  2503     QTest::newRow( "don't enumerate inherited methods" )
       
  2504         << int(QScriptEngine::ExcludeSuperClassMethods)
       
  2505         << (QStringList()
       
  2506             // meta-object-defined properties:
       
  2507             //   inherited
       
  2508             << "objectName"
       
  2509             //   non-inherited
       
  2510             << "p1" << "p2" << "p4" << "p6"
       
  2511             // dynamic properties
       
  2512             << "dp1" << "dp2" << "dp3"
       
  2513             // signals
       
  2514             << "mySignal()"
       
  2515             // slots
       
  2516             << "mySlot()" << "myOtherSlot()");
       
  2517 
       
  2518     QTest::newRow( "don't enumerate inherited members" )
       
  2519         << int(QScriptEngine::ExcludeSuperClassMethods
       
  2520                | QScriptEngine::ExcludeSuperClassProperties)
       
  2521         << (QStringList()
       
  2522             // meta-object-defined properties
       
  2523             << "p1" << "p2" << "p4" << "p6"
       
  2524             // dynamic properties
       
  2525             << "dp1" << "dp2" << "dp3"
       
  2526             // signals
       
  2527             << "mySignal()"
       
  2528             // slots
       
  2529             << "mySlot()" << "myOtherSlot()");
       
  2530 
       
  2531     QTest::newRow( "enumerate properties, not methods" )
       
  2532         << int(QScriptEngine::SkipMethodsInEnumeration)
       
  2533         << (QStringList()
       
  2534             // meta-object-defined properties:
       
  2535             //   inherited
       
  2536             << "objectName"
       
  2537             //   non-inherited
       
  2538             << "p1" << "p2" << "p4" << "p6"
       
  2539             // dynamic properties
       
  2540             << "dp1" << "dp2" << "dp3");
       
  2541 
       
  2542     QTest::newRow( "don't enumerate inherited properties + methods" )
       
  2543         << int(QScriptEngine::ExcludeSuperClassProperties
       
  2544             | QScriptEngine::SkipMethodsInEnumeration)
       
  2545         << (QStringList()
       
  2546             // meta-object-defined properties:
       
  2547             //   non-inherited
       
  2548             << "p1" << "p2" << "p4" << "p6"
       
  2549             // dynamic properties
       
  2550             << "dp1" << "dp2" << "dp3");
       
  2551 
       
  2552     QTest::newRow( "don't enumerate inherited members" )
       
  2553         << int(QScriptEngine::ExcludeSuperClassContents)
       
  2554         << (QStringList()
       
  2555             // meta-object-defined properties
       
  2556             << "p1" << "p2" << "p4" << "p6"
       
  2557             // dynamic properties
       
  2558             << "dp1" << "dp2" << "dp3"
       
  2559             // signals
       
  2560             << "mySignal()"
       
  2561             // slots
       
  2562             << "mySlot()" << "myOtherSlot()");
       
  2563 
       
  2564     QTest::newRow( "don't enumerate deleteLater()" )
       
  2565         << int(QScriptEngine::ExcludeDeleteLater)
       
  2566         << (QStringList()
       
  2567             // meta-object-defined properties:
       
  2568             //   inherited
       
  2569             << "objectName"
       
  2570             //   non-inherited
       
  2571             << "p1" << "p2" << "p4" << "p6"
       
  2572             // dynamic properties
       
  2573             << "dp1" << "dp2" << "dp3"
       
  2574             // inherited slots
       
  2575             << "destroyed(QObject*)" << "destroyed()"
       
  2576             // not included because it's private:
       
  2577             // << "_q_reregisterTimers(void*)"
       
  2578             // signals
       
  2579             << "mySignal()"
       
  2580             // slots
       
  2581             << "mySlot()" << "myOtherSlot()");
       
  2582 }
       
  2583 
       
  2584 void tst_QScriptExtQObject::enumerate()
       
  2585 {
       
  2586     QFETCH( int, wrapOptions );
       
  2587     QFETCH( QStringList, expectedNames );
       
  2588 
       
  2589     QScriptEngine eng;
       
  2590     MyEnumTestQObject enumQObject;
       
  2591     // give it some dynamic properties
       
  2592     enumQObject.setProperty("dp1", "dp1");
       
  2593     enumQObject.setProperty("dp2", "dp2");
       
  2594     enumQObject.setProperty("dp3", "dp3");
       
  2595     QScriptValue obj = eng.newQObject(&enumQObject, QScriptEngine::QtOwnership,
       
  2596                                       QScriptEngine::QObjectWrapOptions(wrapOptions));
       
  2597 
       
  2598     // enumerate in script
       
  2599     {
       
  2600         eng.globalObject().setProperty("myEnumObject", obj);
       
  2601         eng.evaluate("var enumeratedProperties = []");
       
  2602         eng.evaluate("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
       
  2603         QStringList result = qscriptvalue_cast<QStringList>(eng.evaluate("enumeratedProperties"));
       
  2604         QCOMPARE(result.size(), expectedNames.size());
       
  2605         for (int i = 0; i < expectedNames.size(); ++i)
       
  2606             QCOMPARE(result.at(i), expectedNames.at(i));
       
  2607     }
       
  2608     // enumerate in C++
       
  2609     {
       
  2610         QScriptValueIterator it(obj);
       
  2611         QStringList result;
       
  2612         while (it.hasNext()) {
       
  2613             it.next();
       
  2614             QCOMPARE(it.flags(), obj.propertyFlags(it.name()));
       
  2615             result.append(it.name());
       
  2616         }
       
  2617         QCOMPARE(result.size(), expectedNames.size());
       
  2618         for (int i = 0; i < expectedNames.size(); ++i)
       
  2619             QCOMPARE(result.at(i), expectedNames.at(i));
       
  2620     }
       
  2621 }
       
  2622 
       
  2623 class SpecialEnumTestObject : public QObject
       
  2624 {
       
  2625     Q_OBJECT
       
  2626     // overriding a property in the super-class to make it non-scriptable
       
  2627     Q_PROPERTY(QString objectName READ objectName SCRIPTABLE false)
       
  2628 public:
       
  2629     SpecialEnumTestObject(QObject *parent = 0)
       
  2630         : QObject(parent) {}
       
  2631 };
       
  2632 
       
  2633 class SpecialEnumTestObject2 : public QObject
       
  2634 {
       
  2635     Q_OBJECT
       
  2636     // overriding a property in the super-class to make it non-designable (but still scriptable)
       
  2637     Q_PROPERTY(QString objectName READ objectName DESIGNABLE false)
       
  2638 public:
       
  2639     SpecialEnumTestObject2(QObject *parent = 0)
       
  2640         : QObject(parent) {}
       
  2641 };
       
  2642 
       
  2643 void tst_QScriptExtQObject::enumerateSpecial()
       
  2644 {
       
  2645     QScriptEngine eng;
       
  2646     {
       
  2647         SpecialEnumTestObject testObj;
       
  2648         QScriptValueIterator it(eng.newQObject(&testObj));
       
  2649         bool objectNameEncountered = false;
       
  2650         while (it.hasNext()) {
       
  2651             it.next();
       
  2652             if (it.name() == QLatin1String("objectName")) {
       
  2653                 objectNameEncountered = true;
       
  2654                 break;
       
  2655             }
       
  2656         }
       
  2657         QVERIFY(!objectNameEncountered);
       
  2658     }
       
  2659     {
       
  2660         SpecialEnumTestObject2 testObj;
       
  2661         testObj.setObjectName("foo");
       
  2662         QScriptValueList values;
       
  2663         QScriptValueIterator it(eng.newQObject(&testObj));
       
  2664         while (it.hasNext()) {
       
  2665             it.next();
       
  2666             if (it.name() == "objectName")
       
  2667                 values.append(it.value());
       
  2668         }
       
  2669         QCOMPARE(values.size(), 1);
       
  2670         QCOMPARE(values.at(0).toString(), QString::fromLatin1("foo"));
       
  2671     }
       
  2672 }
       
  2673 
       
  2674 void tst_QScriptExtQObject::wrapOptions()
       
  2675 {
       
  2676     QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
       
  2677     MyQObject *child = new MyQObject(m_myObject);
       
  2678     child->setObjectName("child");
       
  2679     // exclude child objects
       
  2680     {
       
  2681         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2682                                                 QScriptEngine::ExcludeChildObjects);
       
  2683         QCOMPARE(obj.property("child").isValid(), false);
       
  2684         obj.setProperty("child", QScriptValue(m_engine, 123));
       
  2685         QCOMPARE(obj.property("child")
       
  2686                  .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  2687     }
       
  2688     // don't auto-create dynamic properties
       
  2689     {
       
  2690         QScriptValue obj = m_engine->newQObject(m_myObject);
       
  2691         QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
       
  2692         obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123));
       
  2693         QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
       
  2694         QCOMPARE(obj.property("anotherDynamicProperty")
       
  2695                  .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  2696     }
       
  2697     // auto-create dynamic properties
       
  2698     {
       
  2699         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2700                                                 QScriptEngine::AutoCreateDynamicProperties);
       
  2701         QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
       
  2702         obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123));
       
  2703         QVERIFY(m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
       
  2704         QCOMPARE(obj.property("anotherDynamicProperty")
       
  2705                  .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  2706         // task 236685
       
  2707         {
       
  2708             QScriptValue obj2 = m_engine->newObject();
       
  2709             obj2.setProperty("notADynamicProperty", 456);
       
  2710             obj.setPrototype(obj2);
       
  2711             QScriptValue ret = obj.property("notADynamicProperty");
       
  2712             QVERIFY(ret.isNumber());
       
  2713             QVERIFY(ret.strictlyEquals(obj2.property("notADynamicProperty")));
       
  2714         }
       
  2715     }
       
  2716     // don't exclude super-class properties
       
  2717     {
       
  2718         QScriptValue obj = m_engine->newQObject(m_myObject);
       
  2719         QVERIFY(obj.property("objectName").isValid());
       
  2720         QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
       
  2721     }
       
  2722     // exclude super-class properties
       
  2723     {
       
  2724         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2725                                                 QScriptEngine::ExcludeSuperClassProperties);
       
  2726         QVERIFY(!obj.property("objectName").isValid());
       
  2727         QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
       
  2728         QVERIFY(obj.property("intProperty").isValid());
       
  2729         QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
       
  2730     }
       
  2731     // don't exclude super-class methods
       
  2732     {
       
  2733         QScriptValue obj = m_engine->newQObject(m_myObject);
       
  2734         QVERIFY(obj.property("deleteLater").isValid());
       
  2735         QVERIFY(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember);
       
  2736     }
       
  2737     // exclude super-class methods
       
  2738     {
       
  2739         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2740                                                 QScriptEngine::ExcludeSuperClassMethods);
       
  2741         QVERIFY(!obj.property("deleteLater").isValid());
       
  2742         QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
       
  2743         QVERIFY(obj.property("mySlot").isValid());
       
  2744         QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
       
  2745     }
       
  2746     // exclude all super-class contents
       
  2747     {
       
  2748         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2749                                                 QScriptEngine::ExcludeSuperClassContents);
       
  2750         QVERIFY(!obj.property("deleteLater").isValid());
       
  2751         QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
       
  2752         QVERIFY(obj.property("mySlot").isValid());
       
  2753         QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
       
  2754 
       
  2755         QVERIFY(!obj.property("objectName").isValid());
       
  2756         QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
       
  2757         QVERIFY(obj.property("intProperty").isValid());
       
  2758         QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
       
  2759     }
       
  2760     // exclude deleteLater()
       
  2761     {
       
  2762         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2763                                                 QScriptEngine::ExcludeDeleteLater);
       
  2764         QVERIFY(!obj.property("deleteLater").isValid());
       
  2765         QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
       
  2766         QVERIFY(obj.property("mySlot").isValid());
       
  2767         QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
       
  2768 
       
  2769         QVERIFY(obj.property("objectName").isValid());
       
  2770         QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
       
  2771         QVERIFY(obj.property("intProperty").isValid());
       
  2772         QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
       
  2773     }
       
  2774     // exclude all that we can
       
  2775     {
       
  2776         QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership,
       
  2777                                                 QScriptEngine::ExcludeSuperClassMethods
       
  2778                                                 | QScriptEngine::ExcludeSuperClassProperties
       
  2779                                                 | QScriptEngine::ExcludeChildObjects);
       
  2780         QVERIFY(!obj.property("deleteLater").isValid());
       
  2781         QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
       
  2782         QVERIFY(obj.property("mySlot").isValid());
       
  2783         QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
       
  2784 
       
  2785         QVERIFY(!obj.property("objectName").isValid());
       
  2786         QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
       
  2787         QVERIFY(obj.property("intProperty").isValid());
       
  2788         QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
       
  2789 
       
  2790         QCOMPARE(obj.property("child").isValid(), false);
       
  2791         obj.setProperty("child", QScriptValue(m_engine, 123));
       
  2792         QCOMPARE(obj.property("child")
       
  2793                  .strictlyEquals(QScriptValue(m_engine, 123)), true);
       
  2794     }
       
  2795 
       
  2796     delete child;
       
  2797 }
       
  2798 
       
  2799 Q_DECLARE_METATYPE(QWidget*)
       
  2800 Q_DECLARE_METATYPE(QPushButton*)
       
  2801 
       
  2802 void tst_QScriptExtQObject::prototypes()
       
  2803 {
       
  2804     QScriptEngine eng;
       
  2805     QScriptValue widgetProto = eng.newQObject(new QWidget(), QScriptEngine::ScriptOwnership);
       
  2806     eng.setDefaultPrototype(qMetaTypeId<QWidget*>(), widgetProto);
       
  2807     QPushButton *pbp = new QPushButton();
       
  2808     QScriptValue buttonProto = eng.newQObject(pbp, QScriptEngine::ScriptOwnership);
       
  2809     buttonProto.setPrototype(widgetProto);
       
  2810     eng.setDefaultPrototype(qMetaTypeId<QPushButton*>(), buttonProto);
       
  2811     QPushButton *pb = new QPushButton();
       
  2812     QScriptValue button = eng.newQObject(pb, QScriptEngine::ScriptOwnership);
       
  2813     QVERIFY(button.prototype().strictlyEquals(buttonProto));
       
  2814 
       
  2815     buttonProto.setProperty("text", QScriptValue(&eng, "prototype button"));
       
  2816     QCOMPARE(pbp->text(), QLatin1String("prototype button"));
       
  2817     button.setProperty("text", QScriptValue(&eng, "not the prototype button"));
       
  2818     QCOMPARE(pb->text(), QLatin1String("not the prototype button"));
       
  2819     QCOMPARE(pbp->text(), QLatin1String("prototype button"));
       
  2820 
       
  2821     buttonProto.setProperty("objectName", QScriptValue(&eng, "prototype button"));
       
  2822     QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
       
  2823     button.setProperty("objectName", QScriptValue(&eng, "not the prototype button"));
       
  2824     QCOMPARE(pb->objectName(), QLatin1String("not the prototype button"));
       
  2825     QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
       
  2826 }
       
  2827 
       
  2828 void tst_QScriptExtQObject::objectDeleted()
       
  2829 {
       
  2830     QScriptEngine eng;
       
  2831     MyQObject *qobj = new MyQObject();
       
  2832     QScriptValue v = eng.newQObject(qobj);
       
  2833     v.setProperty("objectName", QScriptValue(&eng, "foo"));
       
  2834     QCOMPARE(qobj->objectName(), QLatin1String("foo"));
       
  2835     v.setProperty("intProperty", QScriptValue(&eng, 123));
       
  2836     QCOMPARE(qobj->intProperty(), 123);
       
  2837     qobj->resetQtFunctionInvoked();
       
  2838     v.property("myInvokable").call(v);
       
  2839     QCOMPARE(qobj->qtFunctionInvoked(), 0);
       
  2840 
       
  2841     // now delete the object
       
  2842     delete qobj;
       
  2843 
       
  2844     // the documented behavior is: isQObject() should still return true,
       
  2845     // but toQObject() should return 0
       
  2846     QVERIFY(v.isQObject());
       
  2847     QCOMPARE(v.toQObject(), (QObject *)0);
       
  2848 
       
  2849     // any attempt to access properties of the object should result in an exception
       
  2850     {
       
  2851         QScriptValue ret = v.property("objectName");
       
  2852         QVERIFY(ret.isError());
       
  2853         QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2854     }
       
  2855     {
       
  2856         eng.evaluate("Object");
       
  2857         QVERIFY(!eng.hasUncaughtException());
       
  2858         v.setProperty("objectName", QScriptValue(&eng, "foo"));
       
  2859         QVERIFY(eng.hasUncaughtException());
       
  2860         QVERIFY(eng.uncaughtException().isError());
       
  2861         QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2862     }
       
  2863 
       
  2864     {
       
  2865         QScriptValue ret = v.call();
       
  2866         QVERIFY(!ret.isValid());
       
  2867     }
       
  2868 
       
  2869     // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
       
  2870     {
       
  2871         QScriptValue ret = v.property("myInvokableWithIntArg");
       
  2872         QVERIFY(ret.isError());
       
  2873         QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
       
  2874     }
       
  2875 
       
  2876     // access from script
       
  2877     eng.globalObject().setProperty("o", v);
       
  2878     {
       
  2879         QScriptValue ret = eng.evaluate("o()");
       
  2880         QVERIFY(ret.isError());
       
  2881         QCOMPARE(ret.toString(), QLatin1String("TypeError: Result of expression 'o' [] is not a function."));
       
  2882     }
       
  2883     {
       
  2884         QScriptValue ret = eng.evaluate("o.objectName");
       
  2885         QVERIFY(ret.isError());
       
  2886         QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2887     }
       
  2888     {
       
  2889         QScriptValue ret = eng.evaluate("o.myInvokable()");
       
  2890         QVERIFY(ret.isError());
       
  2891         QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokable' of deleted QObject"));
       
  2892     }
       
  2893     {
       
  2894         QScriptValue ret = eng.evaluate("o.myInvokableWithIntArg(10)");
       
  2895         QVERIFY(ret.isError());
       
  2896         QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
       
  2897     }
       
  2898 }
       
  2899 
       
  2900 void tst_QScriptExtQObject::connectToDestroyedSignal()
       
  2901 {
       
  2902     // ### the following test currently depends on signal emission order
       
  2903 #if 0
       
  2904     {
       
  2905         // case 1: deleted when the engine is not doing GC
       
  2906         QScriptEngine eng;
       
  2907         QObject *obj = new QObject();
       
  2908         eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::QtOwnership));
       
  2909         eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
       
  2910         eng.evaluate("wasDestroyed = false");
       
  2911         delete obj;
       
  2912         QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
       
  2913     }
       
  2914     {
       
  2915         // case 2: deleted when the engine is doing GC
       
  2916         QScriptEngine eng;
       
  2917         QObject *obj = new QObject();
       
  2918         eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
       
  2919         eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
       
  2920         eng.evaluate("wasDestroyed = false");
       
  2921         eng.evaluate("o = null");
       
  2922         eng.collectGarbage();
       
  2923         QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
       
  2924     }
       
  2925     {
       
  2926         // case 3: deleted when the engine is destroyed
       
  2927         QScriptEngine eng;
       
  2928         QObject *obj = new QObject();
       
  2929         eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
       
  2930         eng.evaluate("o.destroyed.connect(function() { })");
       
  2931         // the signal handler won't get called -- we don't want to crash
       
  2932     }
       
  2933 #endif
       
  2934 }
       
  2935 
       
  2936 QTEST_MAIN(tst_QScriptExtQObject)
       
  2937 #include "tst_qscriptextqobject.moc"