1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32#include <qscriptengine.h>
33#include <qscriptcontext.h>
34#include <qscriptvalueiterator.h>
35#include <qwidget.h>
36#include <qtextstream.h>
37#include <qpushbutton.h>
38#include <qlineedit.h>
39
40#include "../shared/util.h"
41
42struct CustomType
43{
44 QString string;
45};
46Q_DECLARE_METATYPE(CustomType)
47
48Q_DECLARE_METATYPE(QBrush*)
49Q_DECLARE_METATYPE(QObjectList)
50Q_DECLARE_METATYPE(QList<int>)
51Q_DECLARE_METATYPE(Qt::BrushStyle)
52Q_DECLARE_METATYPE(QDir)
53
54static void dirFromScript(const QScriptValue &in, QDir &out)
55{
56 QScriptValue path = in.property(name: "path");
57 if (!path.isValid())
58 in.engine()->currentContext()->throwError(text: "No path");
59 else
60 out.setPath(path.toString());
61}
62
63namespace MyNS
64{
65 class A : public QObject
66 {
67 Q_OBJECT
68 public:
69 enum Type {
70 Foo,
71 Bar
72 };
73 Q_ENUMS(Type)
74 public Q_SLOTS:
75 int slotTakingScopedEnumArg(MyNS::A::Type t) {
76 return t;
77 }
78 };
79}
80
81class MyQObject : public QObject
82{
83 Q_OBJECT
84
85 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
86 Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
87 Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
88 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
89 Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
90 Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
91 Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
92 Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
93 Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
94 Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
95 Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
96 Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
97 Q_PROPERTY(Policy enumProperty READ enumProperty WRITE setEnumProperty)
98 Q_PROPERTY(Ability flagsProperty READ flagsProperty WRITE setFlagsProperty)
99 Q_ENUMS(Policy Strategy)
100 Q_FLAGS(Ability)
101
102public:
103 enum Policy {
104 FooPolicy = 0,
105 BarPolicy,
106 BazPolicy
107 };
108
109 enum Strategy {
110 FooStrategy = 10,
111 BarStrategy,
112 BazStrategy
113 };
114
115 enum AbilityFlag {
116 NoAbility = 0x000,
117 FooAbility = 0x001,
118 BarAbility = 0x080,
119 BazAbility = 0x200,
120 AllAbility = FooAbility | BarAbility | BazAbility
121 };
122
123 Q_DECLARE_FLAGS(Ability, AbilityFlag)
124
125 MyQObject(QObject *parent = 0)
126 : QObject(parent),
127 m_intValue(123),
128 m_variantValue(QLatin1String("foo")),
129 m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
130 m_stringValue(QLatin1String("bar")),
131 m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
132 m_brushValue(QColor(10, 20, 30, 40)),
133 m_hiddenValue(456.0),
134 m_writeOnlyValue(789),
135 m_readOnlyValue(987),
136 m_enumValue(BarPolicy),
137 m_flagsValue(FooAbility),
138 m_qtFunctionInvoked(-1)
139 { }
140
141 int intProperty() const
142 { return m_intValue; }
143 void setIntProperty(int value)
144 { m_intValue = value; }
145
146 QVariant variantProperty() const
147 { return m_variantValue; }
148 void setVariantProperty(const QVariant &value)
149 { m_variantValue = value; }
150
151 QVariantList variantListProperty() const
152 { return m_variantListValue; }
153 void setVariantListProperty(const QVariantList &value)
154 { m_variantListValue = value; }
155
156 QString stringProperty() const
157 { return m_stringValue; }
158 void setStringProperty(const QString &value)
159 { m_stringValue = value; }
160
161 QStringList stringListProperty() const
162 { return m_stringListValue; }
163 void setStringListProperty(const QStringList &value)
164 { m_stringListValue = value; }
165
166 QByteArray byteArrayProperty() const
167 { return m_byteArrayValue; }
168 void setByteArrayProperty(const QByteArray &value)
169 { m_byteArrayValue = value; }
170
171 QBrush brushProperty() const
172 { return m_brushValue; }
173 Q_INVOKABLE void setBrushProperty(const QBrush &value)
174 { m_brushValue = value; }
175
176 double hiddenProperty() const
177 { return m_hiddenValue; }
178 void setHiddenProperty(double value)
179 { m_hiddenValue = value; }
180
181 int writeOnlyProperty() const
182 { return m_writeOnlyValue; }
183 void setWriteOnlyProperty(int value)
184 { m_writeOnlyValue = value; }
185
186 int readOnlyProperty() const
187 { return m_readOnlyValue; }
188
189 QKeySequence shortcut() const
190 { return m_shortcut; }
191 void setShortcut(const QKeySequence &seq)
192 { m_shortcut = seq; }
193
194 CustomType propWithCustomType() const
195 { return m_customType; }
196 void setPropWithCustomType(const CustomType &c)
197 { m_customType = c; }
198
199 Policy enumProperty() const
200 { return m_enumValue; }
201 void setEnumProperty(Policy policy)
202 { m_enumValue = policy; }
203
204 Ability flagsProperty() const
205 { return m_flagsValue; }
206 void setFlagsProperty(Ability ability)
207 { m_flagsValue = ability; }
208
209 int qtFunctionInvoked() const
210 { return m_qtFunctionInvoked; }
211
212 QVariantList qtFunctionActuals() const
213 { return m_actuals; }
214
215 void resetQtFunctionInvoked()
216 { m_qtFunctionInvoked = -1; m_actuals.clear(); }
217
218 void clearConnectNotifySignals()
219 { m_connectNotifySignals.clear(); }
220 void clearDisconnectNotifySignals()
221 { m_disconnectNotifySignals.clear(); }
222 QList<QMetaMethod> connectNotifySignals() const
223 { return m_connectNotifySignals; }
224 QList<QMetaMethod> disconnectNotifySignals() const
225 { return m_disconnectNotifySignals; }
226 bool hasSingleConnectNotifySignal(const QMetaMethod &signal) const
227 { return (m_connectNotifySignals.size() == 1) && (m_connectNotifySignals.first() == signal); }
228 bool hasConnectNotifySignal(const QMetaMethod &signal) const
229 { return m_connectNotifySignals.contains(t: signal); }
230 bool hasSingleDisconnectNotifySignal(const QMetaMethod &signal) const
231 { return (m_disconnectNotifySignals.size() == 1) && (m_disconnectNotifySignals.first() == signal); }
232
233 Q_INVOKABLE void myInvokable()
234 { m_qtFunctionInvoked = 0; }
235 Q_INVOKABLE void myInvokableWithIntArg(int arg)
236 { m_qtFunctionInvoked = 1; m_actuals << arg; }
237 Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg)
238 { m_qtFunctionInvoked = 2; m_actuals << arg; }
239 Q_INVOKABLE void myInvokableWithFloatArg(float arg)
240 { m_qtFunctionInvoked = 3; m_actuals << arg; }
241 Q_INVOKABLE void myInvokableWithDoubleArg(double arg)
242 { m_qtFunctionInvoked = 4; m_actuals << arg; }
243 Q_INVOKABLE void myInvokableWithStringArg(const QString &arg)
244 { m_qtFunctionInvoked = 5; m_actuals << arg; }
245 Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2)
246 { m_qtFunctionInvoked = 6; m_actuals << arg1 << arg2; }
247 Q_INVOKABLE int myInvokableReturningInt()
248 { m_qtFunctionInvoked = 7; return 123; }
249 Q_INVOKABLE qlonglong myInvokableReturningLongLong()
250 { m_qtFunctionInvoked = 39; return 456; }
251 Q_INVOKABLE QString myInvokableReturningString()
252 { m_qtFunctionInvoked = 8; return QLatin1String("ciao"); }
253 Q_INVOKABLE QVariant myInvokableReturningVariant()
254 { m_qtFunctionInvoked = 60; return 123; }
255 Q_INVOKABLE QScriptValue myInvokableReturningScriptValue()
256 { m_qtFunctionInvoked = 61; return 456; }
257 Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // overload
258 { m_qtFunctionInvoked = 9; m_actuals << arg1 << arg2; }
259 Q_INVOKABLE void myInvokableWithEnumArg(Policy policy)
260 { m_qtFunctionInvoked = 10; m_actuals << policy; }
261 Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy)
262 { m_qtFunctionInvoked = 36; m_actuals << policy; }
263 Q_INVOKABLE Policy myInvokableReturningEnum()
264 { m_qtFunctionInvoked = 37; return BazPolicy; }
265 Q_INVOKABLE MyQObject::Strategy myInvokableReturningQualifiedEnum()
266 { m_qtFunctionInvoked = 38; return BazStrategy; }
267 Q_INVOKABLE QVector<CustomType> myInvokableReturningVectorOfCustomType()
268 { m_qtFunctionInvoked = 11; return QVector<CustomType>(); }
269 Q_INVOKABLE void myInvokableWithVectorOfCustomTypeArg(const QVector<CustomType> &)
270 { m_qtFunctionInvoked = 12; }
271 Q_INVOKABLE QObject *myInvokableReturningQObjectStar()
272 { m_qtFunctionInvoked = 13; return this; }
273 Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst)
274 { m_qtFunctionInvoked = 14; m_actuals << QVariant::fromValue(value: lst); return lst; }
275 Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v)
276 { m_qtFunctionInvoked = 15; m_actuals << v; return v; }
277 Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm)
278 { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; }
279 Q_INVOKABLE QVariantList myInvokableWithVariantListArg(const QVariantList &lst)
280 { m_qtFunctionInvoked = 62; m_actuals.append(t: QVariant(lst)); return lst; }
281 Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst)
282 { m_qtFunctionInvoked = 17; m_actuals << QVariant::fromValue(value: lst); return lst; }
283 Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj)
284 { m_qtFunctionInvoked = 18; m_actuals << QVariant::fromValue(value: obj); return obj; }
285 Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush)
286 { m_qtFunctionInvoked = 19; m_actuals << QVariant::fromValue(value: brush); return brush; }
287 Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style)
288 { m_qtFunctionInvoked = 43; m_actuals << QVariant::fromValue(value: style); }
289 Q_INVOKABLE void myInvokableWithVoidStarArg(void *arg)
290 { m_qtFunctionInvoked = 44; m_actuals << QVariant::fromValue(value: arg); }
291 Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg)
292 { m_qtFunctionInvoked = 45; m_actuals << QVariant::fromValue(value: arg); }
293 Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg)
294 { m_qtFunctionInvoked = 46; m_actuals << QVariant::fromValue(value: arg); }
295 Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "")
296 { m_qtFunctionInvoked = 47; m_actuals << QVariant::fromValue(value: arg1) << QVariant::fromValue(value: arg2); }
297 Q_INVOKABLE QObject& myInvokableReturningRef()
298 { m_qtFunctionInvoked = 48; return *this; }
299 Q_INVOKABLE const QObject& myInvokableReturningConstRef() const
300 { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49; return *this; }
301 Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg)
302 { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50; m_actuals << QVariant::fromValue(value: arg); }
303 Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg)
304 { const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51; m_actuals << QVariant::fromValue(value: arg); }
305 Q_INVOKABLE void myInvokableWithMyQObjectArg(MyQObject *arg)
306 { m_qtFunctionInvoked = 52; m_actuals << QVariant::fromValue(value: (QObject*)arg); }
307 Q_INVOKABLE MyQObject* myInvokableReturningMyQObject()
308 { m_qtFunctionInvoked = 53; return this; }
309 Q_INVOKABLE void myInvokableWithConstMyQObjectArg(const MyQObject *arg)
310 { m_qtFunctionInvoked = 54; m_actuals << QVariant::fromValue(value: (QObject*)arg); }
311 Q_INVOKABLE void myInvokableWithQDirArg(const QDir &arg)
312 { m_qtFunctionInvoked = 55; m_actuals << QVariant::fromValue(value: arg); }
313 Q_INVOKABLE QScriptValue myInvokableWithScriptValueArg(const QScriptValue &arg)
314 { m_qtFunctionInvoked = 56; return arg; }
315 Q_INVOKABLE QObject* myInvokableReturningMyQObjectAsQObject()
316 { m_qtFunctionInvoked = 57; return this; }
317 Q_INVOKABLE Ability myInvokableWithFlagsArg(Ability arg)
318 { m_qtFunctionInvoked = 58; m_actuals << int(arg); return arg; }
319 Q_INVOKABLE MyQObject::Ability myInvokableWithQualifiedFlagsArg(MyQObject::Ability arg)
320 { m_qtFunctionInvoked = 59; m_actuals << int(arg); return arg; }
321 Q_INVOKABLE QWidget *myInvokableWithQWidgetStarArg(QWidget *arg)
322 { m_qtFunctionInvoked = 63; m_actuals << QVariant::fromValue(value: (QWidget*)arg); return arg; }
323 Q_INVOKABLE short myInvokableWithShortArg(short arg)
324 { m_qtFunctionInvoked = 64; m_actuals << QVariant::fromValue(value: arg); return arg; }
325 Q_INVOKABLE unsigned short myInvokableWithUShortArg(unsigned short arg)
326 { m_qtFunctionInvoked = 65; m_actuals << QVariant::fromValue(value: arg); return arg; }
327 Q_INVOKABLE char myInvokableWithCharArg(char arg)
328 { m_qtFunctionInvoked = 66; m_actuals << QVariant::fromValue(value: arg); return arg; }
329 Q_INVOKABLE unsigned char myInvokableWithUCharArg(unsigned char arg)
330 { m_qtFunctionInvoked = 67; m_actuals << QVariant::fromValue(value: arg); return arg; }
331 Q_INVOKABLE qulonglong myInvokableWithULonglongArg(qulonglong arg)
332 { m_qtFunctionInvoked = 68; m_actuals << QVariant::fromValue(value: arg); return arg; }
333 Q_INVOKABLE long myInvokableWithLongArg(long arg)
334 { m_qtFunctionInvoked = 69; m_actuals << QVariant::fromValue(value: arg); return arg; }
335 Q_INVOKABLE unsigned long myInvokableWithULongArg(unsigned long arg)
336 { m_qtFunctionInvoked = 70; m_actuals << QVariant::fromValue(value: arg); return arg; }
337
338 Q_INVOKABLE QObjectList findObjects() const
339 { return findChildren<QObject *>(); }
340 Q_INVOKABLE QList<int> myInvokableNumbers() const
341 { return QList<int>() << 1 << 2 << 3; }
342
343 void emitMySignal()
344 { emit mySignal(); }
345 void emitMySignalWithIntArg(int arg)
346 { emit mySignalWithIntArg(arg); }
347 void emitMySignal2(bool arg)
348 { emit mySignal2(arg); }
349 void emitMySignal2()
350 { emit mySignal2(); }
351 void emitMyOverloadedSignal(int arg)
352 { emit myOverloadedSignal(arg); }
353 void emitMyOverloadedSignal(const QString &arg)
354 { emit myOverloadedSignal(arg); }
355 void emitMyOtherOverloadedSignal(const QString &arg)
356 { emit myOtherOverloadedSignal(arg); }
357 void emitMyOtherOverloadedSignal(int arg)
358 { emit myOtherOverloadedSignal(arg); }
359 void emitMySignalWithDefaultArgWithArg(int arg)
360 { emit mySignalWithDefaultArg(arg); }
361 void emitMySignalWithDefaultArg()
362 { emit mySignalWithDefaultArg(); }
363 void emitMySignalWithVariantArg(const QVariant &arg)
364 { emit mySignalWithVariantArg(arg); }
365 void emitMySignalWithScriptEngineArg(QScriptEngine *arg)
366 { emit mySignalWithScriptEngineArg(arg); }
367
368public Q_SLOTS:
369 void mySlot()
370 { m_qtFunctionInvoked = 20; }
371 void mySlotWithIntArg(int arg)
372 { m_qtFunctionInvoked = 21; m_actuals << arg; }
373 void mySlotWithDoubleArg(double arg)
374 { m_qtFunctionInvoked = 22; m_actuals << arg; }
375 void mySlotWithStringArg(const QString &arg)
376 { m_qtFunctionInvoked = 23; m_actuals << arg; }
377
378 void myOverloadedSlot()
379 { m_qtFunctionInvoked = 24; }
380 void myOverloadedSlot(QObject *arg)
381 { m_qtFunctionInvoked = 41; m_actuals << QVariant::fromValue(value: arg); }
382 void myOverloadedSlot(bool arg)
383 { m_qtFunctionInvoked = 25; m_actuals << arg; }
384 void myOverloadedSlot(const QStringList &arg)
385 { m_qtFunctionInvoked = 42; m_actuals << arg; }
386 void myOverloadedSlot(double arg)
387 { m_qtFunctionInvoked = 26; m_actuals << arg; }
388 void myOverloadedSlot(float arg)
389 { m_qtFunctionInvoked = 27; m_actuals << arg; }
390 void myOverloadedSlot(int arg)
391 { m_qtFunctionInvoked = 28; m_actuals << arg; }
392 void myOverloadedSlot(const QString &arg)
393 { m_qtFunctionInvoked = 29; m_actuals << arg; }
394 void myOverloadedSlot(const QColor &arg)
395 { m_qtFunctionInvoked = 30; m_actuals << arg; }
396 void myOverloadedSlot(const QBrush &arg)
397 { m_qtFunctionInvoked = 31; m_actuals << arg; }
398 void myOverloadedSlot(const QDateTime &arg)
399 { m_qtFunctionInvoked = 32; m_actuals << arg; }
400 void myOverloadedSlot(const QDate &arg)
401 { m_qtFunctionInvoked = 33; m_actuals << arg; }
402 void myOverloadedSlot(const QTime &arg)
403 { m_qtFunctionInvoked = 69; m_actuals << arg; }
404 void myOverloadedSlot(const QRegExp &arg)
405 { m_qtFunctionInvoked = 34; m_actuals << arg; }
406 void myOverloadedSlot(const QVariant &arg)
407 { m_qtFunctionInvoked = 35; m_actuals << arg; }
408
409 virtual int myVirtualSlot(int arg)
410 { m_qtFunctionInvoked = 58; return arg; }
411
412 void qscript_call(int arg)
413 { m_qtFunctionInvoked = 40; m_actuals << arg; }
414
415protected Q_SLOTS:
416 void myProtectedSlot() { m_qtFunctionInvoked = 36; }
417
418private Q_SLOTS:
419 void myPrivateSlot() { }
420
421Q_SIGNALS:
422 void mySignal();
423 void mySignalWithIntArg(int arg);
424 void mySignalWithDoubleArg(double arg);
425 void mySignal2(bool arg = false);
426 void myOverloadedSignal(int arg);
427 void myOverloadedSignal(const QString &arg);
428 void myOtherOverloadedSignal(const QString &arg);
429 void myOtherOverloadedSignal(int arg);
430 void mySignalWithDefaultArg(int arg = 123);
431 void mySignalWithVariantArg(const QVariant &arg);
432 void mySignalWithScriptEngineArg(QScriptEngine *arg);
433
434protected:
435 void connectNotify(const QMetaMethod &signal) {
436 m_connectNotifySignals.append(t: signal);
437 }
438 void disconnectNotify(const QMetaMethod &signal) {
439 m_disconnectNotifySignals.append(t: signal);
440 }
441
442protected:
443 int m_intValue;
444 QVariant m_variantValue;
445 QVariantList m_variantListValue;
446 QString m_stringValue;
447 QStringList m_stringListValue;
448 QByteArray m_byteArrayValue;
449 QBrush m_brushValue;
450 double m_hiddenValue;
451 int m_writeOnlyValue;
452 int m_readOnlyValue;
453 QKeySequence m_shortcut;
454 CustomType m_customType;
455 Policy m_enumValue;
456 Ability m_flagsValue;
457 int m_qtFunctionInvoked;
458 QVariantList m_actuals;
459 QList<QMetaMethod> m_connectNotifySignals;
460 QList<QMetaMethod> m_disconnectNotifySignals;
461};
462
463Q_DECLARE_METATYPE(MyQObject*)
464Q_DECLARE_METATYPE(MyQObject::Policy)
465
466class MyOtherQObject : public MyQObject
467{
468 Q_OBJECT
469public:
470 MyOtherQObject(QObject *parent = 0)
471 : MyQObject(parent)
472 { }
473public Q_SLOTS:
474 virtual int myVirtualSlot(int arg)
475 { m_qtFunctionInvoked = 59; return arg; }
476};
477
478class MyEnumTestQObject : public QObject
479{
480 Q_OBJECT
481 Q_PROPERTY(QString p1 READ p1)
482 Q_PROPERTY(QString p2 READ p2)
483 Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
484 Q_PROPERTY(QString p4 READ p4)
485 Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
486 Q_PROPERTY(QString p6 READ p6)
487public:
488 MyEnumTestQObject(QObject *parent = 0)
489 : QObject(parent) { }
490 QString p1() const { return QLatin1String("p1"); }
491 QString p2() const { return QLatin1String("p2"); }
492 QString p3() const { return QLatin1String("p3"); }
493 QString p4() const { return QLatin1String("p4"); }
494 QString p5() const { return QLatin1String("p5"); }
495 QString p6() const { return QLatin1String("p5"); }
496public Q_SLOTS:
497 void mySlot() { }
498 void myOtherSlot() { }
499Q_SIGNALS:
500 void mySignal();
501};
502
503class tst_QScriptExtQObject : public QObject
504{
505 Q_OBJECT
506
507public:
508 tst_QScriptExtQObject();
509 virtual ~tst_QScriptExtQObject();
510
511public slots:
512 void init();
513 void cleanup();
514
515protected slots:
516 void onSignalHandlerException(const QScriptValue &exception)
517 {
518 m_signalHandlerException = exception;
519 }
520
521private slots:
522 void registeredTypes();
523 void getSetStaticProperty();
524 void getSetStaticProperty_propertyFlags();
525 void getSetStaticProperty_changeInCpp();
526 void getSetStaticProperty_changeInJS();
527 void getSetStaticProperty_compatibleVariantTypes();
528 void getSetStaticProperty_conversion();
529 void getSetStaticProperty_delete();
530 void getSetStaticProperty_nonScriptable();
531 void getSetStaticProperty_writeOnly();
532 void getSetStaticProperty_readOnly();
533 void getSetStaticProperty_enum();
534 void getSetStaticProperty_qflags();
535 void getSetStaticProperty_pointerDeref();
536 void getSetStaticProperty_customGetterSetter();
537 void getSetStaticProperty_methodPersistence();
538 void getSetDynamicProperty();
539 void getSetDynamicProperty_deleteFromCpp();
540 void getSetDynamicProperty_hideChildObject();
541 void getSetDynamicProperty_setBeforeGet();
542 void getSetDynamicProperty_doNotHideJSProperty();
543 void getSetChildren();
544 void callQtInvokable();
545 void callQtInvokable2();
546 void callQtInvokable3();
547 void callQtInvokable4();
548 void callQtInvokable5();
549 void callQtInvokable6();
550 void callQtInvokable7();
551 void connectAndDisconnect();
552 void connectAndDisconnect_emitFromJS();
553 void connectAndDisconnect_senderWrapperCollected();
554 void connectAndDisconnectWithBadArgs();
555 void connectAndDisconnect_senderDeleted();
556 void cppConnectAndDisconnect();
557 void cppConnectAndDisconnect2();
558 void classEnums();
559 void classConstructor();
560 void overrideInvokable();
561 void transferInvokable();
562 void findChild();
563 void findChildren();
564 void childObjects();
565 void overloadedSlots();
566 void enumerate_data();
567 void enumerate();
568 void enumerateSpecial();
569 void wrapOptions();
570 void prototypes();
571 void objectDeleted();
572 void connectToDestroyedSignal();
573 void emitAfterReceiverDeleted();
574 void inheritedSlots();
575 void enumerateMetaObject();
576 void nestedArrayAsSlotArgument_data();
577 void nestedArrayAsSlotArgument();
578 void nestedObjectAsSlotArgument_data();
579 void nestedObjectAsSlotArgument();
580 void propertyAccessThroughActivationObject();
581 void connectionRemovedAfterQueuedCall();
582 void collectQObjectWithClosureSlot();
583 void collectQObjectWithClosureSlot2();
584
585private:
586 QScriptEngine *m_engine;
587 MyQObject *m_myObject;
588 QScriptValue m_signalHandlerException;
589};
590
591tst_QScriptExtQObject::tst_QScriptExtQObject()
592{
593}
594
595tst_QScriptExtQObject::~tst_QScriptExtQObject()
596{
597}
598
599void tst_QScriptExtQObject::init()
600{
601 m_engine = new QScriptEngine();
602 m_myObject = new MyQObject();
603 m_engine->globalObject().setProperty(name: "myObject", value: m_engine->newQObject(object: m_myObject));
604 m_engine->globalObject().setProperty(name: "global", value: m_engine->globalObject());
605}
606
607void tst_QScriptExtQObject::cleanup()
608{
609 delete m_engine;
610 delete m_myObject;
611}
612
613// this test has to be first and test that some types are automatically registered
614void tst_QScriptExtQObject::registeredTypes()
615{
616 QScriptEngine e;
617 QObject *t = new MyQObject;
618 QObject *c = new QObject(t);
619 c->setObjectName ("child1");
620
621 e.globalObject().setProperty(name: "MyTest", value: e.newQObject(object: t));
622
623 QScriptValue v1 = e.evaluate(program: "MyTest.findObjects()[0].objectName;");
624 QCOMPARE(v1.toString(), c->objectName());
625
626 QScriptValue v2 = e.evaluate(program: "MyTest.myInvokableNumbers()");
627 QCOMPARE(qscriptvalue_cast<QList<int> >(v2), (QList<int>() << 1 << 2 << 3));
628}
629
630
631static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *)
632{
633 if (ctx->argumentCount() != 0)
634 ctx->callee().setProperty(name: "value", value: ctx->argument(index: 0));
635 return ctx->callee().property(name: "value");
636}
637
638static QScriptValue policyToScriptValue(QScriptEngine *engine, const MyQObject::Policy &policy)
639{
640 return qScriptValueFromValue(engine, t: policy);
641}
642
643static void policyFromScriptValue(const QScriptValue &value, MyQObject::Policy &policy)
644{
645 QString str = value.toString();
646 if (str == QLatin1String("red"))
647 policy = MyQObject::FooPolicy;
648 else if (str == QLatin1String("green"))
649 policy = MyQObject::BarPolicy;
650 else if (str == QLatin1String("blue"))
651 policy = MyQObject::BazPolicy;
652 else
653 policy = (MyQObject::Policy)-1;
654}
655
656void tst_QScriptExtQObject::getSetStaticProperty()
657{
658 QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true);
659
660 // initial value (set in MyQObject constructor)
661 QCOMPARE(m_engine->evaluate("myObject.intProperty")
662 .strictlyEquals(QScriptValue(m_engine, 123.0)), true);
663 QCOMPARE(m_engine->evaluate("myObject.variantProperty")
664 .toVariant(), QVariant(QLatin1String("foo")));
665 QCOMPARE(m_engine->evaluate("myObject.stringProperty")
666 .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))), true);
667 QCOMPARE(m_engine->evaluate("myObject.variantListProperty").isArray(), true);
668 QCOMPARE(m_engine->evaluate("myObject.variantListProperty.length")
669 .strictlyEquals(QScriptValue(m_engine, 2)), true);
670 QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
671 .strictlyEquals(QScriptValue(m_engine, 123)), true);
672 QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
673 .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
674 QCOMPARE(m_engine->evaluate("myObject.stringListProperty").isArray(), true);
675 QCOMPARE(m_engine->evaluate("myObject.stringListProperty.length")
676 .strictlyEquals(QScriptValue(m_engine, 2)), true);
677 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
678 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
679 QLatin1String("zig"));
680 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
681 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
682 QLatin1String("zag"));
683}
684
685void tst_QScriptExtQObject::getSetStaticProperty_propertyFlags()
686{
687 // default flags for "normal" properties
688 {
689 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
690 QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::ReadOnly));
691 QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::Undeletable);
692 QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertyGetter);
693 QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertySetter);
694 QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::SkipInEnumeration));
695 QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
696
697 QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::ReadOnly));
698 QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::Undeletable));
699 QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::SkipInEnumeration));
700 QVERIFY(mobj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
701
702 // signature-based property
703 QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::ReadOnly));
704 QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::Undeletable));
705 QVERIFY(!(mobj.propertyFlags("mySlot()") & QScriptValue::SkipInEnumeration));
706 QVERIFY(mobj.propertyFlags("mySlot()") & QScriptValue::QObjectMember);
707 }
708}
709
710void tst_QScriptExtQObject::getSetStaticProperty_changeInCpp()
711{
712 // property change in C++ should be reflected in script
713 m_myObject->setIntProperty(456);
714 QCOMPARE(m_engine->evaluate("myObject.intProperty")
715 .strictlyEquals(QScriptValue(m_engine, 456)), true);
716 m_myObject->setIntProperty(789);
717 QCOMPARE(m_engine->evaluate("myObject.intProperty")
718 .strictlyEquals(QScriptValue(m_engine, 789)), true);
719
720 m_myObject->setVariantProperty(QLatin1String("bar"));
721 QVERIFY(m_engine->evaluate("myObject.variantProperty")
722 .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))));
723 m_myObject->setVariantProperty(42);
724 QCOMPARE(m_engine->evaluate("myObject.variantProperty")
725 .toVariant(), QVariant(42));
726 m_myObject->setVariantProperty(QVariant::fromValue(value: QBrush()));
727 QVERIFY(m_engine->evaluate("myObject.variantProperty").isVariant());
728
729 m_myObject->setStringProperty(QLatin1String("baz"));
730 QCOMPARE(m_engine->evaluate("myObject.stringProperty")
731 .equals(QScriptValue(m_engine, QLatin1String("baz"))), true);
732 m_myObject->setStringProperty(QLatin1String("zab"));
733 QCOMPARE(m_engine->evaluate("myObject.stringProperty")
734 .equals(QScriptValue(m_engine, QLatin1String("zab"))), true);
735}
736
737void tst_QScriptExtQObject::getSetStaticProperty_changeInJS()
738{
739 // property change in script should be reflected in C++
740 QCOMPARE(m_engine->evaluate("myObject.intProperty = 123")
741 .strictlyEquals(QScriptValue(m_engine, 123)), true);
742 QCOMPARE(m_engine->evaluate("myObject.intProperty")
743 .strictlyEquals(QScriptValue(m_engine, 123)), true);
744 QCOMPARE(m_myObject->intProperty(), 123);
745 QCOMPARE(m_engine->evaluate("myObject.intProperty = 'ciao!';"
746 "myObject.intProperty")
747 .strictlyEquals(QScriptValue(m_engine, 0)), true);
748 QCOMPARE(m_myObject->intProperty(), 0);
749 QCOMPARE(m_engine->evaluate("myObject.intProperty = '123';"
750 "myObject.intProperty")
751 .strictlyEquals(QScriptValue(m_engine, 123)), true);
752 QCOMPARE(m_myObject->intProperty(), 123);
753
754 QCOMPARE(m_engine->evaluate("myObject.stringProperty = 'ciao'")
755 .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
756 QCOMPARE(m_engine->evaluate("myObject.stringProperty")
757 .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
758 QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
759 QCOMPARE(m_engine->evaluate("myObject.stringProperty = 123;"
760 "myObject.stringProperty")
761 .strictlyEquals(QScriptValue(m_engine, QLatin1String("123"))), true);
762 QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
763 QVERIFY(m_engine->evaluate("myObject.stringProperty = null;"
764 "myObject.stringProperty")
765 .strictlyEquals(QScriptValue(m_engine, QString())));
766 QCOMPARE(m_myObject->stringProperty(), QString());
767 QVERIFY(m_engine->evaluate("myObject.stringProperty = undefined;"
768 "myObject.stringProperty")
769 .strictlyEquals(QScriptValue(m_engine, QString())));
770 QCOMPARE(m_myObject->stringProperty(), QString());
771
772 QCOMPARE(m_engine->evaluate("myObject.variantProperty = 'foo';"
773 "myObject.variantProperty.valueOf()").toString(), QLatin1String("foo"));
774 QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
775 QVERIFY(m_engine->evaluate("myObject.variantProperty = undefined;"
776 "myObject.variantProperty").isUndefined());
777 QVERIFY(!m_myObject->variantProperty().isValid());
778 QVERIFY(m_engine->evaluate("myObject.variantProperty = null;"
779 "myObject.variantProperty").isUndefined());
780 QVERIFY(!m_myObject->variantProperty().isValid());
781 QCOMPARE(m_engine->evaluate("myObject.variantProperty = 42;"
782 "myObject.variantProperty").toNumber(), 42.0);
783 QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
784
785 QCOMPARE(m_engine->evaluate("myObject.variantListProperty = [1, 'two', true];"
786 "myObject.variantListProperty.length")
787 .strictlyEquals(QScriptValue(m_engine, 3)), true);
788 QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]")
789 .strictlyEquals(QScriptValue(m_engine, 1)), true);
790 QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]")
791 .strictlyEquals(QScriptValue(m_engine, QLatin1String("two"))), true);
792 QCOMPARE(m_engine->evaluate("myObject.variantListProperty[2]")
793 .strictlyEquals(QScriptValue(m_engine, true)), true);
794 {
795 QVariantList vl = qscriptvalue_cast<QVariantList>(value: m_engine->evaluate(program: "myObject.variantListProperty"));
796 QCOMPARE(vl, QVariantList()
797 << QVariant(1)
798 << QVariant(QLatin1String("two"))
799 << QVariant(true));
800 }
801
802 QCOMPARE(m_engine->evaluate("myObject.stringListProperty = [1, 'two', true];"
803 "myObject.stringListProperty.length")
804 .strictlyEquals(QScriptValue(m_engine, 3)), true);
805 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true);
806 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(),
807 QLatin1String("1"));
808 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true);
809 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(),
810 QLatin1String("two"));
811 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").isString(), true);
812 QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").toString(),
813 QLatin1String("true"));
814 {
815 QStringList sl = qscriptvalue_cast<QStringList>(value: m_engine->evaluate(program: "myObject.stringListProperty"));
816 QCOMPARE(sl, QStringList()
817 << QLatin1String("1")
818 << QLatin1String("two")
819 << QLatin1String("true"));
820 }
821}
822
823void tst_QScriptExtQObject::getSetStaticProperty_compatibleVariantTypes()
824{
825 // test setting properties where we can't convert the type natively but where the
826 // types happen to be compatible variant types already
827 {
828 QKeySequence sequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_Delete);
829 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
830
831 QVERIFY(m_myObject->shortcut().isEmpty());
832 mobj.setProperty(name: "shortcut", value: m_engine->newVariant(value: sequence));
833 QVERIFY(m_myObject->shortcut() == sequence);
834 }
835 {
836 CustomType t; t.string = "hello";
837 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
838
839 QVERIFY(m_myObject->propWithCustomType().string.isEmpty());
840 mobj.setProperty(name: "propWithCustomType", value: m_engine->newVariant(value: QVariant::fromValue(value: t)));
841 QVERIFY(m_myObject->propWithCustomType().string == t.string);
842 }
843}
844
845void tst_QScriptExtQObject::getSetStaticProperty_conversion()
846{
847 // test that we do value conversion if necessary when setting properties
848 {
849 QScriptValue br = m_engine->evaluate(program: "myObject.brushProperty");
850 QVERIFY(br.isVariant());
851 QVERIFY(!br.strictlyEquals(m_engine->evaluate("myObject.brushProperty")));
852 QCOMPARE(qscriptvalue_cast<QBrush>(br), m_myObject->brushProperty());
853 QCOMPARE(qscriptvalue_cast<QColor>(br), m_myObject->brushProperty().color());
854
855 QColor newColor(40, 30, 20, 10);
856 QScriptValue val = qScriptValueFromValue(engine: m_engine, t: newColor);
857 m_engine->globalObject().setProperty(name: "myColor", value: val);
858 QScriptValue ret = m_engine->evaluate(program: "myObject.brushProperty = myColor");
859 QCOMPARE(ret.strictlyEquals(val), true);
860 br = m_engine->evaluate(program: "myObject.brushProperty");
861 QCOMPARE(qscriptvalue_cast<QBrush>(br), QBrush(newColor));
862 QCOMPARE(qscriptvalue_cast<QColor>(br), newColor);
863
864 m_engine->globalObject().setProperty(name: "myColor", value: QScriptValue());
865 }
866}
867
868void tst_QScriptExtQObject::getSetStaticProperty_delete()
869{
870 // try to delete
871 QCOMPARE(m_engine->evaluate("delete myObject.intProperty").toBoolean(), false);
872 QCOMPARE(m_engine->evaluate("myObject.intProperty").toNumber(), 123.0);
873
874 m_myObject->setVariantProperty(42);
875 QCOMPARE(m_engine->evaluate("delete myObject.variantProperty").toBoolean(), false);
876 QCOMPARE(m_engine->evaluate("myObject.variantProperty").toNumber(), 42.0);
877}
878
879void tst_QScriptExtQObject::getSetStaticProperty_nonScriptable()
880{
881 // non-scriptable property
882 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
883 QCOMPARE(m_engine->evaluate("myObject.hiddenProperty").isUndefined(), true);
884 QCOMPARE(m_engine->evaluate("myObject.hiddenProperty = 123;"
885 "myObject.hiddenProperty").toInt32(), 123);
886 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
887}
888
889void tst_QScriptExtQObject::getSetStaticProperty_writeOnly()
890{
891 // write-only property
892 QCOMPARE(m_myObject->writeOnlyProperty(), 789);
893 QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty").isUndefined(), true);
894 QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty = 123;"
895 "myObject.writeOnlyProperty").isUndefined(), true);
896 QCOMPARE(m_myObject->writeOnlyProperty(), 123);
897}
898
899void tst_QScriptExtQObject::getSetStaticProperty_readOnly()
900{
901 // read-only property
902 QCOMPARE(m_myObject->readOnlyProperty(), 987);
903 QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty").toInt32(), 987);
904 QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty = 654;"
905 "myObject.readOnlyProperty").toInt32(), 987);
906 QCOMPARE(m_myObject->readOnlyProperty(), 987);
907 {
908 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
909 QCOMPARE(mobj.propertyFlags("readOnlyProperty") & QScriptValue::ReadOnly,
910 QScriptValue::ReadOnly);
911 }
912}
913
914void tst_QScriptExtQObject::getSetStaticProperty_enum()
915{
916 // enum property
917 QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
918 {
919 QScriptValue val = m_engine->evaluate(program: "myObject.enumProperty");
920 QVERIFY(val.isNumber());
921 QCOMPARE(val.toInt32(), int(MyQObject::BarPolicy));
922 }
923 m_engine->evaluate(program: "myObject.enumProperty = 2");
924 QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
925 m_engine->evaluate(program: "myObject.enumProperty = 'BarPolicy'");
926 QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
927 m_engine->evaluate(program: "myObject.enumProperty = 'ScoobyDoo'");
928 QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
929 // enum property with custom conversion
930 qScriptRegisterMetaType<MyQObject::Policy>(eng: m_engine, toScriptValue: policyToScriptValue, fromScriptValue: policyFromScriptValue);
931 m_engine->evaluate(program: "myObject.enumProperty = 'red'");
932 QCOMPARE(m_myObject->enumProperty(), MyQObject::FooPolicy);
933 m_engine->evaluate(program: "myObject.enumProperty = 'green'");
934 QCOMPARE(m_myObject->enumProperty(), MyQObject::BarPolicy);
935 m_engine->evaluate(program: "myObject.enumProperty = 'blue'");
936 QCOMPARE(m_myObject->enumProperty(), MyQObject::BazPolicy);
937 m_engine->evaluate(program: "myObject.enumProperty = 'nada'");
938 QCOMPARE(m_myObject->enumProperty(), (MyQObject::Policy)-1);
939}
940
941void tst_QScriptExtQObject::getSetStaticProperty_qflags()
942{
943 // flags property
944 QCOMPARE(m_myObject->flagsProperty(), MyQObject::FooAbility);
945 {
946 QScriptValue val = m_engine->evaluate(program: "myObject.flagsProperty");
947 QVERIFY(val.isNumber());
948 QCOMPARE(val.toInt32(), int(MyQObject::FooAbility));
949 }
950 m_engine->evaluate(program: "myObject.flagsProperty = 0x80");
951 QCOMPARE(m_myObject->flagsProperty(), MyQObject::BarAbility);
952 m_engine->evaluate(program: "myObject.flagsProperty = 0x81");
953 QCOMPARE(m_myObject->flagsProperty(), MyQObject::Ability(MyQObject::FooAbility | MyQObject::BarAbility));
954 m_engine->evaluate(program: "myObject.flagsProperty = 123"); // bogus values are accepted
955 QCOMPARE(int(m_myObject->flagsProperty()), 123);
956 m_engine->evaluate(program: "myObject.flagsProperty = 'BazAbility'");
957 QCOMPARE(m_myObject->flagsProperty(), MyQObject::BazAbility);
958 m_engine->evaluate(program: "myObject.flagsProperty = 'ScoobyDoo'");
959 QCOMPARE(m_myObject->flagsProperty(), MyQObject::BazAbility);
960}
961
962void tst_QScriptExtQObject::getSetStaticProperty_pointerDeref()
963{
964 // auto-dereferencing of pointers
965 {
966 QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE);
967 QBrush *bp = &b;
968 QScriptValue bpValue = m_engine->newVariant(value: QVariant::fromValue(value: bp));
969 m_engine->globalObject().setProperty(name: "brushPointer", value: bpValue);
970 {
971 QScriptValue ret = m_engine->evaluate(program: "myObject.setBrushProperty(brushPointer)");
972 QCOMPARE(ret.isUndefined(), true);
973 QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
974 }
975 {
976 b = QColor(0xDE, 0xAD, 0xBE, 0xEF);
977 QScriptValue ret = m_engine->evaluate(program: "myObject.brushProperty = brushPointer");
978 QCOMPARE(ret.strictlyEquals(bpValue), true);
979 QCOMPARE(qscriptvalue_cast<QBrush>(m_engine->evaluate("myObject.brushProperty")), b);
980 }
981 m_engine->globalObject().setProperty(name: "brushPointer", value: QScriptValue());
982 }
983}
984
985void tst_QScriptExtQObject::getSetStaticProperty_customGetterSetter()
986{
987 // install custom property getter+setter
988 {
989 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
990 mobj.setProperty(name: "intProperty", value: m_engine->newFunction(signature: getSetProperty),
991 flags: QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
992 QVERIFY(mobj.property("intProperty").toInt32() != 321);
993 mobj.setProperty(name: "intProperty", value: 321);
994 QCOMPARE(mobj.property("intProperty").toInt32(), 321);
995 }
996}
997
998void tst_QScriptExtQObject::getSetStaticProperty_methodPersistence()
999{
1000 // method properties are persistent
1001 {
1002 QScriptValue slot = m_engine->evaluate(program: "myObject.mySlot");
1003 QVERIFY(slot.isFunction());
1004 QScriptValue sameSlot = m_engine->evaluate(program: "myObject.mySlot");
1005 QVERIFY(sameSlot.strictlyEquals(slot));
1006 sameSlot = m_engine->evaluate(program: "myObject['mySlot()']");
1007 QVERIFY(sameSlot.isFunction());
1008 QEXPECT_FAIL("", "QTBUG-17611: Signature-based method lookup creates new function wrapper object", Continue);
1009 QVERIFY(sameSlot.strictlyEquals(slot));
1010 }
1011}
1012
1013void tst_QScriptExtQObject::getSetDynamicProperty()
1014{
1015 // initially the object does not have the property
1016 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
1017 .strictlyEquals(QScriptValue(m_engine, false)), true);
1018
1019 // add a dynamic property in C++
1020 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
1021 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')")
1022 .strictlyEquals(QScriptValue(m_engine, true)), true);
1023 QCOMPARE(m_engine->evaluate("myObject.dynamicProperty")
1024 .strictlyEquals(QScriptValue(m_engine, 123)), true);
1025
1026 // check the flags
1027 {
1028 QScriptValue mobj = m_engine->globalObject().property(name: "myObject");
1029 QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::ReadOnly));
1030 QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::Undeletable));
1031 QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::SkipInEnumeration));
1032 QVERIFY(mobj.propertyFlags("dynamicProperty") & QScriptValue::QObjectMember);
1033 }
1034
1035 // property change in script should be reflected in C++
1036 QCOMPARE(m_engine->evaluate("myObject.dynamicProperty = 'foo';"
1037 "myObject.dynamicProperty")
1038 .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true);
1039 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
1040
1041 // delete the property
1042 QCOMPARE(m_engine->evaluate("delete myObject.dynamicProperty").toBoolean(), true);
1043 QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
1044 QCOMPARE(m_engine->evaluate("myObject.dynamicProperty").isUndefined(), true);
1045 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')").toBoolean(), false);
1046}
1047
1048void tst_QScriptExtQObject::getSetDynamicProperty_deleteFromCpp()
1049{
1050 QScriptValue val = m_engine->newQObject(object: m_myObject);
1051
1052 m_myObject->setProperty(name: "dynamicFromCpp", value: 1234);
1053 QVERIFY(val.property("dynamicFromCpp").strictlyEquals(QScriptValue(m_engine, 1234)));
1054
1055 m_myObject->setProperty(name: "dynamicFromCpp", value: 4321);
1056 QVERIFY(val.property("dynamicFromCpp").strictlyEquals(QScriptValue(m_engine, 4321)));
1057 QCOMPARE(m_myObject->property("dynamicFromCpp").toInt(), 4321);
1058
1059 // In this case we delete the property from C++
1060 m_myObject->setProperty(name: "dynamicFromCpp", value: QVariant());
1061 QVERIFY(!m_myObject->property("dynamicFromCpp").isValid());
1062 QVERIFY(!val.property("dynamicFromCpp").isValid());
1063}
1064
1065void tst_QScriptExtQObject::getSetDynamicProperty_hideChildObject()
1066{
1067 QScriptValue val = m_engine->newQObject(object: m_myObject);
1068
1069 // Add our named child and access it
1070 QObject *child = new QObject(m_myObject);
1071 child->setObjectName("testName");
1072 QCOMPARE(val.property("testName").toQObject(), child);
1073
1074 // Dynamic properties have precedence, hiding the child object
1075 m_myObject->setProperty(name: "testName", value: 42);
1076 QVERIFY(val.property("testName").strictlyEquals(QScriptValue(m_engine, 42)));
1077
1078 // Remove dynamic property
1079 m_myObject->setProperty(name: "testName", value: QVariant());
1080 QCOMPARE(val.property("testName").toQObject(), child);
1081}
1082
1083void tst_QScriptExtQObject::getSetDynamicProperty_setBeforeGet()
1084{
1085 QScriptValue val = m_engine->newQObject(object: m_myObject);
1086
1087 m_myObject->setProperty(name: "dynamic", value: 1111);
1088 val.setProperty(name: "dynamic", value: 42);
1089
1090 QVERIFY(val.property("dynamic").strictlyEquals(QScriptValue(m_engine, 42)));
1091 QCOMPARE(m_myObject->property("dynamic").toInt(), 42);
1092}
1093
1094void tst_QScriptExtQObject::getSetDynamicProperty_doNotHideJSProperty()
1095{
1096 QScriptValue val = m_engine->newQObject(object: m_myObject);
1097
1098 // Set property on JS and dynamically on our QObject
1099 val.setProperty(name: "x", value: 42);
1100 m_myObject->setProperty(name: "x", value: 2222);
1101
1102 QEXPECT_FAIL("", "QTBUG-17612: Dynamic C++ property overrides JS property", Continue);
1103
1104 // JS should see the original JS value
1105 QVERIFY(val.property("x").strictlyEquals(QScriptValue(m_engine, 42)));
1106
1107 // The dynamic property is intact
1108 QCOMPARE(m_myObject->property("x").toInt(), 2222);
1109}
1110
1111void tst_QScriptExtQObject::getSetChildren()
1112{
1113 QScriptValue mobj = m_engine->evaluate(program: "myObject");
1114
1115 // initially the object does not have the child
1116 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
1117 .strictlyEquals(QScriptValue(m_engine, false)), true);
1118
1119 // add a child
1120 MyQObject *child = new MyQObject(m_myObject);
1121 child->setObjectName("child");
1122 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
1123 .strictlyEquals(QScriptValue(m_engine, true)), true);
1124
1125 QVERIFY(mobj.propertyFlags("child") & QScriptValue::ReadOnly);
1126 QVERIFY(mobj.propertyFlags("child") & QScriptValue::Undeletable);
1127 QVERIFY(mobj.propertyFlags("child") & QScriptValue::SkipInEnumeration);
1128 QVERIFY(!(mobj.propertyFlags("child") & QScriptValue::QObjectMember));
1129
1130 {
1131 QScriptValue scriptChild = m_engine->evaluate(program: "myObject.child");
1132 QVERIFY(scriptChild.isQObject());
1133 QCOMPARE(scriptChild.toQObject(), (QObject*)child);
1134 QScriptValue sameChild = m_engine->evaluate(program: "myObject.child");
1135 QVERIFY(sameChild.strictlyEquals(scriptChild));
1136 }
1137
1138 // add a grandchild
1139 MyQObject *grandChild = new MyQObject(child);
1140 grandChild->setObjectName("grandChild");
1141 QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
1142 .strictlyEquals(QScriptValue(m_engine, true)), true);
1143
1144 // delete grandchild
1145 delete grandChild;
1146 QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')")
1147 .strictlyEquals(QScriptValue(m_engine, false)), true);
1148
1149 // delete child
1150 delete child;
1151 QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')")
1152 .strictlyEquals(QScriptValue(m_engine, false)), true);
1153
1154}
1155
1156Q_DECLARE_METATYPE(QVector<int>)
1157Q_DECLARE_METATYPE(QVector<double>)
1158Q_DECLARE_METATYPE(QVector<QString>)
1159
1160template <class T>
1161static QScriptValue qobjectToScriptValue(QScriptEngine *engine, T* const &in)
1162{ return engine->newQObject(in); }
1163
1164template <class T>
1165static void qobjectFromScriptValue(const QScriptValue &object, T* &out)
1166{ out = qobject_cast<T*>(object.toQObject()); }
1167
1168void tst_QScriptExtQObject::callQtInvokable()
1169{
1170 m_myObject->resetQtFunctionInvoked();
1171 QCOMPARE(m_engine->evaluate("myObject.myInvokable()").isUndefined(), true);
1172 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1173 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1174
1175 // extra arguments should silently be ignored
1176 m_myObject->resetQtFunctionInvoked();
1177 QCOMPARE(m_engine->evaluate("myObject.myInvokable(10, 20, 30)").isUndefined(), true);
1178 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1179 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1180
1181 m_myObject->resetQtFunctionInvoked();
1182 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123)").isUndefined(), true);
1183 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1184 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1185 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1186
1187 m_myObject->resetQtFunctionInvoked();
1188 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg('123')").isUndefined(), true);
1189 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1190 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1191 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1192
1193 m_myObject->resetQtFunctionInvoked();
1194 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithLonglongArg(123)").isUndefined(), true);
1195 QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
1196 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1197 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
1198
1199 m_myObject->resetQtFunctionInvoked();
1200 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithFloatArg(123.5)").isUndefined(), true);
1201 QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
1202 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1203 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1204
1205 m_myObject->resetQtFunctionInvoked();
1206 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithDoubleArg(123.5)").isUndefined(), true);
1207 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1208 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1209 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1210
1211 m_myObject->resetQtFunctionInvoked();
1212 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg('ciao')").isUndefined(), true);
1213 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1214 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1215 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
1216
1217 m_myObject->resetQtFunctionInvoked();
1218 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg(123)").isUndefined(), true);
1219 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1220 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1221 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1222
1223 m_myObject->resetQtFunctionInvoked();
1224 QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(null)").isUndefined());
1225 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1226 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1227 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
1228 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1229
1230 m_myObject->resetQtFunctionInvoked();
1231 QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(undefined)").isUndefined());
1232 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1233 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1234 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String);
1235 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1236
1237 m_myObject->resetQtFunctionInvoked();
1238 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArgs(123, 456)").isUndefined(), true);
1239 QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
1240 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1241 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1242 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1243
1244 m_myObject->resetQtFunctionInvoked();
1245 QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningInt()")
1246 .strictlyEquals(QScriptValue(m_engine, 123)), true);
1247 QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
1248 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1249
1250 m_myObject->resetQtFunctionInvoked();
1251 QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningLongLong()")
1252 .strictlyEquals(QScriptValue(m_engine, 456)), true);
1253 QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
1254 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1255
1256 m_myObject->resetQtFunctionInvoked();
1257 QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningString()")
1258 .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true);
1259 QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
1260 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1261
1262 m_myObject->resetQtFunctionInvoked();
1263 QVERIFY(m_engine->evaluate("myObject.myInvokableReturningVariant()")
1264 .strictlyEquals(QScriptValue(m_engine, 123)));
1265 QCOMPARE(m_myObject->qtFunctionInvoked(), 60);
1266
1267 m_myObject->resetQtFunctionInvoked();
1268 QVERIFY(m_engine->evaluate("myObject.myInvokableReturningScriptValue()")
1269 .strictlyEquals(QScriptValue(m_engine, 456)));
1270 QCOMPARE(m_myObject->qtFunctionInvoked(), 61);
1271
1272 m_myObject->resetQtFunctionInvoked();
1273 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123, 456)").isUndefined(), true);
1274 QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
1275 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1276 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1277 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1278}
1279
1280void tst_QScriptExtQObject::callQtInvokable2()
1281{
1282 m_myObject->resetQtFunctionInvoked();
1283 QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined());
1284 QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
1285 m_myObject->resetQtFunctionInvoked();
1286 QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(123)").isError());
1287 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1288
1289 m_myObject->resetQtFunctionInvoked();
1290 {
1291 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithAmbiguousArg(123)");
1292 QVERIFY(ret.isError());
1293 QCOMPARE(ret.toString(), QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
1294 }
1295
1296 m_myObject->resetQtFunctionInvoked();
1297 {
1298 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithDefaultArgs(123, 'hello')");
1299 QVERIFY(ret.isUndefined());
1300 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1301 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1302 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1303 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
1304 }
1305
1306 m_myObject->resetQtFunctionInvoked();
1307 {
1308 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithDefaultArgs(456)");
1309 QVERIFY(ret.isUndefined());
1310 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1311 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1312 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1313 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
1314 }
1315
1316 {
1317 QScriptValue fun = m_engine->evaluate(program: "myObject.myInvokableWithPointArg");
1318 QVERIFY(fun.isFunction());
1319 m_myObject->resetQtFunctionInvoked();
1320 {
1321 QScriptValue ret = fun.call(thisObject: m_engine->evaluate(program: "myObject"),
1322 args: QScriptValueList() << qScriptValueFromValue(engine: m_engine, t: QPoint(10, 20)));
1323 QVERIFY(ret.isUndefined());
1324 QCOMPARE(m_myObject->qtFunctionInvoked(), 50);
1325 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1326 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPoint(), QPoint(10, 20));
1327 }
1328 m_myObject->resetQtFunctionInvoked();
1329 {
1330 QScriptValue ret = fun.call(thisObject: m_engine->evaluate(program: "myObject"),
1331 args: QScriptValueList() << qScriptValueFromValue(engine: m_engine, t: QPointF(30, 40)));
1332 QVERIFY(ret.isUndefined());
1333 QCOMPARE(m_myObject->qtFunctionInvoked(), 51);
1334 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1335 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPointF(), QPointF(30, 40));
1336 }
1337 }
1338
1339 // calling function that returns (const)ref
1340 m_myObject->resetQtFunctionInvoked();
1341 {
1342 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningRef()");
1343 QVERIFY(ret.isUndefined());
1344 QVERIFY(!m_engine->hasUncaughtException());
1345 QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1346 }
1347 m_myObject->resetQtFunctionInvoked();
1348 {
1349 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningConstRef()");
1350 QVERIFY(ret.isUndefined());
1351 QVERIFY(!m_engine->hasUncaughtException());
1352 QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1353 }
1354
1355 // first time we expect failure because the metatype is not registered
1356 m_myObject->resetQtFunctionInvoked();
1357 QCOMPARE(QMetaType::Type(QMetaType::type("QVector<CustomType>")), QMetaType::UnknownType); // this type should not be registered yet
1358 QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningVectorOfCustomType()").isError(), true);
1359 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1360
1361 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithVectorOfCustomTypeArg(CustomType())").isError(), true);
1362 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1363
1364 // now we register it, and it should work
1365 qScriptRegisterSequenceMetaType<QVector<CustomType> >(engine: m_engine);
1366 {
1367 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningVectorOfCustomType()");
1368 QCOMPARE(ret.isArray(), true);
1369 QCOMPARE(m_myObject->qtFunctionInvoked(), 11);
1370 }
1371}
1372
1373void tst_QScriptExtQObject::callQtInvokable3()
1374{
1375 {
1376 qScriptRegisterSequenceMetaType<QVector<CustomType> >(engine: m_engine);
1377 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVectorOfCustomTypeArg(myObject.myInvokableReturningVectorOfCustomType())");
1378 QCOMPARE(ret.isUndefined(), true);
1379 QCOMPARE(m_myObject->qtFunctionInvoked(), 12);
1380 }
1381
1382 m_myObject->resetQtFunctionInvoked();
1383 {
1384 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningQObjectStar()");
1385 QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1386 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1387 QCOMPARE(ret.isQObject(), true);
1388 QCOMPARE(ret.toQObject(), (QObject *)m_myObject);
1389 }
1390
1391 m_myObject->resetQtFunctionInvoked();
1392 {
1393 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQObjectListArg([myObject])");
1394 QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1395 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1396 QCOMPARE(ret.isArray(), true);
1397 QCOMPARE(ret.property(QLatin1String("length"))
1398 .strictlyEquals(QScriptValue(m_engine, 1)), true);
1399 QCOMPARE(ret.property(QLatin1String("0")).isQObject(), true);
1400 QCOMPARE(ret.property(QLatin1String("0")).toQObject(), (QObject *)m_myObject);
1401 }
1402
1403 m_myObject->resetQtFunctionInvoked();
1404 {
1405 m_myObject->setVariantProperty(QVariant(123));
1406 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1407 QVERIFY(ret.isNumber());
1408 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1409 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1410 QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1411 QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
1412 }
1413
1414 m_myObject->resetQtFunctionInvoked();
1415 {
1416 m_myObject->setVariantProperty(QVariant::fromValue(value: QBrush()));
1417 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1418 QVERIFY(ret.isVariant());
1419 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1420 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1421 QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1422 QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1423 }
1424
1425 m_myObject->resetQtFunctionInvoked();
1426 {
1427 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg(123)");
1428 QVERIFY(ret.isNumber());
1429 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1430 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1431 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1432 QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123)));
1433 }
1434
1435 m_myObject->resetQtFunctionInvoked();
1436 {
1437 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg('ciao')");
1438 QVERIFY(ret.isString());
1439 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1440 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1441 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(QString::fromLatin1("ciao")));
1442 QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, QString::fromLatin1("ciao"))));
1443 }
1444
1445 m_myObject->resetQtFunctionInvoked();
1446 {
1447 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg(null)");
1448 QVERIFY(ret.isUndefined()); // invalid QVariant is converted to Undefined
1449 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1450 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1451 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1452 }
1453
1454 m_myObject->resetQtFunctionInvoked();
1455 {
1456 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantArg(undefined)");
1457 QVERIFY(ret.isUndefined());
1458 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1459 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1460 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1461 }
1462
1463 m_engine->globalObject().setProperty(name: "fishy", value: m_engine->newVariant(value: 123));
1464 m_engine->evaluate(program: "myObject.myInvokableWithStringArg(fishy)");
1465
1466 m_myObject->resetQtFunctionInvoked();
1467 {
1468 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })");
1469 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1470 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1471 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1472 QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1473 QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1474 QCOMPARE(vmap.keys().size(), 2);
1475 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1476 QCOMPARE(vmap.value("a"), QVariant(123));
1477 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1478 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1479
1480 QCOMPARE(ret.isObject(), true);
1481 QCOMPARE(ret.property("a").strictlyEquals(QScriptValue(m_engine, 123)), true);
1482 QCOMPARE(ret.property("b").strictlyEquals(QScriptValue(m_engine, "ciao")), true);
1483 }
1484
1485 m_myObject->resetQtFunctionInvoked();
1486 {
1487 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithListOfIntArg([1, 5])");
1488 QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1489 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1490 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1491 QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1492 QList<int> ilst = qvariant_cast<QList<int> >(v);
1493 QCOMPARE(ilst.size(), 2);
1494 QCOMPARE(ilst.at(0), 1);
1495 QCOMPARE(ilst.at(1), 5);
1496
1497 QCOMPARE(ret.isArray(), true);
1498 QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true);
1499 QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true);
1500 }
1501}
1502
1503void tst_QScriptExtQObject::callQtInvokable4()
1504{
1505 m_myObject->resetQtFunctionInvoked();
1506 {
1507 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQObjectStarArg(myObject)");
1508 QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1509 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1510 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1511 QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1512 QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)m_myObject);
1513
1514 QCOMPARE(ret.isQObject(), true);
1515 QCOMPARE(qscriptvalue_cast<QObject*>(ret), (QObject *)m_myObject);
1516 }
1517
1518 m_myObject->resetQtFunctionInvoked();
1519 {
1520 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQWidgetStarArg(null)");
1521 QVERIFY(ret.isNull());
1522 QCOMPARE(m_myObject->qtFunctionInvoked(), 63);
1523 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1524 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1525 QCOMPARE(qvariant_cast<QWidget*>(v), (QObject *)0);
1526 }
1527
1528 m_myObject->resetQtFunctionInvoked();
1529 {
1530 // no implicit conversion from integer to QObject*
1531 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQObjectStarArg(123)");
1532 QCOMPARE(ret.isError(), true);
1533 }
1534
1535 m_myObject->resetQtFunctionInvoked();
1536 {
1537 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithShortArg(123)");
1538 QVERIFY(ret.isNumber());
1539 QCOMPARE(m_myObject->qtFunctionInvoked(), 64);
1540 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1541 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1542 QCOMPARE(v.userType(), int(QMetaType::Short));
1543 QCOMPARE(qvariant_cast<short>(v), short(123));
1544 }
1545
1546 m_myObject->resetQtFunctionInvoked();
1547 {
1548 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithUShortArg(123)");
1549 QVERIFY(ret.isNumber());
1550 QCOMPARE(m_myObject->qtFunctionInvoked(), 65);
1551 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1552 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1553 QCOMPARE(v.userType(), int(QMetaType::UShort));
1554 QCOMPARE(qvariant_cast<ushort>(v), ushort(123));
1555 }
1556
1557 m_myObject->resetQtFunctionInvoked();
1558 {
1559 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithCharArg(123)");
1560 QVERIFY(ret.isNumber());
1561 QCOMPARE(m_myObject->qtFunctionInvoked(), 66);
1562 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1563 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1564 QCOMPARE(v.userType(), int(QMetaType::Char));
1565 QCOMPARE(qvariant_cast<char>(v), char(123));
1566 }
1567
1568 m_myObject->resetQtFunctionInvoked();
1569 {
1570 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithUCharArg(123)");
1571 QVERIFY(ret.isNumber());
1572 QCOMPARE(m_myObject->qtFunctionInvoked(), 67);
1573 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1574 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1575 QCOMPARE(v.userType(), int(QMetaType::UChar));
1576 QCOMPARE(qvariant_cast<uchar>(v), uchar(123));
1577 }
1578
1579 m_myObject->resetQtFunctionInvoked();
1580 {
1581 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithULonglongArg(123)");
1582 QVERIFY(ret.isNumber());
1583 QCOMPARE(m_myObject->qtFunctionInvoked(), 68);
1584 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1585 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1586 QCOMPARE(v.userType(), int(QMetaType::ULongLong));
1587 QCOMPARE(qvariant_cast<qulonglong>(v), qulonglong(123));
1588 }
1589
1590 m_myObject->resetQtFunctionInvoked();
1591 {
1592 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithLongArg(123)");
1593 QCOMPARE(m_myObject->qtFunctionInvoked(), 69);
1594 QVERIFY(ret.isNumber());
1595 QCOMPARE(long(ret.toInteger()), long(123));
1596
1597 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1598 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1599 QCOMPARE(v.userType(), int(QMetaType::Long));
1600 QCOMPARE(qvariant_cast<long>(v), long(123));
1601 }
1602
1603 m_myObject->resetQtFunctionInvoked();
1604 {
1605 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithULongArg(456)");
1606 QCOMPARE(m_myObject->qtFunctionInvoked(), 70);
1607 QVERIFY(ret.isNumber());
1608 QCOMPARE(ulong(ret.toInteger()), ulong(456));
1609
1610 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1611 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1612 QCOMPARE(v.userType(), int(QMetaType::ULong));
1613 QCOMPARE(qvariant_cast<unsigned long>(v), ulong(456));
1614 }
1615}
1616
1617void tst_QScriptExtQObject::callQtInvokable5()
1618{
1619 m_myObject->resetQtFunctionInvoked();
1620 {
1621 QScriptValue fun = m_engine->evaluate(program: "myObject.myInvokableWithQBrushArg");
1622 QVERIFY(fun.isFunction());
1623 QColor color(10, 20, 30, 40);
1624 // QColor should be converted to a QBrush
1625 QScriptValue ret = fun.call(thisObject: QScriptValue(), args: QScriptValueList()
1626 << qScriptValueFromValue(engine: m_engine, t: color));
1627 QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1628 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1629 QVariant v = m_myObject->qtFunctionActuals().at(i: 0);
1630 QCOMPARE(v.userType(), int(QMetaType::QBrush));
1631 QCOMPARE(qvariant_cast<QColor>(v), color);
1632
1633 QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1634 }
1635
1636 // private slots should not be part of the QObject binding
1637 QCOMPARE(m_engine->evaluate("myObject.myPrivateSlot").isUndefined(), true);
1638
1639 // protected slots should be fine
1640 m_myObject->resetQtFunctionInvoked();
1641 m_engine->evaluate(program: "myObject.myProtectedSlot()");
1642 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1643
1644 // call with too few arguments
1645 {
1646 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithIntArg()");
1647 QVERIFY(ret.isError());
1648 QCOMPARE(ret.toString(), QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
1649 }
1650
1651 // call function where not all types have been registered
1652 m_myObject->resetQtFunctionInvoked();
1653 {
1654 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithBrushStyleArg(0)");
1655 QVERIFY(ret.isError());
1656 QCOMPARE(ret.toString(), QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): argument 1 has unknown type `Qt::BrushStyle' (register the type with qScriptRegisterMetaType())"));
1657 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1658 }
1659
1660 // call function with incompatible argument type
1661 m_myObject->resetQtFunctionInvoked();
1662 {
1663 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQBrushArg(null)");
1664 QVERIFY(ret.isError());
1665 QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
1666 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1667 }
1668
1669 // ability to call a slot with QObject-based arguments, even if those types haven't been registered
1670 m_myObject->resetQtFunctionInvoked();
1671 {
1672 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithMyQObjectArg(myObject)");
1673 QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
1674 QVERIFY(ret.isUndefined());
1675 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1676 QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
1677 }
1678
1679 // inability to call a slot returning QObject-based type, when that type hasn't been registered
1680 m_myObject->resetQtFunctionInvoked();
1681 {
1682 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningMyQObject()");
1683 QVERIFY(ret.isError());
1684 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: cannot call myInvokableReturningMyQObject(): unknown return type `MyQObject*' (register the type with qScriptRegisterMetaType())"));
1685 }
1686
1687 // ability to call a slot returning QObject-based type when that type has been registered
1688 qRegisterMetaType<MyQObject*>(typeName: "MyQObject*");
1689 m_myObject->resetQtFunctionInvoked();
1690 {
1691 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningMyQObject()");
1692 QCOMPARE(m_myObject->qtFunctionInvoked(), 53);
1693 QVERIFY(ret.isQObject());
1694 QCOMPARE(*reinterpret_cast<MyQObject* const *>(ret.toVariant().constData()), m_myObject);
1695 }
1696
1697 // ability to call a slot with QObject-based argument, when the argument is const
1698 m_myObject->resetQtFunctionInvoked();
1699 {
1700 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithConstMyQObjectArg(myObject)");
1701 QCOMPARE(m_myObject->qtFunctionInvoked(), 54);
1702 QVERIFY(ret.isUndefined());
1703 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1704 QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
1705 }
1706}
1707
1708void tst_QScriptExtQObject::callQtInvokable6()
1709{
1710 // QScriptValue arguments should be passed on without conversion
1711 m_myObject->resetQtFunctionInvoked();
1712 {
1713 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithScriptValueArg(123)");
1714 QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
1715 QVERIFY(ret.isNumber());
1716 QCOMPARE(ret.toInt32(), 123);
1717 }
1718 m_myObject->resetQtFunctionInvoked();
1719 {
1720 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithScriptValueArg('ciao')");
1721 QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
1722 QVERIFY(ret.isString());
1723 QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
1724 }
1725 m_myObject->resetQtFunctionInvoked();
1726 {
1727 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithScriptValueArg(this)");
1728 QCOMPARE(m_myObject->qtFunctionInvoked(), 56);
1729 QVERIFY(ret.isObject());
1730 QVERIFY(ret.strictlyEquals(m_engine->globalObject()));
1731 }
1732
1733 // the prototype specified by a conversion function should not be "down-graded"
1734 m_myObject->resetQtFunctionInvoked();
1735 {
1736 QScriptValue qobjectProto = m_engine->newObject();
1737 qScriptRegisterMetaType<QObject*>(eng: m_engine, toScriptValue: qobjectToScriptValue,
1738 fromScriptValue: qobjectFromScriptValue, prototype: qobjectProto);
1739 QScriptValue myQObjectProto = m_engine->newObject();
1740 myQObjectProto.setPrototype(qobjectProto);
1741 qScriptRegisterMetaType<MyQObject*>(eng: m_engine, toScriptValue: qobjectToScriptValue,
1742 fromScriptValue: qobjectFromScriptValue, prototype: myQObjectProto);
1743 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningMyQObjectAsQObject()");
1744 QCOMPARE(m_myObject->qtFunctionInvoked(), 57);
1745 QVERIFY(ret.isQObject());
1746 QVERIFY(ret.prototype().strictlyEquals(myQObjectProto));
1747
1748 qScriptRegisterMetaType<QObject*>(eng: m_engine, toScriptValue: 0, fromScriptValue: 0, prototype: QScriptValue());
1749 qScriptRegisterMetaType<MyQObject*>(eng: m_engine, toScriptValue: 0, fromScriptValue: 0, prototype: QScriptValue());
1750 }
1751
1752 // detect exceptions during argument conversion
1753 m_myObject->resetQtFunctionInvoked();
1754 {
1755 QScriptValue (*dummy)(QScriptEngine *, const QDir &) = 0;
1756 qScriptRegisterMetaType<QDir>(eng: m_engine, toScriptValue: dummy, fromScriptValue: dirFromScript);
1757 {
1758 QVERIFY(!m_engine->hasUncaughtException());
1759 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQDirArg({})");
1760 QVERIFY(m_engine->hasUncaughtException());
1761 QVERIFY(ret.isError());
1762 QCOMPARE(ret.toString(), QString::fromLatin1("Error: No path"));
1763 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1764 }
1765 m_engine->clearExceptions();
1766 {
1767 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQDirArg({path:'.'})");
1768 QVERIFY(!m_engine->hasUncaughtException());
1769 QVERIFY(ret.isUndefined());
1770 QCOMPARE(m_myObject->qtFunctionInvoked(), 55);
1771 }
1772 }
1773}
1774
1775void tst_QScriptExtQObject::callQtInvokable7()
1776{
1777 // qscript_call()
1778 {
1779 m_myObject->resetQtFunctionInvoked();
1780 QScriptValue ret = m_engine->evaluate(program: "new myObject(123)");
1781 QVERIFY(ret.isError());
1782 QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
1783 }
1784 {
1785 m_myObject->resetQtFunctionInvoked();
1786 QScriptValue ret = m_engine->evaluate(program: "myObject(123)");
1787 QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
1788 }
1789
1790 // task 233624
1791 {
1792 MyNS::A a;
1793 m_engine->globalObject().setProperty(name: "anObject", value: m_engine->newQObject(object: &a));
1794 QScriptValue ret = m_engine->evaluate(program: "anObject.slotTakingScopedEnumArg(1)");
1795 QVERIFY(!ret.isError());
1796 QVERIFY(ret.isNumber());
1797 QCOMPARE(ret.toInt32(), 1);
1798 m_engine->globalObject().setProperty(name: "anObject", value: QScriptValue());
1799 }
1800
1801 // virtual slot redeclared in subclass (task 236467)
1802 {
1803 MyOtherQObject moq;
1804 m_engine->globalObject().setProperty(name: "myOtherQObject", value: m_engine->newQObject(object: &moq));
1805 moq.resetQtFunctionInvoked();
1806 QScriptValue ret = m_engine->evaluate(program: "myOtherQObject.myVirtualSlot(123)");
1807 QCOMPARE(moq.qtFunctionInvoked(), 59);
1808 QVERIFY(!ret.isError());
1809 QVERIFY(ret.isNumber());
1810 QCOMPARE(ret.toInt32(), 123);
1811 }
1812}
1813
1814void tst_QScriptExtQObject::connectAndDisconnect()
1815{
1816 // connect(function)
1817 QCOMPARE(m_engine->evaluate("myObject.mySignal.connect(123)").isError(), true);
1818
1819 m_engine->evaluate(program: "myHandler = function() { global.gotSignal = true; global.signalArgs = arguments; global.slotThisObject = this; }");
1820
1821 m_myObject->clearConnectNotifySignals();
1822 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myHandler)").isUndefined());
1823 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignal)));
1824
1825 m_engine->evaluate(program: "gotSignal = false");
1826 m_engine->evaluate(program: "myObject.mySignal()");
1827 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1828 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
1829 QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->globalObject()));
1830
1831 m_engine->evaluate(program: "gotSignal = false");
1832 m_myObject->emitMySignal();
1833 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1834 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
1835
1836 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myHandler)").isUndefined());
1837
1838 m_engine->evaluate(program: "gotSignal = false");
1839 m_myObject->emitMySignalWithIntArg(arg: 123);
1840 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1841 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1842 QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
1843
1844 m_myObject->clearDisconnectNotifySignals();
1845 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isUndefined());
1846 QVERIFY(m_myObject->hasSingleDisconnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignal)));
1847
1848 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isError());
1849
1850 QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
1851 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myHandler)").isUndefined());
1852
1853 m_engine->evaluate(program: "gotSignal = false");
1854 m_myObject->emitMySignal2(arg: false);
1855 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1856 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1857 QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), false);
1858
1859 m_engine->evaluate(program: "gotSignal = false");
1860 QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined());
1861 m_myObject->emitMySignal2(arg: true);
1862 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1863 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1864 QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), true);
1865
1866 QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myHandler)").isUndefined());
1867
1868 QVERIFY(m_engine->evaluate("myObject['mySignal2()'].connect(myHandler)").isUndefined());
1869
1870 m_engine->evaluate(program: "gotSignal = false");
1871 m_myObject->emitMySignal2();
1872 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1873
1874 QVERIFY(m_engine->evaluate("myObject['mySignal2()'].disconnect(myHandler)").isUndefined());
1875
1876 // connecting to signal with default args should pick the most generic version (i.e. with all args)
1877 m_myObject->clearConnectNotifySignals();
1878 QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.connect(myHandler)").isUndefined());
1879 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithDefaultArg)));
1880 m_engine->evaluate(program: "gotSignal = false");
1881 m_myObject->emitMySignalWithDefaultArgWithArg(arg: 456);
1882 QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
1883 QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
1884 QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 456);
1885
1886 m_engine->evaluate(program: "gotSignal = false");
1887 m_myObject->emitMySignalWithDefaultArg();
1888 QVERIFY(m_engine->evaluate("gotSignal").toBoolean());
1889 QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1);
1890 QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 123);
1891
1892 QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.disconnect(myHandler)").isUndefined());
1893
1894 m_engine->evaluate(program: "gotSignal = false");
1895 // connecting to overloaded signal should throw an error
1896 {
1897 QScriptValue ret = m_engine->evaluate(program: "myObject.myOverloadedSignal.connect(myHandler)");
1898 QVERIFY(ret.isError());
1899 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOverloadedSignal(); candidates are\n"
1900 " myOverloadedSignal(int)\n"
1901 " myOverloadedSignal(QString)\n"
1902 "Use e.g. object['myOverloadedSignal(QString)'].connect() to connect to a particular overload"));
1903 }
1904 m_myObject->emitMyOverloadedSignal(arg: 123);
1905 QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
1906 m_myObject->emitMyOverloadedSignal(arg: "ciao");
1907 QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
1908
1909 m_engine->evaluate(program: "gotSignal = false");
1910 {
1911 QScriptValue ret = m_engine->evaluate(program: "myObject.myOtherOverloadedSignal.connect(myHandler)");
1912 QVERIFY(ret.isError());
1913 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOtherOverloadedSignal(); candidates are\n"
1914 " myOtherOverloadedSignal(QString)\n"
1915 " myOtherOverloadedSignal(int)\n"
1916 "Use e.g. object['myOtherOverloadedSignal(int)'].connect() to connect to a particular overload"));
1917 }
1918 m_myObject->emitMyOtherOverloadedSignal(arg: "ciao");
1919 QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
1920 m_myObject->emitMyOtherOverloadedSignal(arg: 123);
1921 QVERIFY(!m_engine->evaluate("gotSignal").toBoolean());
1922
1923 // signal with QVariant arg: argument conversion should work
1924 m_myObject->clearConnectNotifySignals();
1925 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.connect(myHandler)").isUndefined());
1926 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithVariantArg)));
1927 m_engine->evaluate(program: "gotSignal = false");
1928 m_myObject->emitMySignalWithVariantArg(arg: 123);
1929 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1930 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1931 QVERIFY(m_engine->evaluate("signalArgs[0]").isNumber());
1932 QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0);
1933 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.disconnect(myHandler)").isUndefined());
1934
1935 // signal with argument type that's unknown to the meta-type system
1936 m_myObject->clearConnectNotifySignals();
1937 QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.connect(myHandler)").isUndefined());
1938 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithScriptEngineArg)));
1939 m_engine->evaluate(program: "gotSignal = false");
1940 QTest::ignoreMessage(type: QtWarningMsg, message: "QScriptEngine: Unable to handle unregistered datatype 'QScriptEngine*' when invoking handler of signal MyQObject::mySignalWithScriptEngineArg(QScriptEngine*)");
1941 m_myObject->emitMySignalWithScriptEngineArg(arg: m_engine);
1942 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1943 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1944 QVERIFY(m_engine->evaluate("signalArgs[0]").isUndefined());
1945 QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.disconnect(myHandler)").isUndefined());
1946
1947 // signal with QVariant arg: QVariant should be unwrapped only once
1948 m_myObject->clearConnectNotifySignals();
1949 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.connect(myHandler)").isUndefined());
1950 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithVariantArg)));
1951 m_engine->evaluate(program: "gotSignal = false");
1952 QVariant tmp(123);
1953 QVariant signalArg(QMetaType::QVariant, &tmp);
1954 m_myObject->emitMySignalWithVariantArg(arg: signalArg);
1955 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1956 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1957 QVERIFY(m_engine->evaluate("signalArgs[0]").isVariant());
1958 QCOMPARE(m_engine->evaluate("signalArgs[0]").toVariant().toDouble(), 123.0);
1959 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.disconnect(myHandler)").isUndefined());
1960
1961 // signal with QVariant arg: with an invalid QVariant
1962 m_myObject->clearConnectNotifySignals();
1963 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.connect(myHandler)").isUndefined());
1964 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithVariantArg)));
1965 m_engine->evaluate(program: "gotSignal = false");
1966 m_myObject->emitMySignalWithVariantArg(arg: QVariant());
1967 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1968 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1969 QVERIFY(m_engine->evaluate("signalArgs[0]").isUndefined());
1970 QVERIFY(m_engine->evaluate("myObject.mySignalWithVariantArg.disconnect(myHandler)").isUndefined());
1971
1972 // signal with argument type that's unknown to the meta-type system
1973 m_myObject->clearConnectNotifySignals();
1974 QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.connect(myHandler)").isUndefined());
1975 QVERIFY(m_myObject->hasSingleConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignalWithScriptEngineArg)));
1976 m_engine->evaluate(program: "gotSignal = false");
1977 QTest::ignoreMessage(type: QtWarningMsg, message: "QScriptEngine: Unable to handle unregistered datatype 'QScriptEngine*' when invoking handler of signal MyQObject::mySignalWithScriptEngineArg(QScriptEngine*)");
1978 m_myObject->emitMySignalWithScriptEngineArg(arg: m_engine);
1979 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1980 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
1981 QVERIFY(m_engine->evaluate("signalArgs[0]").isUndefined());
1982 QVERIFY(m_engine->evaluate("myObject.mySignalWithScriptEngineArg.disconnect(myHandler)").isUndefined());
1983
1984 // connect(object, function)
1985 m_engine->evaluate(program: "otherObject = { name:'foo' }");
1986 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
1987 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
1988 m_engine->evaluate(program: "gotSignal = false");
1989 m_myObject->emitMySignal();
1990 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), false);
1991
1992 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isError());
1993
1994 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined());
1995 m_engine->evaluate(program: "gotSignal = false");
1996 m_myObject->emitMySignal();
1997 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
1998 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0);
1999 QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("otherObject")));
2000 QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("foo"));
2001 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined());
2002
2003 m_engine->evaluate(program: "yetAnotherObject = { name:'bar', func : function() { } }");
2004 QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(yetAnotherObject, myHandler)").isUndefined());
2005 m_engine->evaluate(program: "gotSignal = false");
2006 m_myObject->emitMySignal2(arg: true);
2007 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
2008 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
2009 QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("yetAnotherObject")));
2010 QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("bar"));
2011 QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)").isUndefined());
2012
2013 QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myObject, myHandler)").isUndefined());
2014 m_engine->evaluate(program: "gotSignal = false");
2015 m_myObject->emitMySignal2(arg: true);
2016 QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true);
2017 QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0);
2018 QCOMPARE(m_engine->evaluate("slotThisObject").toQObject(), (QObject *)m_myObject);
2019 QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myObject, myHandler)").isUndefined());
2020
2021 // connect(obj, string)
2022 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(yetAnotherObject, 'func')").isUndefined());
2023 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject, 'mySlot')").isUndefined());
2024 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(yetAnotherObject, 'func')").isUndefined());
2025 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject, 'mySlot')").isUndefined());
2026}
2027
2028void tst_QScriptExtQObject::connectAndDisconnect_emitFromJS()
2029{
2030 // no arguments
2031 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
2032 m_myObject->resetQtFunctionInvoked();
2033 QCOMPARE(m_engine->evaluate("myObject.mySignal()").isUndefined(), true);
2034 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
2035 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject.mySlot)").isUndefined());
2036
2037 // one argument
2038 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)").isUndefined());
2039 m_myObject->resetQtFunctionInvoked();
2040 QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
2041 QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
2042 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2043 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
2044 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)").isUndefined());
2045
2046 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)").isUndefined());
2047 m_myObject->resetQtFunctionInvoked();
2048 QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
2049 QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
2050 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2051 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
2052 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)").isUndefined());
2053
2054 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)").isUndefined());
2055 m_myObject->resetQtFunctionInvoked();
2056 QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
2057 QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
2058 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2059 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
2060 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)").isUndefined());
2061
2062 // connecting to overloaded slot
2063 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)").isUndefined());
2064 m_myObject->resetQtFunctionInvoked();
2065 QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true);
2066 QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
2067 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2068 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
2069 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)").isUndefined());
2070
2071 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])").isUndefined());
2072 m_myObject->resetQtFunctionInvoked();
2073 QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(456)").isUndefined(), true);
2074 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
2075 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2076 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
2077 QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])").isUndefined());
2078}
2079
2080void tst_QScriptExtQObject::connectAndDisconnect_senderWrapperCollected()
2081{
2082 // when the wrapper dies, the connection stays alive
2083 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
2084 m_myObject->resetQtFunctionInvoked();
2085 m_myObject->emitMySignal();
2086 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
2087 m_engine->evaluate(program: "myObject = null");
2088 m_engine->collectGarbage();
2089 m_myObject->resetQtFunctionInvoked();
2090 m_myObject->emitMySignal();
2091 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
2092}
2093
2094void tst_QScriptExtQObject::connectAndDisconnectWithBadArgs()
2095{
2096 {
2097 QScriptValue ret = m_engine->evaluate(program: "(function() { }).connect()");
2098 QVERIFY(ret.isError());
2099 QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
2100 }
2101 {
2102 QScriptValue ret = m_engine->evaluate(program: "var o = { }; o.connect = Function.prototype.connect; o.connect()");
2103 QVERIFY(ret.isError());
2104 QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given"));
2105 }
2106
2107 {
2108 QScriptValue ret = m_engine->evaluate(program: "(function() { }).connect(123)");
2109 QVERIFY(ret.isError());
2110 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
2111 }
2112 {
2113 QScriptValue ret = m_engine->evaluate(program: "var o = { }; o.connect = Function.prototype.connect; o.connect(123)");
2114 QVERIFY(ret.isError());
2115 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal"));
2116 }
2117
2118 {
2119 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokable.connect(123)");
2120 QVERIFY(ret.isError());
2121 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
2122 }
2123 {
2124 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokable.connect(function() { })");
2125 QVERIFY(ret.isError());
2126 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal"));
2127 }
2128
2129 {
2130 QScriptValue ret = m_engine->evaluate(program: "myObject.mySignal.connect(123)");
2131 QVERIFY(ret.isError());
2132 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: target is not a function"));
2133 }
2134
2135 {
2136 QScriptValue ret = m_engine->evaluate(program: "(function() { }).disconnect()");
2137 QVERIFY(ret.isError());
2138 QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
2139 }
2140 {
2141 QScriptValue ret = m_engine->evaluate(program: "var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect()");
2142 QVERIFY(ret.isError());
2143 QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given"));
2144 }
2145
2146 {
2147 QScriptValue ret = m_engine->evaluate(program: "(function() { }).disconnect(123)");
2148 QVERIFY(ret.isError());
2149 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
2150 }
2151 {
2152 QScriptValue ret = m_engine->evaluate(program: "var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect(123)");
2153 QVERIFY(ret.isError());
2154 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal"));
2155 }
2156
2157 {
2158 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokable.disconnect(123)");
2159 QVERIFY(ret.isError());
2160 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
2161 }
2162 {
2163 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokable.disconnect(function() { })");
2164 QVERIFY(ret.isError());
2165 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal"));
2166 }
2167
2168 {
2169 QScriptValue ret = m_engine->evaluate(program: "myObject.mySignal.disconnect(123)");
2170 QVERIFY(ret.isError());
2171 QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: target is not a function"));
2172 }
2173
2174 {
2175 QScriptValue ret = m_engine->evaluate(program: "myObject.mySignal.disconnect(function() { })");
2176 QVERIFY(ret.isError());
2177 QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: failed to disconnect from MyQObject::mySignal()"));
2178 }
2179}
2180
2181void tst_QScriptExtQObject::connectAndDisconnect_senderDeleted()
2182{
2183 QScriptEngine eng;
2184 QObject *obj = new QObject;
2185 eng.globalObject().setProperty(name: "obj", value: eng.newQObject(object: obj));
2186 eng.evaluate(program: "signal = obj.destroyed");
2187 delete obj;
2188 {
2189 QScriptValue ret = eng.evaluate(program: "signal.connect(function(){})");
2190 QVERIFY(ret.isError());
2191 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Function.prototype.connect: cannot connect to deleted QObject"));
2192 }
2193 {
2194 QScriptValue ret = eng.evaluate(program: "signal.disconnect(function(){})");
2195 QVERIFY(ret.isError());
2196 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Function.prototype.discconnect: cannot disconnect from deleted QObject"));
2197 }
2198}
2199
2200void tst_QScriptExtQObject::cppConnectAndDisconnect()
2201{
2202 QScriptEngine eng;
2203 QLineEdit edit;
2204 QLineEdit edit2;
2205 QScriptValue fun = eng.evaluate(program: "function fun(text) { signalObject = this; signalArg = text; }; fun");
2206 QVERIFY(fun.isFunction());
2207 for (int z = 0; z < 2; ++z) {
2208 QScriptValue receiver;
2209 if (z == 0)
2210 receiver = QScriptValue();
2211 else
2212 receiver = eng.newObject();
2213 for (int y = 0; y < 2; ++y) {
2214 QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
2215 QVERIFY(qScriptConnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
2216 // check signal emission
2217 for (int x = 0; x < 4; ++x) {
2218 QLineEdit *ed = (x < 2) ? &edit : &edit2;
2219 ed->setText((x % 2) ? "foo" : "bar");
2220 {
2221 QScriptValue ret = eng.globalObject().property(name: "signalObject");
2222 if (receiver.isObject())
2223 QVERIFY(ret.strictlyEquals(receiver));
2224 else
2225 QVERIFY(ret.strictlyEquals(eng.globalObject()));
2226 }
2227 {
2228 QScriptValue ret = eng.globalObject().property(name: "signalArg");
2229 QVERIFY(ret.isString());
2230 QCOMPARE(ret.toString(), ed->text());
2231 }
2232 eng.collectGarbage();
2233 }
2234
2235 // check disconnect
2236 QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
2237 eng.globalObject().setProperty(name: "signalObject", value: QScriptValue());
2238 eng.globalObject().setProperty(name: "signalArg", value: QScriptValue());
2239 edit.setText("something else");
2240 QVERIFY(!eng.globalObject().property("signalObject").isValid());
2241 QVERIFY(!eng.globalObject().property("signalArg").isValid());
2242 QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun));
2243
2244 // other object's connection should remain
2245 edit2.setText(edit.text());
2246 {
2247 QScriptValue ret = eng.globalObject().property(name: "signalObject");
2248 if (receiver.isObject())
2249 QVERIFY(ret.strictlyEquals(receiver));
2250 else
2251 QVERIFY(ret.strictlyEquals(eng.globalObject()));
2252 }
2253 {
2254 QScriptValue ret = eng.globalObject().property(name: "signalArg");
2255 QVERIFY(ret.isString());
2256 QCOMPARE(ret.toString(), edit2.text());
2257 }
2258
2259 // disconnect other object too
2260 QVERIFY(qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
2261 eng.globalObject().setProperty(name: "signalObject", value: QScriptValue());
2262 eng.globalObject().setProperty(name: "signalArg", value: QScriptValue());
2263 edit2.setText("even more different");
2264 QVERIFY(!eng.globalObject().property("signalObject").isValid());
2265 QVERIFY(!eng.globalObject().property("signalArg").isValid());
2266 QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
2267 }
2268 }
2269}
2270
2271void tst_QScriptExtQObject::cppConnectAndDisconnect2()
2272{
2273 QScriptEngine eng;
2274 QLineEdit edit;
2275 QLineEdit edit2;
2276 QScriptValue fun = eng.evaluate(program: "function fun(text) { signalObject = this; signalArg = text; }; fun");
2277 // make sure we don't crash when engine is deleted
2278 {
2279 QScriptEngine *eng2 = new QScriptEngine;
2280 QScriptValue fun2 = eng2->evaluate(program: "(function(text) { signalObject = this; signalArg = text; })");
2281 QVERIFY(fun2.isFunction());
2282 QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
2283 delete eng2;
2284 edit.setText("ciao");
2285 QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2));
2286 }
2287
2288 // mixing script-side and C++-side connect
2289 {
2290 eng.globalObject().setProperty(name: "edit", value: eng.newQObject(object: &edit));
2291 QVERIFY(eng.evaluate("edit.textChanged.connect(fun)").isUndefined());
2292 QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
2293
2294 QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
2295 QVERIFY(eng.evaluate("edit.textChanged.disconnect(fun)").isUndefined());
2296 }
2297
2298 // signalHandlerException()
2299 {
2300 connect(sender: &eng, SIGNAL(signalHandlerException(QScriptValue)),
2301 receiver: this, SLOT(onSignalHandlerException(QScriptValue)));
2302
2303 eng.globalObject().setProperty(name: "edit", value: eng.newQObject(object: &edit));
2304 QScriptValue fun = eng.evaluate(program: "(function() { nonExistingFunction(); })");
2305 QVERIFY(fun.isFunction());
2306 QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
2307
2308 m_signalHandlerException = QScriptValue();
2309 QScriptValue ret = eng.evaluate(program: "edit.text = 'trigger a signal handler exception from script'");
2310 QVERIFY(ret.isError());
2311 QVERIFY(m_signalHandlerException.strictlyEquals(ret));
2312
2313 m_signalHandlerException = QScriptValue();
2314 edit.setText("trigger a signal handler exception from C++");
2315 QVERIFY(m_signalHandlerException.isError());
2316
2317 QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun));
2318
2319 m_signalHandlerException = QScriptValue();
2320 eng.evaluate(program: "edit.text = 'no more exception from script'");
2321 QVERIFY(!m_signalHandlerException.isValid());
2322 edit.setText("no more exception from C++");
2323 QVERIFY(!m_signalHandlerException.isValid());
2324
2325 disconnect(sender: &eng, SIGNAL(signalHandlerException(QScriptValue)),
2326 receiver: this, SLOT(onSignalHandlerException(QScriptValue)));
2327 }
2328
2329 // check that connectNotify() and disconnectNotify() are called (task 232987)
2330 {
2331 m_myObject->clearConnectNotifySignals();
2332 QVERIFY(qScriptConnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
2333 QCOMPARE(m_myObject->connectNotifySignals().size(), 2);
2334 QVERIFY(m_myObject->hasConnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignal)));
2335 // We get a destroyed() connection as well, used internally by Qt Script
2336 QVERIFY(m_myObject->hasConnectNotifySignal(QMetaMethod::fromSignal(&QObject::destroyed)));
2337
2338 m_myObject->clearDisconnectNotifySignals();
2339 QVERIFY(qScriptDisconnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun));
2340 QVERIFY(m_myObject->hasSingleDisconnectNotifySignal(QMetaMethod::fromSignal(&MyQObject::mySignal)));
2341 }
2342
2343 // bad args
2344 QVERIFY(!qScriptConnect(0, SIGNAL(foo()), QScriptValue(), fun));
2345 QVERIFY(!qScriptConnect(&edit, 0, QScriptValue(), fun));
2346 QVERIFY(!qScriptConnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
2347 QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
2348 QVERIFY(!qScriptDisconnect(0, SIGNAL(foo()), QScriptValue(), fun));
2349 QVERIFY(!qScriptDisconnect(&edit, 0, QScriptValue(), fun));
2350 QVERIFY(!qScriptDisconnect(&edit, SIGNAL(foo()), QScriptValue(), fun));
2351 QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), QScriptValue(), QScriptValue()));
2352 {
2353 QScriptEngine eng2;
2354 QScriptValue receiverInDifferentEngine = eng2.newObject();
2355 QVERIFY(!qScriptConnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
2356 QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(QString)), receiverInDifferentEngine, fun));
2357 }
2358}
2359
2360void tst_QScriptExtQObject::classEnums()
2361{
2362 QScriptValue myClass = m_engine->newQMetaObject(metaObject: m_myObject->metaObject(), ctor: m_engine->undefinedValue());
2363 m_engine->globalObject().setProperty(name: "MyQObject", value: myClass);
2364
2365 QVERIFY(m_engine->evaluate("MyQObject.FooPolicy").isNumber()); // no strong typing
2366 QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.FooPolicy").toInt32()),
2367 MyQObject::FooPolicy);
2368 QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BarPolicy").toInt32()),
2369 MyQObject::BarPolicy);
2370 QCOMPARE(static_cast<MyQObject::Policy>(m_engine->evaluate("MyQObject.BazPolicy").toInt32()),
2371 MyQObject::BazPolicy);
2372
2373 QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.FooStrategy").toInt32()),
2374 MyQObject::FooStrategy);
2375 QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BarStrategy").toInt32()),
2376 MyQObject::BarStrategy);
2377 QCOMPARE(static_cast<MyQObject::Strategy>(m_engine->evaluate("MyQObject.BazStrategy").toInt32()),
2378 MyQObject::BazStrategy);
2379
2380 QVERIFY(m_engine->evaluate("MyQObject.NoAbility").isNumber()); // no strong typing
2381 QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.NoAbility").toInt32()),
2382 MyQObject::NoAbility);
2383 QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.FooAbility").toInt32()),
2384 MyQObject::FooAbility);
2385 QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BarAbility").toInt32()),
2386 MyQObject::BarAbility);
2387 QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BazAbility").toInt32()),
2388 MyQObject::BazAbility);
2389 QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.AllAbility").toInt32()),
2390 MyQObject::AllAbility);
2391
2392 // Constructors for flags are not provided
2393 QVERIFY(m_engine->evaluate("MyQObject.Ability").isUndefined());
2394
2395 QScriptValue::PropertyFlags expectedEnumFlags = QScriptValue::ReadOnly | QScriptValue::Undeletable;
2396 QCOMPARE(myClass.propertyFlags("FooPolicy"), expectedEnumFlags);
2397 QCOMPARE(myClass.propertyFlags("BarPolicy"), expectedEnumFlags);
2398 QCOMPARE(myClass.propertyFlags("BazPolicy"), expectedEnumFlags);
2399
2400 // enums from Qt are inherited through prototype
2401 QCOMPARE(static_cast<Qt::FocusPolicy>(m_engine->evaluate("MyQObject.StrongFocus").toInt32()),
2402 Qt::StrongFocus);
2403 QCOMPARE(static_cast<Qt::Key>(m_engine->evaluate("MyQObject.Key_Left").toInt32()),
2404 Qt::Key_Left);
2405
2406 QCOMPARE(m_engine->evaluate("MyQObject.className()").toString(), QLatin1String("MyQObject"));
2407
2408 qRegisterMetaType<MyQObject::Policy>(typeName: "Policy");
2409
2410 m_myObject->resetQtFunctionInvoked();
2411 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
2412 QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
2413 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2414 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
2415
2416 m_myObject->resetQtFunctionInvoked();
2417 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg('BarPolicy')").isUndefined(), true);
2418 QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
2419 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2420 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BarPolicy));
2421
2422 m_myObject->resetQtFunctionInvoked();
2423 QVERIFY(m_engine->evaluate("myObject.myInvokableWithEnumArg('NoSuchPolicy')").isError());
2424 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
2425
2426 m_myObject->resetQtFunctionInvoked();
2427 QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true);
2428 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
2429 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2430 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
2431
2432 m_myObject->resetQtFunctionInvoked();
2433 {
2434 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningEnum()");
2435 QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
2436 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
2437 QCOMPARE(ret.isVariant(), true);
2438 }
2439 m_myObject->resetQtFunctionInvoked();
2440 {
2441 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableReturningQualifiedEnum()");
2442 QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
2443 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
2444 QCOMPARE(ret.isNumber(), true);
2445 }
2446
2447 m_myObject->resetQtFunctionInvoked();
2448 {
2449 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithFlagsArg(MyQObject.FooAbility)");
2450 QCOMPARE(m_myObject->qtFunctionInvoked(), 58);
2451 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2452 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::FooAbility));
2453 QCOMPARE(ret.isNumber(), true);
2454 QCOMPARE(ret.toInt32(), int(MyQObject::FooAbility));
2455 }
2456 m_myObject->resetQtFunctionInvoked();
2457 {
2458 QScriptValue ret = m_engine->evaluate(program: "myObject.myInvokableWithQualifiedFlagsArg(MyQObject.BarAbility)");
2459 QCOMPARE(m_myObject->qtFunctionInvoked(), 59);
2460 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2461 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BarAbility));
2462 QCOMPARE(ret.isNumber(), true);
2463 QCOMPARE(ret.toInt32(), int(MyQObject::BarAbility));
2464 }
2465
2466 // enum properties are not deletable or writable
2467 QVERIFY(!m_engine->evaluate("delete MyQObject.BazPolicy").toBool());
2468 myClass.setProperty(name: "BazPolicy", value: QScriptValue());
2469 QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
2470 MyQObject::BazPolicy);
2471 myClass.setProperty(name: "BazPolicy", value: MyQObject::FooPolicy);
2472 QCOMPARE(static_cast<MyQObject::Policy>(myClass.property("BazPolicy").toInt32()),
2473 MyQObject::BazPolicy);
2474}
2475
2476QT_BEGIN_NAMESPACE
2477Q_SCRIPT_DECLARE_QMETAOBJECT(MyQObject, QObject*)
2478Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
2479QT_END_NAMESPACE
2480
2481class ConstructorTest : public QObject
2482{
2483 Q_OBJECT
2484public:
2485 Q_INVOKABLE ConstructorTest(QObject *parent)
2486 : QObject(parent)
2487 {
2488 setProperty(name: "ctorIndex", value: 0);
2489 }
2490 Q_INVOKABLE ConstructorTest(int arg, QObject *parent = 0)
2491 : QObject(parent)
2492 {
2493 setProperty(name: "ctorIndex", value: 1);
2494 setProperty(name: "arg", value: arg);
2495 }
2496 Q_INVOKABLE ConstructorTest(const QString &arg, QObject *parent = 0)
2497 : QObject(parent)
2498 {
2499 setProperty(name: "ctorIndex", value: 2);
2500 setProperty(name: "arg", value: arg);
2501 }
2502 Q_INVOKABLE ConstructorTest(int arg, const QString &arg2, QObject *parent = 0)
2503 : QObject(parent)
2504 {
2505 setProperty(name: "ctorIndex", value: 3);
2506 setProperty(name: "arg", value: arg);
2507 setProperty(name: "arg2", value: arg2);
2508 }
2509 Q_INVOKABLE ConstructorTest(const QBrush &arg, QObject *parent = 0)
2510 : QObject(parent)
2511 {
2512 setProperty(name: "ctorIndex", value: 4);
2513 setProperty(name: "arg", value: arg);
2514 }
2515};
2516
2517void tst_QScriptExtQObject::classConstructor()
2518{
2519 QScriptValue myClass = qScriptValueFromQMetaObject<MyQObject>(engine: m_engine);
2520 m_engine->globalObject().setProperty(name: "MyQObject", value: myClass);
2521
2522 QScriptValue myObj = m_engine->evaluate(program: "myObj = MyQObject()");
2523 QObject *qobj = myObj.toQObject();
2524 QVERIFY(qobj != 0);
2525 QCOMPARE(qobj->metaObject()->className(), "MyQObject");
2526 QCOMPARE(qobj->parent(), (QObject *)0);
2527
2528 QScriptValue qobjectClass = qScriptValueFromQMetaObject<QObject>(engine: m_engine);
2529 m_engine->globalObject().setProperty(name: "QObject", value: qobjectClass);
2530
2531 QScriptValue otherObj = m_engine->evaluate(program: "otherObj = QObject(myObj)");
2532 QObject *qqobj = otherObj.toQObject();
2533 QVERIFY(qqobj != 0);
2534 QCOMPARE(qqobj->metaObject()->className(), "QObject");
2535 QCOMPARE(qqobj->parent(), qobj);
2536
2537 delete qobj;
2538
2539 // Q_INVOKABLE constructors
2540 {
2541 QScriptValue klazz = m_engine->newQMetaObject(metaObject: &ConstructorTest::staticMetaObject);
2542 {
2543 QScriptValue obj = klazz.construct();
2544 QVERIFY(obj.isError());
2545 QCOMPARE(obj.toString(), QString::fromLatin1("SyntaxError: too few arguments in call to ConstructorTest(); candidates are\n"
2546 " ConstructorTest(QBrush)\n"
2547 " ConstructorTest(QBrush,QObject*)\n"
2548 " ConstructorTest(int,QString)\n"
2549 " ConstructorTest(int,QString,QObject*)\n"
2550 " ConstructorTest(QString)\n"
2551 " ConstructorTest(QString,QObject*)\n"
2552 " ConstructorTest(int)\n"
2553 " ConstructorTest(int,QObject*)\n"
2554 " ConstructorTest(QObject*)"));
2555 }
2556 {
2557 QObject objobj;
2558 QScriptValue arg = m_engine->newQObject(object: &objobj);
2559 QScriptValue obj = klazz.construct(args: QScriptValueList() << arg);
2560 QVERIFY(!obj.isError());
2561 QVERIFY(obj.instanceOf(klazz));
2562 QVERIFY(obj.property("ctorIndex").isNumber());
2563 QCOMPARE(obj.property("ctorIndex").toInt32(), 0);
2564 }
2565 {
2566 int arg = 123;
2567 QScriptValue obj = klazz.construct(args: QScriptValueList() << arg);
2568 QVERIFY(!obj.isError());
2569 QVERIFY(obj.instanceOf(klazz));
2570 QVERIFY(obj.property("ctorIndex").isNumber());
2571 QCOMPARE(obj.property("ctorIndex").toInt32(), 1);
2572 QVERIFY(obj.property("arg").isNumber());
2573 QCOMPARE(obj.property("arg").toInt32(), arg);
2574 }
2575 {
2576 QString arg = "foo";
2577 QScriptValue obj = klazz.construct(args: QScriptValueList() << arg);
2578 QVERIFY(!obj.isError());
2579 QVERIFY(obj.instanceOf(klazz));
2580 QVERIFY(obj.property("ctorIndex").isNumber());
2581 QCOMPARE(obj.property("ctorIndex").toInt32(), 2);
2582 QVERIFY(obj.property("arg").isString());
2583 QCOMPARE(obj.property("arg").toString(), arg);
2584 }
2585 {
2586 int arg = 123;
2587 QString arg2 = "foo";
2588 QScriptValue obj = klazz.construct(args: QScriptValueList() << arg << arg2);
2589 QVERIFY(!obj.isError());
2590 QVERIFY(obj.instanceOf(klazz));
2591 QVERIFY(obj.property("ctorIndex").isNumber());
2592 QCOMPARE(obj.property("ctorIndex").toInt32(), 3);
2593 QVERIFY(obj.property("arg").isNumber());
2594 QCOMPARE(obj.property("arg").toInt32(), arg);
2595 QVERIFY(obj.property("arg2").isString());
2596 QCOMPARE(obj.property("arg2").toString(), arg2);
2597 }
2598 {
2599 QBrush arg(Qt::red);
2600 QScriptValue obj = klazz.construct(args: QScriptValueList() << qScriptValueFromValue(engine: m_engine, t: arg));
2601 QVERIFY(!obj.isError());
2602 QVERIFY(obj.instanceOf(klazz));
2603 QVERIFY(obj.property("ctorIndex").isNumber());
2604 QCOMPARE(obj.property("ctorIndex").toInt32(), 4);
2605 QVERIFY(obj.property("arg").isVariant());
2606 QCOMPARE(qvariant_cast<QBrush>(obj.property("arg").toVariant()), arg);
2607 }
2608 {
2609 QDir arg;
2610 QScriptValue obj = klazz.construct(args: QScriptValueList()
2611 << qScriptValueFromValue(engine: m_engine, t: arg));
2612 QVERIFY(obj.isError());
2613 QCOMPARE(obj.toString(), QString::fromLatin1("TypeError: ambiguous call of overloaded function ConstructorTest(); candidates were\n"
2614 " ConstructorTest(int)\n"
2615 " ConstructorTest(QString)"));
2616 }
2617 }
2618}
2619
2620void tst_QScriptExtQObject::overrideInvokable()
2621{
2622 m_myObject->resetQtFunctionInvoked();
2623 m_engine->evaluate(program: "myObject.myInvokable()");
2624 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
2625
2626 m_myObject->resetQtFunctionInvoked();
2627 m_engine->evaluate(program: "myObject.myInvokable = function() { global.a = 123; }");
2628 m_engine->evaluate(program: "myObject.myInvokable()");
2629 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
2630 QCOMPARE(m_engine->evaluate("global.a").toNumber(), 123.0);
2631
2632 m_engine->evaluate(program: "myObject.myInvokable = function() { global.a = 456; }");
2633 m_engine->evaluate(program: "myObject.myInvokable()");
2634 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
2635 QCOMPARE(m_engine->evaluate("global.a").toNumber(), 456.0);
2636
2637 m_engine->evaluate(program: "delete myObject.myInvokable");
2638 m_engine->evaluate(program: "myObject.myInvokable()");
2639 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
2640
2641 m_myObject->resetQtFunctionInvoked();
2642 m_engine->evaluate(program: "myObject.myInvokable = myObject.myInvokableWithIntArg");
2643 m_engine->evaluate(program: "myObject.myInvokable(123)");
2644 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
2645
2646 m_engine->evaluate(program: "delete myObject.myInvokable");
2647 m_myObject->resetQtFunctionInvoked();
2648 // this form (with the '()') is read-only
2649 m_engine->evaluate(program: "myObject['myInvokable()'] = function() { global.a = 123; }");
2650 m_engine->evaluate(program: "myObject.myInvokable()");
2651 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
2652}
2653
2654void tst_QScriptExtQObject::transferInvokable()
2655{
2656 m_myObject->resetQtFunctionInvoked();
2657 m_engine->evaluate(program: "myObject.foozball = myObject.myInvokable");
2658 m_engine->evaluate(program: "myObject.foozball()");
2659 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
2660 m_myObject->resetQtFunctionInvoked();
2661 m_engine->evaluate(program: "myObject.foozball = myObject.myInvokableWithIntArg");
2662 m_engine->evaluate(program: "myObject.foozball(123)");
2663 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
2664 m_myObject->resetQtFunctionInvoked();
2665 m_engine->evaluate(program: "myObject.myInvokable = myObject.myInvokableWithIntArg");
2666 m_engine->evaluate(program: "myObject.myInvokable(123)");
2667 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
2668
2669 MyOtherQObject other;
2670 m_engine->globalObject().setProperty(
2671 name: "myOtherObject", value: m_engine->newQObject(object: &other));
2672 m_engine->evaluate(program: "myOtherObject.foo = myObject.foozball");
2673 other.resetQtFunctionInvoked();
2674 m_engine->evaluate(program: "myOtherObject.foo(456)");
2675 QCOMPARE(other.qtFunctionInvoked(), 1);
2676}
2677
2678void tst_QScriptExtQObject::findChild()
2679{
2680 QObject *child = new QObject(m_myObject);
2681 child->setObjectName(QLatin1String("myChildObject"));
2682
2683 {
2684 QScriptValue result = m_engine->evaluate(program: "myObject.findChild('noSuchChild')");
2685 QCOMPARE(result.isNull(), true);
2686 }
2687
2688 {
2689 QScriptValue result = m_engine->evaluate(program: "myObject.findChild('myChildObject')");
2690 QCOMPARE(result.isQObject(), true);
2691 QCOMPARE(result.toQObject(), child);
2692 }
2693
2694 delete child;
2695}
2696
2697void tst_QScriptExtQObject::findChildren()
2698{
2699 QObject *child = new QObject(m_myObject);
2700 child->setObjectName(QLatin1String("myChildObject"));
2701
2702 {
2703 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren('noSuchChild')");
2704 QCOMPARE(result.isArray(), true);
2705 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 0.0);
2706 }
2707
2708 {
2709 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren('myChildObject')");
2710 QCOMPARE(result.isArray(), true);
2711 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
2712 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
2713 }
2714
2715 QObject *namelessChild = new QObject(m_myObject);
2716
2717 {
2718 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren('myChildObject')");
2719 QCOMPARE(result.isArray(), true);
2720 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
2721 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
2722 }
2723
2724 QObject *anotherChild = new QObject(m_myObject);
2725 anotherChild->setObjectName(QLatin1String("anotherChildObject"));
2726
2727 {
2728 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren('anotherChildObject')");
2729 QCOMPARE(result.isArray(), true);
2730 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0);
2731 QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
2732 }
2733
2734 anotherChild->setObjectName(QLatin1String("myChildObject"));
2735 {
2736 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren('myChildObject')");
2737 QCOMPARE(result.isArray(), true);
2738 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0);
2739 QObject *o1 = result.property(name: QLatin1String("0")).toQObject();
2740 QObject *o2 = result.property(name: QLatin1String("1")).toQObject();
2741 if (o1 != child) {
2742 QCOMPARE(o1, anotherChild);
2743 QCOMPARE(o2, child);
2744 } else {
2745 QCOMPARE(o1, child);
2746 QCOMPARE(o2, anotherChild);
2747 }
2748 }
2749
2750 // find all
2751 {
2752 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren()");
2753 QVERIFY(result.isArray());
2754 int count = 3;
2755 QCOMPARE(result.property("length").toInt32(), count);
2756 for (int i = 0; i < 3; ++i) {
2757 QObject *o = result.property(arrayIndex: i).toQObject();
2758 if (o == namelessChild || o == child || o == anotherChild)
2759 --count;
2760 }
2761 QVERIFY(count == 0);
2762 }
2763
2764 // matchall regexp
2765 {
2766 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren(/.*/)");
2767 QVERIFY(result.isArray());
2768 int count = 3;
2769 QCOMPARE(result.property("length").toInt32(), count);
2770 for (int i = 0; i < 3; ++i) {
2771 QObject *o = result.property(arrayIndex: i).toQObject();
2772 if (o == namelessChild || o == child || o == anotherChild)
2773 --count;
2774 }
2775 QVERIFY(count == 0);
2776 }
2777
2778 // matchall regexp my*
2779 {
2780 QScriptValue result = m_engine->evaluate(program: "myObject.findChildren(new RegExp(\"^my.*\"))");
2781 QCOMPARE(result.isArray(), true);
2782 QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0);
2783 QObject *o1 = result.property(name: QLatin1String("0")).toQObject();
2784 QObject *o2 = result.property(name: QLatin1String("1")).toQObject();
2785 if (o1 != child) {
2786 QCOMPARE(o1, anotherChild);
2787 QCOMPARE(o2, child);
2788 } else {
2789 QCOMPARE(o1, child);
2790 QCOMPARE(o2, anotherChild);
2791 }
2792 }
2793 delete anotherChild;
2794 delete namelessChild;
2795 delete child;
2796}
2797
2798void tst_QScriptExtQObject::childObjects()
2799{
2800 QObject *child1 = new QObject(m_myObject);
2801 child1->setObjectName("child1");
2802 QObject *child2 = new QObject(m_myObject);
2803 QScriptValue wrapped = m_engine->newQObject(object: m_myObject);
2804
2805 QVERIFY(wrapped.property("child1").isQObject());
2806 QCOMPARE(wrapped.property("child1").toQObject(), child1);
2807 QVERIFY(!wrapped.property("child2").isQObject());
2808 QVERIFY(!wrapped.property("child2").isValid());
2809
2810 // Setting the name later
2811 child2->setObjectName("child2");
2812
2813 QVERIFY(wrapped.property("child1").isQObject());
2814 QCOMPARE(wrapped.property("child1").toQObject(), child1);
2815 QVERIFY(wrapped.property("child2").isQObject());
2816 QCOMPARE(wrapped.property("child2").toQObject(), child2);
2817
2818 // Adding a child later
2819 QObject *child3 = new QObject(m_myObject);
2820 child3->setObjectName("child3");
2821
2822 QVERIFY(wrapped.property("child3").isQObject());
2823 QCOMPARE(wrapped.property("child3").toQObject(), child3);
2824
2825 // Changing a child name
2826 child1->setObjectName("anotherName");
2827
2828 QVERIFY(!wrapped.property("child1").isValid());
2829 QVERIFY(wrapped.property("anotherName").isQObject());
2830 QCOMPARE(wrapped.property("anotherName").toQObject(), child1);
2831
2832 // Creating another object wrapper excluding child from
2833 // properties.
2834 QScriptValue wrapped2 = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership, options: QScriptEngine::ExcludeChildObjects);
2835
2836 QVERIFY(!wrapped2.property("anotherName").isValid());
2837 QVERIFY(!wrapped2.property("child2").isValid());
2838 QVERIFY(!wrapped2.property("child3").isValid());
2839}
2840
2841void tst_QScriptExtQObject::overloadedSlots()
2842{
2843 // should pick myOverloadedSlot(double)
2844 m_myObject->resetQtFunctionInvoked();
2845 m_engine->evaluate(program: "myObject.myOverloadedSlot(10)");
2846 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2847
2848 // should pick myOverloadedSlot(double)
2849 m_myObject->resetQtFunctionInvoked();
2850 m_engine->evaluate(program: "myObject.myOverloadedSlot(10.0)");
2851 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2852
2853 // should pick myOverloadedSlot(QString)
2854 m_myObject->resetQtFunctionInvoked();
2855 m_engine->evaluate(program: "myObject.myOverloadedSlot('10')");
2856 QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
2857
2858 // should pick myOverloadedSlot(bool)
2859 m_myObject->resetQtFunctionInvoked();
2860 m_engine->evaluate(program: "myObject.myOverloadedSlot(true)");
2861 QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
2862
2863 // should pick myOverloadedSlot(QDateTime)
2864 m_myObject->resetQtFunctionInvoked();
2865 m_engine->evaluate(program: "myObject.myOverloadedSlot(new Date())");
2866 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2867
2868 // should pick myOverloadedSlot(QRegExp)
2869 m_myObject->resetQtFunctionInvoked();
2870 m_engine->evaluate(program: "myObject.myOverloadedSlot(new RegExp())");
2871 QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
2872
2873 // should pick myOverloadedSlot(QVariant)
2874 m_myObject->resetQtFunctionInvoked();
2875 QScriptValue f = m_engine->evaluate(program: "myObject.myOverloadedSlot");
2876 f.call(thisObject: QScriptValue(), args: QScriptValueList() << m_engine->newVariant(value: QVariant("ciao")));
2877 QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
2878
2879 // should pick myOverloadedSlot(QObject*)
2880 m_myObject->resetQtFunctionInvoked();
2881 m_engine->evaluate(program: "myObject.myOverloadedSlot(myObject)");
2882 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2883
2884 // should pick myOverloadedSlot(QObject*)
2885 m_myObject->resetQtFunctionInvoked();
2886 m_engine->evaluate(program: "myObject.myOverloadedSlot(null)");
2887 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2888
2889 // should pick myOverloadedSlot(QStringList)
2890 m_myObject->resetQtFunctionInvoked();
2891 m_engine->evaluate(program: "myObject.myOverloadedSlot(['hello'])");
2892 QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
2893}
2894
2895void tst_QScriptExtQObject::enumerate_data()
2896{
2897 QTest::addColumn<int>(name: "wrapOptions");
2898 QTest::addColumn<QStringList>(name: "expectedNames");
2899
2900 QTest::newRow( dataTag: "enumerate all" )
2901 << 0
2902 << (QStringList()
2903 // meta-object-defined properties:
2904 // inherited
2905 << "objectName"
2906 // non-inherited
2907 << "p1" << "p2" << "p4" << "p6"
2908 // dynamic properties
2909 << "dp1" << "dp2" << "dp3"
2910 // inherited signals
2911 << "destroyed(QObject*)" << "destroyed()"
2912 << "objectNameChanged(QString)"
2913 // inherited slots
2914 << "deleteLater()"
2915 // not included because it's private:
2916 // << "_q_reregisterTimers(void*)"
2917 // signals
2918 << "mySignal()"
2919 // slots
2920 << "mySlot()" << "myOtherSlot()");
2921
2922 QTest::newRow( dataTag: "don't enumerate inherited properties" )
2923 << int(QScriptEngine::ExcludeSuperClassProperties)
2924 << (QStringList()
2925 // meta-object-defined properties:
2926 // non-inherited
2927 << "p1" << "p2" << "p4" << "p6"
2928 // dynamic properties
2929 << "dp1" << "dp2" << "dp3"
2930 // inherited signals
2931 << "destroyed(QObject*)" << "destroyed()"
2932 << "objectNameChanged(QString)"
2933 // inherited slots
2934 << "deleteLater()"
2935 // not included because it's private:
2936 // << "_q_reregisterTimers(void*)"
2937 // signals
2938 << "mySignal()"
2939 // slots
2940 << "mySlot()" << "myOtherSlot()");
2941
2942 QTest::newRow( dataTag: "don't enumerate inherited methods" )
2943 << int(QScriptEngine::ExcludeSuperClassMethods)
2944 << (QStringList()
2945 // meta-object-defined properties:
2946 // inherited
2947 << "objectName"
2948 // non-inherited
2949 << "p1" << "p2" << "p4" << "p6"
2950 // dynamic properties
2951 << "dp1" << "dp2" << "dp3"
2952 // signals
2953 << "mySignal()"
2954 // slots
2955 << "mySlot()" << "myOtherSlot()");
2956
2957 QTest::newRow( dataTag: "don't enumerate inherited members" )
2958 << int(QScriptEngine::ExcludeSuperClassMethods
2959 | QScriptEngine::ExcludeSuperClassProperties)
2960 << (QStringList()
2961 // meta-object-defined properties
2962 << "p1" << "p2" << "p4" << "p6"
2963 // dynamic properties
2964 << "dp1" << "dp2" << "dp3"
2965 // signals
2966 << "mySignal()"
2967 // slots
2968 << "mySlot()" << "myOtherSlot()");
2969
2970 QTest::newRow( dataTag: "enumerate properties, not methods" )
2971 << int(QScriptEngine::SkipMethodsInEnumeration)
2972 << (QStringList()
2973 // meta-object-defined properties:
2974 // inherited
2975 << "objectName"
2976 // non-inherited
2977 << "p1" << "p2" << "p4" << "p6"
2978 // dynamic properties
2979 << "dp1" << "dp2" << "dp3");
2980
2981 QTest::newRow( dataTag: "don't enumerate inherited properties + methods" )
2982 << int(QScriptEngine::ExcludeSuperClassProperties
2983 | QScriptEngine::SkipMethodsInEnumeration)
2984 << (QStringList()
2985 // meta-object-defined properties:
2986 // non-inherited
2987 << "p1" << "p2" << "p4" << "p6"
2988 // dynamic properties
2989 << "dp1" << "dp2" << "dp3");
2990
2991 QTest::newRow( dataTag: "don't enumerate inherited members" )
2992 << int(QScriptEngine::ExcludeSuperClassContents)
2993 << (QStringList()
2994 // meta-object-defined properties
2995 << "p1" << "p2" << "p4" << "p6"
2996 // dynamic properties
2997 << "dp1" << "dp2" << "dp3"
2998 // signals
2999 << "mySignal()"
3000 // slots
3001 << "mySlot()" << "myOtherSlot()");
3002
3003 QTest::newRow( dataTag: "don't enumerate deleteLater()" )
3004 << int(QScriptEngine::ExcludeDeleteLater)
3005 << (QStringList()
3006 // meta-object-defined properties:
3007 // inherited
3008 << "objectName"
3009 // non-inherited
3010 << "p1" << "p2" << "p4" << "p6"
3011 // dynamic properties
3012 << "dp1" << "dp2" << "dp3"
3013 // inherited signals
3014 << "destroyed(QObject*)" << "destroyed()"
3015 << "objectNameChanged(QString)"
3016 // not included because it's private:
3017 // << "_q_reregisterTimers(void*)"
3018 // signals
3019 << "mySignal()"
3020 // slots
3021 << "mySlot()" << "myOtherSlot()");
3022
3023 QTest::newRow( dataTag: "don't enumerate slots" )
3024 << int(QScriptEngine::ExcludeSlots)
3025 << (QStringList()
3026 // meta-object-defined properties:
3027 // inherited
3028 << "objectName"
3029 // non-inherited
3030 << "p1" << "p2" << "p4" << "p6"
3031 // dynamic properties
3032 << "dp1" << "dp2" << "dp3"
3033 // inherited signals
3034 << "destroyed(QObject*)" << "destroyed()"
3035 << "objectNameChanged(QString)"
3036 // signals
3037 << "mySignal()");
3038}
3039
3040// Message for easily identifying mismatches in string list.
3041static QByteArray msgEnumerationFail(const QStringList &actual, const QStringList &expected)
3042{
3043 QString result;
3044 QTextStream str(&result);
3045 str << "\nActual " << actual.size() << ":\n";
3046 for (int i = 0; i < actual.size(); ++i) {
3047 const int index = expected.indexOf(t: actual.at(i));
3048 if (index < 0)
3049 str << "*** ";
3050 str << " #" << i << " '"<< actual.at(i)
3051 << "'\tin expected at: " << index << '\n';
3052 }
3053 str << "Expected " << expected.size() << ":\n";
3054 for (int i = 0; i < expected.size(); ++i) {
3055 const int index = actual.indexOf(t: expected.at(i));
3056 if (index < 0)
3057 str << "*** ";
3058 str << " #" << i << " '"<< expected.at(i)
3059 << "'\t in actual at: " << index << '\n';
3060 }
3061 return result.toLocal8Bit();
3062}
3063
3064void tst_QScriptExtQObject::enumerate()
3065{
3066 QFETCH( int, wrapOptions );
3067 QFETCH( QStringList, expectedNames );
3068
3069 QScriptEngine eng;
3070 MyEnumTestQObject enumQObject;
3071 // give it some dynamic properties
3072 enumQObject.setProperty(name: "dp1", value: "dp1");
3073 enumQObject.setProperty(name: "dp2", value: "dp2");
3074 enumQObject.setProperty(name: "dp3", value: "dp3");
3075 QScriptValue obj = eng.newQObject(object: &enumQObject, ownership: QScriptEngine::QtOwnership,
3076 options: QScriptEngine::QObjectWrapOptions(wrapOptions));
3077
3078 // enumerate in script
3079 {
3080 eng.globalObject().setProperty(name: "myEnumObject", value: obj);
3081 eng.evaluate(program: "var enumeratedProperties = []");
3082 eng.evaluate(program: "for (var p in myEnumObject) { enumeratedProperties.push(p); }");
3083 QStringList result = qscriptvalue_cast<QStringList>(value: eng.evaluate(program: "enumeratedProperties"));
3084 QVERIFY2(result == expectedNames, msgEnumerationFail(result, expectedNames).constData());
3085 }
3086 // enumerate in C++
3087 {
3088 QScriptValueIterator it(obj);
3089 QStringList result;
3090 while (it.hasNext()) {
3091 it.next();
3092 QCOMPARE(it.flags(), obj.propertyFlags(it.name()));
3093 result.append(t: it.name());
3094 }
3095 QVERIFY2(result == expectedNames, msgEnumerationFail(result, expectedNames).constData());
3096 }
3097}
3098
3099class SpecialEnumTestObject : public QObject
3100{
3101 Q_OBJECT
3102 // overriding a property in the super-class to make it non-scriptable
3103 Q_PROPERTY(QString objectName READ objectName SCRIPTABLE false)
3104public:
3105 SpecialEnumTestObject(QObject *parent = 0)
3106 : QObject(parent) {}
3107};
3108
3109class SpecialEnumTestObject2 : public QObject
3110{
3111 Q_OBJECT
3112 // overriding a property in the super-class to make it non-designable (but still scriptable)
3113 Q_PROPERTY(QString objectName READ objectName DESIGNABLE false)
3114public:
3115 SpecialEnumTestObject2(QObject *parent = 0)
3116 : QObject(parent) {}
3117};
3118
3119void tst_QScriptExtQObject::enumerateSpecial()
3120{
3121 QScriptEngine eng;
3122 {
3123 SpecialEnumTestObject testObj;
3124 QScriptValueIterator it(eng.newQObject(object: &testObj));
3125 bool objectNameEncountered = false;
3126 while (it.hasNext()) {
3127 it.next();
3128 if (it.name() == QLatin1String("objectName")) {
3129 objectNameEncountered = true;
3130 break;
3131 }
3132 }
3133 QVERIFY(!objectNameEncountered);
3134 }
3135 {
3136 SpecialEnumTestObject2 testObj;
3137 testObj.setObjectName("foo");
3138 QScriptValueList values;
3139 QScriptValueIterator it(eng.newQObject(object: &testObj));
3140 while (it.hasNext()) {
3141 it.next();
3142 if (it.name() == "objectName")
3143 values.append(t: it.value());
3144 }
3145 QCOMPARE(values.size(), 1);
3146 QCOMPARE(values.at(0).toString(), QString::fromLatin1("foo"));
3147 }
3148}
3149
3150void tst_QScriptExtQObject::wrapOptions()
3151{
3152 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
3153 MyQObject *child = new MyQObject(m_myObject);
3154 child->setObjectName("child");
3155 // exclude child objects
3156 {
3157 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3158 options: QScriptEngine::ExcludeChildObjects);
3159 QCOMPARE(obj.property("child").isValid(), false);
3160 obj.setProperty(name: "child", value: QScriptValue(m_engine, 123));
3161 QCOMPARE(obj.property("child")
3162 .strictlyEquals(QScriptValue(m_engine, 123)), true);
3163 }
3164 // don't auto-create dynamic properties
3165 {
3166 QScriptValue obj = m_engine->newQObject(object: m_myObject);
3167 QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
3168 obj.setProperty(name: "anotherDynamicProperty", value: QScriptValue(m_engine, 123));
3169 QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
3170 QCOMPARE(obj.property("anotherDynamicProperty")
3171 .strictlyEquals(QScriptValue(m_engine, 123)), true);
3172 }
3173 // auto-create dynamic properties
3174 {
3175 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3176 options: QScriptEngine::AutoCreateDynamicProperties);
3177 QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
3178 obj.setProperty(name: "anotherDynamicProperty", value: QScriptValue(m_engine, 123));
3179 QVERIFY(m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty"));
3180 QCOMPARE(obj.property("anotherDynamicProperty")
3181 .strictlyEquals(QScriptValue(m_engine, 123)), true);
3182 // task 236685
3183 {
3184 QScriptValue obj2 = m_engine->newObject();
3185 obj2.setProperty(name: "notADynamicProperty", value: 456);
3186 obj.setPrototype(obj2);
3187 QScriptValue ret = obj.property(name: "notADynamicProperty");
3188 QVERIFY(ret.isNumber());
3189 QVERIFY(ret.strictlyEquals(obj2.property("notADynamicProperty")));
3190 }
3191 }
3192 // don't exclude super-class properties
3193 {
3194 QScriptValue obj = m_engine->newQObject(object: m_myObject);
3195 QVERIFY(obj.property("objectName").isValid());
3196 QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
3197 }
3198 // exclude super-class properties
3199 {
3200 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3201 options: QScriptEngine::ExcludeSuperClassProperties);
3202 QVERIFY(!obj.property("objectName").isValid());
3203 QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
3204 QVERIFY(obj.property("intProperty").isValid());
3205 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3206 }
3207 // don't exclude super-class methods
3208 {
3209 QScriptValue obj = m_engine->newQObject(object: m_myObject);
3210 QVERIFY(obj.property("deleteLater").isValid());
3211 QVERIFY(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember);
3212 }
3213 // exclude super-class methods
3214 {
3215 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3216 options: QScriptEngine::ExcludeSuperClassMethods);
3217 QVERIFY(!obj.property("deleteLater").isValid());
3218 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3219 QVERIFY(obj.property("mySlot").isValid());
3220 QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
3221 }
3222 // exclude all super-class contents
3223 {
3224 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3225 options: QScriptEngine::ExcludeSuperClassContents);
3226 QVERIFY(!obj.property("deleteLater").isValid());
3227 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3228 QVERIFY(obj.property("mySlot").isValid());
3229 QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
3230
3231 QVERIFY(!obj.property("objectName").isValid());
3232 QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
3233 QVERIFY(obj.property("intProperty").isValid());
3234 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3235 }
3236 // exclude deleteLater()
3237 {
3238 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3239 options: QScriptEngine::ExcludeDeleteLater);
3240 QVERIFY(!obj.property("deleteLater").isValid());
3241 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3242 QVERIFY(obj.property("mySlot").isValid());
3243 QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
3244
3245 QVERIFY(obj.property("objectName").isValid());
3246 QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
3247 QVERIFY(obj.property("intProperty").isValid());
3248 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3249 }
3250 // exclude slots
3251 {
3252 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3253 options: QScriptEngine::ExcludeSlots);
3254 QVERIFY(!obj.property("deleteLater").isValid());
3255 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3256 QVERIFY(!obj.property("mySlot").isValid());
3257 QVERIFY(!(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember));
3258
3259 QVERIFY(obj.property("myInvokable").isFunction());
3260 QVERIFY(obj.propertyFlags("myInvokable") & QScriptValue::QObjectMember);
3261
3262 QVERIFY(obj.property("mySignal").isFunction());
3263 QVERIFY(obj.propertyFlags("mySignal") & QScriptValue::QObjectMember);
3264 QVERIFY(obj.property("destroyed").isFunction());
3265 QVERIFY(obj.propertyFlags("destroyed") & QScriptValue::QObjectMember);
3266
3267 QVERIFY(obj.property("objectName").isValid());
3268 QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember);
3269 QVERIFY(obj.property("intProperty").isValid());
3270 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3271 }
3272 // exclude all that we can
3273 {
3274 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3275 options: QScriptEngine::ExcludeSuperClassMethods
3276 | QScriptEngine::ExcludeSuperClassProperties
3277 | QScriptEngine::ExcludeChildObjects);
3278 QVERIFY(!obj.property("deleteLater").isValid());
3279 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3280 QVERIFY(obj.property("mySlot").isValid());
3281 QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember);
3282
3283 QVERIFY(!obj.property("objectName").isValid());
3284 QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
3285 QVERIFY(obj.property("intProperty").isValid());
3286 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3287
3288 QCOMPARE(obj.property("child").isValid(), false);
3289 obj.setProperty(name: "child", value: QScriptValue(m_engine, 123));
3290 QCOMPARE(obj.property("child")
3291 .strictlyEquals(QScriptValue(m_engine, 123)), true);
3292 }
3293 // exclude absolutely all that we can
3294 {
3295 QScriptValue obj = m_engine->newQObject(object: m_myObject, ownership: QScriptEngine::QtOwnership,
3296 options: QScriptEngine::ExcludeSuperClassMethods
3297 | QScriptEngine::ExcludeSuperClassProperties
3298 | QScriptEngine::ExcludeChildObjects
3299 | QScriptEngine::ExcludeSlots);
3300 QVERIFY(!obj.property("deleteLater").isValid());
3301 QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember));
3302
3303 QVERIFY(!obj.property("mySlot").isValid());
3304 QVERIFY(!(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember));
3305
3306 QVERIFY(obj.property("mySignal").isFunction());
3307 QVERIFY(obj.propertyFlags("mySignal") & QScriptValue::QObjectMember);
3308
3309 QVERIFY(obj.property("myInvokable").isFunction());
3310 QVERIFY(obj.propertyFlags("myInvokable") & QScriptValue::QObjectMember);
3311
3312 QVERIFY(!obj.property("objectName").isValid());
3313 QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember));
3314
3315 QVERIFY(obj.property("intProperty").isValid());
3316 QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember);
3317
3318 QVERIFY(!obj.property("child").isValid());
3319 }
3320
3321 delete child;
3322}
3323
3324Q_DECLARE_METATYPE(QWidget*)
3325Q_DECLARE_METATYPE(QPushButton*)
3326
3327void tst_QScriptExtQObject::prototypes()
3328{
3329 QScriptEngine eng;
3330 QScriptValue widgetProto = eng.newQObject(object: new QWidget(), ownership: QScriptEngine::ScriptOwnership);
3331 eng.setDefaultPrototype(metaTypeId: qMetaTypeId<QWidget*>(), prototype: widgetProto);
3332 QPushButton *pbp = new QPushButton();
3333 QScriptValue buttonProto = eng.newQObject(object: pbp, ownership: QScriptEngine::ScriptOwnership);
3334 buttonProto.setPrototype(widgetProto);
3335 eng.setDefaultPrototype(metaTypeId: qMetaTypeId<QPushButton*>(), prototype: buttonProto);
3336 QPushButton *pb = new QPushButton();
3337 QScriptValue button = eng.newQObject(object: pb, ownership: QScriptEngine::ScriptOwnership);
3338 QVERIFY(button.prototype().strictlyEquals(buttonProto));
3339
3340 buttonProto.setProperty(name: "text", value: QScriptValue(&eng, "prototype button"));
3341 QCOMPARE(pbp->text(), QLatin1String("prototype button"));
3342 button.setProperty(name: "text", value: QScriptValue(&eng, "not the prototype button"));
3343 QCOMPARE(pb->text(), QLatin1String("not the prototype button"));
3344 QCOMPARE(pbp->text(), QLatin1String("prototype button"));
3345
3346 buttonProto.setProperty(name: "objectName", value: QScriptValue(&eng, "prototype button"));
3347 QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
3348 button.setProperty(name: "objectName", value: QScriptValue(&eng, "not the prototype button"));
3349 QCOMPARE(pb->objectName(), QLatin1String("not the prototype button"));
3350 QCOMPARE(pbp->objectName(), QLatin1String("prototype button"));
3351}
3352
3353void tst_QScriptExtQObject::objectDeleted()
3354{
3355 QScriptEngine eng;
3356 MyQObject *qobj = new MyQObject();
3357 QScriptValue v = eng.newQObject(object: qobj);
3358 v.setProperty(name: "objectName", value: QScriptValue(&eng, "foo"));
3359 QCOMPARE(qobj->objectName(), QLatin1String("foo"));
3360 v.setProperty(name: "intProperty", value: QScriptValue(&eng, 123));
3361 QCOMPARE(qobj->intProperty(), 123);
3362 qobj->resetQtFunctionInvoked();
3363 QScriptValue invokable = v.property(name: "myInvokable");
3364 invokable.call(thisObject: v);
3365 QCOMPARE(qobj->qtFunctionInvoked(), 0);
3366
3367 // now delete the object
3368 delete qobj;
3369
3370 // the documented behavior is: isQObject() should still return true,
3371 // but toQObject() should return 0
3372 QVERIFY(v.isQObject());
3373 QCOMPARE(v.toQObject(), (QObject *)0);
3374
3375 // any attempt to access properties of the object should result in an exception
3376 {
3377 QScriptValue ret = v.property(name: "objectName");
3378 QVERIFY(ret.isError());
3379 QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
3380 }
3381 {
3382 eng.evaluate(program: "Object");
3383 QVERIFY(!eng.hasUncaughtException());
3384 v.setProperty(name: "objectName", value: QScriptValue(&eng, "foo"));
3385 QVERIFY(eng.hasUncaughtException());
3386 QVERIFY(eng.uncaughtException().isError());
3387 QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
3388 }
3389
3390 {
3391 QScriptValue ret = v.call();
3392 QVERIFY(!ret.isValid());
3393 }
3394
3395 // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
3396 {
3397 QScriptValue ret = v.property(name: "myInvokableWithIntArg");
3398 QVERIFY(ret.isError());
3399 QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
3400 }
3401
3402 // Meta-method wrappers are still valid, but throw error when called
3403 QVERIFY(invokable.isFunction());
3404 {
3405 QScriptValue ret = invokable.call(thisObject: v);
3406 QVERIFY(ret.isError());
3407 QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot call function of deleted QObject"));
3408 }
3409
3410 // access from script
3411 eng.globalObject().setProperty(name: "o", value: v);
3412 {
3413 QScriptValue ret = eng.evaluate(program: "o()");
3414 QVERIFY(ret.isError());
3415 QCOMPARE(ret.toString(), QLatin1String("TypeError: Result of expression 'o' [] is not a function."));
3416 }
3417 {
3418 QScriptValue ret = eng.evaluate(program: "o.objectName");
3419 QVERIFY(ret.isError());
3420 QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
3421 }
3422 {
3423 QScriptValue ret = eng.evaluate(program: "o.myInvokable()");
3424 QVERIFY(ret.isError());
3425 QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokable' of deleted QObject"));
3426 }
3427 {
3428 QScriptValue ret = eng.evaluate(program: "o.myInvokableWithIntArg(10)");
3429 QVERIFY(ret.isError());
3430 QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
3431 }
3432}
3433
3434void tst_QScriptExtQObject::connectToDestroyedSignal()
3435{
3436 // ### the following test currently depends on signal emission order
3437#if 0
3438 {
3439 // case 1: deleted when the engine is not doing GC
3440 QScriptEngine eng;
3441 QObject *obj = new QObject();
3442 eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::QtOwnership));
3443 eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
3444 eng.evaluate("wasDestroyed = false");
3445 delete obj;
3446 QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
3447 }
3448 {
3449 // case 2: deleted when the engine is doing GC
3450 QScriptEngine eng;
3451 QObject *obj = new QObject();
3452 eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
3453 eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })");
3454 eng.evaluate("wasDestroyed = false");
3455 eng.evaluate("o = null");
3456 eng.collectGarbage();
3457 QVERIFY(eng.evaluate("wasDestroyed").toBoolean());
3458 }
3459 {
3460 // case 3: deleted when the engine is destroyed
3461 QScriptEngine eng;
3462 QObject *obj = new QObject();
3463 eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership));
3464 eng.evaluate("o.destroyed.connect(function() { })");
3465 // the signal handler won't get called -- we don't want to crash
3466 }
3467#endif
3468}
3469
3470void tst_QScriptExtQObject::emitAfterReceiverDeleted()
3471{
3472 for (int x = 0; x < 2; ++x) {
3473 MyQObject *obj = new MyQObject;
3474 QScriptValue scriptObj = m_engine->newQObject(object: obj);
3475 if (x == 0) {
3476 // Connecting from JS
3477 m_engine->globalObject().setProperty(name: "obj", value: scriptObj);
3478 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(obj, 'mySlot()')").isUndefined());
3479 } else {
3480 // Connecting from C++
3481 qScriptConnect(sender: m_myObject, SIGNAL(mySignal()), receiver: scriptObj, function: scriptObj.property(name: "mySlot"));
3482 }
3483 delete obj;
3484 QSignalSpy signalHandlerExceptionSpy(m_engine, SIGNAL(signalHandlerException(QScriptValue)));
3485 QVERIFY(!m_engine->hasUncaughtException());
3486 m_myObject->emitMySignal();
3487 QCOMPARE(signalHandlerExceptionSpy.count(), 0);
3488 QVERIFY(!m_engine->hasUncaughtException());
3489 }
3490}
3491
3492void tst_QScriptExtQObject::inheritedSlots()
3493{
3494 QScriptEngine eng;
3495
3496 QPushButton prototypeButton;
3497 QScriptValue scriptPrototypeButton = eng.newQObject(object: &prototypeButton);
3498
3499 QPushButton button;
3500 QScriptValue scriptButton = eng.newQObject(object: &button, ownership: QScriptEngine::QtOwnership,
3501 options: QScriptEngine::ExcludeSlots);
3502 scriptButton.setPrototype(scriptPrototypeButton);
3503
3504 QVERIFY(scriptButton.property("click").isFunction());
3505 QVERIFY(scriptButton.property("click").strictlyEquals(scriptPrototypeButton.property("click")));
3506
3507 QSignalSpy prototypeButtonClickedSpy(&prototypeButton, SIGNAL(clicked()));
3508 QSignalSpy buttonClickedSpy(&button, SIGNAL(clicked()));
3509 scriptButton.property(name: "click").call(thisObject: scriptButton);
3510 QCOMPARE(buttonClickedSpy.count(), 1);
3511 QCOMPARE(prototypeButtonClickedSpy.count(), 0);
3512}
3513
3514void tst_QScriptExtQObject::enumerateMetaObject()
3515{
3516 QScriptValue myClass = m_engine->newQMetaObject(metaObject: m_myObject->metaObject(), ctor: m_engine->undefinedValue());
3517
3518 QStringList expectedNames;
3519 expectedNames << "FooPolicy" << "BarPolicy" << "BazPolicy"
3520 << "FooStrategy" << "BarStrategy" << "BazStrategy"
3521 << "NoAbility" << "FooAbility" << "BarAbility" << "BazAbility" << "AllAbility";
3522
3523 for (int x = 0; x < 2; ++x) {
3524 QSet<QString> actualNames;
3525 if (x == 0) {
3526 // From C++
3527 QScriptValueIterator it(myClass);
3528 while (it.hasNext()) {
3529 it.next();
3530 actualNames.insert(value: it.name());
3531 }
3532 } else {
3533 // From JS
3534 m_engine->globalObject().setProperty(name: "MyClass", value: myClass);
3535 QScriptValue ret = m_engine->evaluate(program: "a=[]; for (var p in MyClass) if (MyClass.hasOwnProperty(p)) a.push(p); a");
3536 QVERIFY(ret.isArray());
3537 QStringList strings = qscriptvalue_cast<QStringList>(value: ret);
3538 for (int i = 0; i < strings.size(); ++i)
3539 actualNames.insert(value: strings.at(i));
3540 }
3541 QCOMPARE(actualNames.size(), expectedNames.size());
3542 for (int i = 0; i < expectedNames.size(); ++i)
3543 QVERIFY(actualNames.contains(expectedNames.at(i)));
3544 }
3545}
3546
3547void tst_QScriptExtQObject::nestedArrayAsSlotArgument_data()
3548{
3549 QTest::addColumn<QString>(name: "program");
3550 QTest::addColumn<QVariantList>(name: "expected");
3551
3552 QTest::newRow(dataTag: "[[]]")
3553 << QString::fromLatin1(str: "[[]]")
3554 << (QVariantList() << (QVariant(QVariantList())));
3555 QTest::newRow(dataTag: "[[123]]")
3556 << QString::fromLatin1(str: "[[123]]")
3557 << (QVariantList() << (QVariant(QVariantList() << 123)));
3558 QTest::newRow(dataTag: "[[], 123]")
3559 << QString::fromLatin1(str: "[[], 123]")
3560 << (QVariantList() << QVariant(QVariantList()) << 123);
3561
3562 // Cyclic
3563 QTest::newRow(dataTag: "var a=[]; a.push(a)")
3564 << QString::fromLatin1(str: "var a=[]; a.push(a); a")
3565 << (QVariantList() << QVariant(QVariantList()));
3566 QTest::newRow(dataTag: "var a=[]; a.push(123, a)")
3567 << QString::fromLatin1(str: "var a=[]; a.push(123, a); a")
3568 << (QVariantList() << 123 << QVariant(QVariantList()));
3569 QTest::newRow(dataTag: "var a=[]; var b=[]; a.push(b); b.push(a)")
3570 << QString::fromLatin1(str: "var a=[]; var b=[]; a.push(b); b.push(a); a")
3571 << (QVariantList() << QVariant(QVariantList() << QVariant(QVariantList())));
3572 QTest::newRow(dataTag: "var a=[]; var b=[]; a.push(123, b); b.push(456, a)")
3573 << QString::fromLatin1(str: "var a=[]; var b=[]; a.push(123, b); b.push(456, a); a")
3574 << (QVariantList() << 123 << QVariant(QVariantList() << 456 << QVariant(QVariantList())));
3575}
3576
3577void tst_QScriptExtQObject::nestedArrayAsSlotArgument()
3578{
3579 QFETCH(QString, program);
3580 QFETCH(QVariantList, expected);
3581 QScriptValue a = m_engine->evaluate(program);
3582 QVERIFY(!a.isError());
3583 QVERIFY(a.isArray());
3584 // Slot that takes QVariantList
3585 {
3586 QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantListArg")
3587 .call(QScriptValue(), QScriptValueList() << a).isError());
3588 QCOMPARE(m_myObject->qtFunctionInvoked(), 62);
3589 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
3590 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::List);
3591 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toList(), expected);
3592 }
3593 // Slot that takes QVariant
3594 {
3595 m_myObject->resetQtFunctionInvoked();
3596 QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantArg")
3597 .call(QScriptValue(), QScriptValueList() << a).isError());
3598 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
3599 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
3600 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::List);
3601 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toList(), expected);
3602 }
3603}
3604
3605void tst_QScriptExtQObject::nestedObjectAsSlotArgument_data()
3606{
3607 QTest::addColumn<QString>(name: "program");
3608 QTest::addColumn<QVariantMap>(name: "expected");
3609
3610 {
3611 QVariantMap m;
3612 m["a"] = QVariantMap();
3613 QTest::newRow(dataTag: "{ a:{} }")
3614 << QString::fromLatin1(str: "({ a:{} })")
3615 << m;
3616 }
3617 {
3618 QVariantMap m, m2;
3619 m2["b"] = 10;
3620 m2["c"] = 20;
3621 m["a"] = m2;
3622 QTest::newRow(dataTag: "{ a:{b:10, c:20} }")
3623 << QString::fromLatin1(str: "({ a:{b:10, c:20} })")
3624 << m;
3625 }
3626 {
3627 QVariantMap m;
3628 m["a"] = 10;
3629 m["b"] = QVariantList() << 20 << 30;
3630 QTest::newRow(dataTag: "{ a:10, b:[20, 30]}")
3631 << QString::fromLatin1(str: "({ a:10, b:[20,30]})")
3632 << m;
3633 }
3634
3635 // Cyclic
3636 {
3637 QVariantMap m;
3638 m["p"] = QVariantMap();
3639 QTest::newRow(dataTag: "var o={}; o.p=o")
3640 << QString::fromLatin1(str: "var o={}; o.p=o; o")
3641 << m;
3642 }
3643 {
3644 QVariantMap m;
3645 m["p"] = 123;
3646 m["q"] = QVariantMap();
3647 QTest::newRow(dataTag: "var o={}; o.p=123; o.q=o")
3648 << QString::fromLatin1(str: "var o={}; o.p=123; o.q=o; o")
3649 << m;
3650 }
3651}
3652
3653void tst_QScriptExtQObject::nestedObjectAsSlotArgument()
3654{
3655 QFETCH(QString, program);
3656 QFETCH(QVariantMap, expected);
3657 QScriptValue o = m_engine->evaluate(program);
3658 QVERIFY(!o.isError());
3659 QVERIFY(o.isObject());
3660 // Slot that takes QVariantMap
3661 {
3662 QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantMapArg")
3663 .call(QScriptValue(), QScriptValueList() << o).isError());
3664 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
3665 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
3666 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::Map);
3667 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toMap(), expected);
3668 }
3669 // Slot that takes QVariant
3670 {
3671 m_myObject->resetQtFunctionInvoked();
3672 QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantArg")
3673 .call(QScriptValue(), QScriptValueList() << o).isError());
3674 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
3675 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
3676 QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::Map);
3677 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toMap(), expected);
3678 }
3679}
3680
3681// QTBUG-21760
3682void tst_QScriptExtQObject::propertyAccessThroughActivationObject()
3683{
3684 QScriptContext *ctx = m_engine->pushContext();
3685 ctx->setActivationObject(m_engine->newQObject(object: m_myObject));
3686
3687 QVERIFY(m_engine->evaluate("intProperty").isNumber());
3688 QVERIFY(m_engine->evaluate("mySlot()").isUndefined());
3689 QVERIFY(m_engine->evaluate("mySlotWithStringArg('test')").isUndefined());
3690
3691 QVERIFY(m_engine->evaluate("dynamicProperty").isError());
3692 m_myObject->setProperty(name: "dynamicProperty", value: 123);
3693 QCOMPARE(m_engine->evaluate("dynamicProperty").toInt32(), 123);
3694
3695 m_engine->popContext();
3696}
3697
3698class SignalEmitterThread : public QThread
3699{
3700public:
3701 SignalEmitterThread(MyQObject *sender)
3702 : m_sender(sender)
3703 { }
3704
3705 void run()
3706 { m_sender->emitMySignal(); }
3707
3708private:
3709 MyQObject *m_sender;
3710};
3711
3712// QTBUG-26261
3713void tst_QScriptExtQObject::connectionRemovedAfterQueuedCall()
3714{
3715 QVERIFY(m_engine->evaluate("var pass = true; function onMySignal() { pass = false; }").isUndefined());
3716 QVERIFY(m_engine->evaluate("myObject.mySignal.connect(onMySignal)").isUndefined());
3717
3718 SignalEmitterThread thread(m_myObject);
3719 QVERIFY(m_myObject->thread() != &thread); // Premise for queued call
3720 thread.start();
3721 QVERIFY(thread.wait());
3722
3723 QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(onMySignal)").isUndefined());
3724 // Should not crash
3725 QCoreApplication::processEvents();
3726
3727 QVERIFY(m_engine->evaluate("pass").toBool());
3728}
3729
3730// QTBUG-26590
3731void tst_QScriptExtQObject::collectQObjectWithClosureSlot()
3732{
3733 QScriptEngine eng;
3734 QScriptValue fun = eng.evaluate(program: "(function(obj) {\n"
3735 " obj.mySignal.connect(function() { obj.mySlot(); });\n"
3736 "})");
3737 QVERIFY(fun.isFunction());
3738
3739 QPointer<MyQObject> obj = new MyQObject;
3740 {
3741 QScriptValue wrapper = eng.newQObject(object: obj, ownership: QScriptEngine::ScriptOwnership);
3742 QVERIFY(fun.call(QScriptValue(), QScriptValueList() << wrapper).isUndefined());
3743 }
3744 QVERIFY(obj != 0);
3745 QCOMPARE(obj->qtFunctionInvoked(), -1);
3746 obj->emitMySignal();
3747 QCOMPARE(obj->qtFunctionInvoked(), 20);
3748
3749 collectGarbage_helper(eng);
3750 // The closure that's connected to obj's signal has the only JS reference
3751 // to obj, and the closure is only referenced by the connection. Hence, obj
3752 // should have been collected.
3753 if (obj != 0)
3754 QEXPECT_FAIL("", "Test can fail because the garbage collector is conservative", Continue);
3755 QVERIFY(obj == 0);
3756}
3757
3758void tst_QScriptExtQObject::collectQObjectWithClosureSlot2()
3759{
3760 QScriptEngine eng;
3761 QScriptValue fun = eng.evaluate(program: "(function(obj1, obj2) {\n"
3762 " obj2.mySignal.connect(function() { obj1.mySlot(); });\n"
3763 " obj1.mySignal.connect(function() { obj2.mySlot(); });\n"
3764 "})");
3765 QVERIFY(fun.isFunction());
3766
3767 QPointer<MyQObject> obj1 = new MyQObject;
3768 QScriptValue wrapper1 = eng.newQObject(object: obj1, ownership: QScriptEngine::ScriptOwnership);
3769 QPointer<MyQObject> obj2 = new MyQObject;
3770 {
3771 QScriptValue wrapper2 = eng.newQObject(object: obj2, ownership: QScriptEngine::ScriptOwnership);
3772 QVERIFY(fun.call(QScriptValue(), QScriptValueList() << wrapper1 << wrapper2).isUndefined());
3773 }
3774 QVERIFY(obj1 != 0);
3775 QVERIFY(obj2 != 0);
3776
3777 collectGarbage_helper(eng);
3778 // obj1 is referenced by a QScriptValue, so it (and its connections) should not be collected.
3779 QVERIFY(obj1 != 0);
3780 // obj2 is referenced from the closure that's connected to obj1's signal, so it
3781 // (and its connections) should not be collected.
3782 QVERIFY(obj2 != 0);
3783
3784 QCOMPARE(obj2->qtFunctionInvoked(), -1);
3785 obj1->emitMySignal();
3786 QCOMPARE(obj2->qtFunctionInvoked(), 20);
3787
3788 QCOMPARE(obj1->qtFunctionInvoked(), -1);
3789 obj2->emitMySignal();
3790 QCOMPARE(obj1->qtFunctionInvoked(), 20);
3791}
3792
3793QTEST_MAIN(tst_QScriptExtQObject)
3794#include "tst_qscriptextqobject.moc"
3795

source code of qtscript/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp