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