8b549e480b849d50d4147cb9221744ba23513112
[WebKit-https.git] / WebKit / qt / tests / qwebframe / tst_qwebframe.cpp
1 /*
2     Copyright (C) 2008 Trolltech ASA
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20
21 #include <QtTest/QtTest>
22
23 #include <qwebpage.h>
24 #include <qwidget.h>
25 #include <qwebview.h>
26 #include <qwebframe.h>
27 #include <qwebhistory.h>
28 #include <QRegExp>
29 #include <QNetworkRequest>
30 //TESTED_CLASS=
31 //TESTED_FILES=
32
33 // Task 160192
34 /**
35  * Starts an event loop that runs until the given signal is received.
36  Optionally the event loop
37  * can return earlier on a timeout.
38  *
39  * \return \p true if the requested signal was received
40  *         \p false on timeout
41  */
42 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
43 {
44     QEventLoop loop;
45     QObject::connect(obj, signal, &loop, SLOT(quit()));
46     QTimer timer;
47     QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
48     if (timeout > 0) {
49         QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
50         timer.setSingleShot(true);
51         timer.start(timeout);
52     }
53     loop.exec();
54     return timeoutSpy.isEmpty();
55 }
56
57 /* Mostly a test for the JavaScript related parts of QWebFrame */
58
59
60 struct CustomType {
61     QString string;
62 };
63 Q_DECLARE_METATYPE(CustomType)
64
65 Q_DECLARE_METATYPE(QBrush*)
66 Q_DECLARE_METATYPE(QObjectList)
67 Q_DECLARE_METATYPE(QList<int>)
68 Q_DECLARE_METATYPE(Qt::BrushStyle)
69 Q_DECLARE_METATYPE(QVariantList)
70 Q_DECLARE_METATYPE(QVariantMap)
71
72 class MyQObject : public QObject
73 {
74     Q_OBJECT
75
76     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
77     Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
78     Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
79     Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
80     Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
81     Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
82     Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
83     Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
84     Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
85     Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
86     Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
87     Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
88     Q_ENUMS(Policy Strategy)
89     Q_FLAGS(Ability)
90
91 public:
92     enum Policy {
93         FooPolicy = 0,
94         BarPolicy,
95         BazPolicy
96     };
97
98     enum Strategy {
99         FooStrategy = 10,
100         BarStrategy,
101         BazStrategy
102     };
103
104     enum AbilityFlag {
105         NoAbility  = 0x000,
106         FooAbility = 0x001,
107         BarAbility = 0x080,
108         BazAbility = 0x200,
109         AllAbility = FooAbility | BarAbility | BazAbility
110     };
111
112     Q_DECLARE_FLAGS(Ability, AbilityFlag)
113
114     MyQObject(QObject* parent = 0)
115         : QObject(parent),
116             m_intValue(123),
117             m_variantValue(QLatin1String("foo")),
118             m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
119             m_stringValue(QLatin1String("bar")),
120             m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
121             m_brushValue(QColor(10, 20, 30, 40)),
122             m_hiddenValue(456.0),
123             m_writeOnlyValue(789),
124             m_readOnlyValue(987),
125             m_qtFunctionInvoked(-1) { }
126
127     ~MyQObject() { }
128
129     int intProperty() const {
130         return m_intValue;
131     }
132     void setIntProperty(int value) {
133         m_intValue = value;
134     }
135
136     QVariant variantProperty() const {
137         return m_variantValue;
138     }
139     void setVariantProperty(const QVariant &value) {
140         m_variantValue = value;
141     }
142
143     QVariantList variantListProperty() const {
144         return m_variantListValue;
145     }
146     void setVariantListProperty(const QVariantList &value) {
147         m_variantListValue = value;
148     }
149
150     QString stringProperty() const {
151         return m_stringValue;
152     }
153     void setStringProperty(const QString &value) {
154         m_stringValue = value;
155     }
156
157     QStringList stringListProperty() const {
158         return m_stringListValue;
159     }
160     void setStringListProperty(const QStringList &value) {
161         m_stringListValue = value;
162     }
163
164     QByteArray byteArrayProperty() const {
165         return m_byteArrayValue;
166     }
167     void setByteArrayProperty(const QByteArray &value) {
168         m_byteArrayValue = value;
169     }
170
171     QBrush brushProperty() const {
172         return m_brushValue;
173     }
174     Q_INVOKABLE void setBrushProperty(const QBrush &value) {
175         m_brushValue = value;
176     }
177
178     double hiddenProperty() const {
179         return m_hiddenValue;
180     }
181     void setHiddenProperty(double value) {
182         m_hiddenValue = value;
183     }
184
185     int writeOnlyProperty() const {
186         return m_writeOnlyValue;
187     }
188     void setWriteOnlyProperty(int value) {
189         m_writeOnlyValue = value;
190     }
191
192     int readOnlyProperty() const {
193         return m_readOnlyValue;
194     }
195
196     QKeySequence shortcut() const {
197         return m_shortcut;
198     }
199     void setShortcut(const QKeySequence &seq) {
200         m_shortcut = seq;
201     }
202
203     CustomType propWithCustomType() const {
204         return m_customType;
205     }
206     void setPropWithCustomType(const CustomType &c) {
207         m_customType = c;
208     }
209
210     int qtFunctionInvoked() const {
211         return m_qtFunctionInvoked;
212     }
213
214     QVariantList qtFunctionActuals() const {
215         return m_actuals;
216     }
217
218     void resetQtFunctionInvoked() {
219         m_qtFunctionInvoked = -1;
220         m_actuals.clear();
221     }
222
223     Q_INVOKABLE void myInvokable() {
224         m_qtFunctionInvoked = 0;
225     }
226     Q_INVOKABLE void myInvokableWithIntArg(int arg) {
227         m_qtFunctionInvoked = 1;
228         m_actuals << arg;
229     }
230     Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
231         m_qtFunctionInvoked = 2;
232         m_actuals << arg;
233     }
234     Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
235         m_qtFunctionInvoked = 3;
236         m_actuals << arg;
237     }
238     Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
239         m_qtFunctionInvoked = 4;
240         m_actuals << arg;
241     }
242     Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
243         m_qtFunctionInvoked = 5;
244         m_actuals << arg;
245     }
246     Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
247         m_qtFunctionInvoked = 6;
248         m_actuals << arg1 << arg2;
249     }
250     Q_INVOKABLE int myInvokableReturningInt() {
251         m_qtFunctionInvoked = 7;
252         return 123;
253     }
254     Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
255         m_qtFunctionInvoked = 39;
256         return 456;
257     }
258     Q_INVOKABLE QString myInvokableReturningString() {
259         m_qtFunctionInvoked = 8;
260         return QLatin1String("ciao");
261     }
262     Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
263         m_qtFunctionInvoked = 9;
264         m_actuals << arg1 << arg2;
265     }
266     Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
267         m_qtFunctionInvoked = 10;
268         m_actuals << policy;
269     }
270     Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
271         m_qtFunctionInvoked = 36;
272         m_actuals << policy;
273     }
274     Q_INVOKABLE Policy myInvokableReturningEnum() {
275         m_qtFunctionInvoked = 37;
276         return BazPolicy;
277     }
278     Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
279         m_qtFunctionInvoked = 38;
280         return BazPolicy;
281     }
282     Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
283         m_qtFunctionInvoked = 11;
284         return QVector<int>();
285     }
286     Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
287         m_qtFunctionInvoked = 12;
288     }
289     Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
290         m_qtFunctionInvoked = 13;
291         return this;
292     }
293     Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
294         m_qtFunctionInvoked = 14;
295         m_actuals << qVariantFromValue(lst);
296         return lst;
297     }
298     Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
299         m_qtFunctionInvoked = 15;
300         m_actuals << v;
301         return v;
302     }
303     Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
304         m_qtFunctionInvoked = 16;
305         m_actuals << vm;
306         return vm;
307     }
308     Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
309         m_qtFunctionInvoked = 17;
310         m_actuals << qVariantFromValue(lst);
311         return lst;
312     }
313     Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
314         m_qtFunctionInvoked = 18;
315         m_actuals << qVariantFromValue(obj);
316         return obj;
317     }
318     Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
319         m_qtFunctionInvoked = 19;
320         m_actuals << qVariantFromValue(brush);
321         return brush;
322     }
323     Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
324         m_qtFunctionInvoked = 43;
325         m_actuals << qVariantFromValue(style);
326     }
327     Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
328         m_qtFunctionInvoked = 44;
329         m_actuals << qVariantFromValue(arg);
330     }
331     Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
332         m_qtFunctionInvoked = 45;
333         m_actuals << qVariantFromValue(arg);
334     }
335     Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
336         m_qtFunctionInvoked = 46;
337         m_actuals << qVariantFromValue(arg);
338     }
339     Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
340         m_qtFunctionInvoked = 47;
341         m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2);
342     }
343     Q_INVOKABLE QObject& myInvokableReturningRef() {
344         m_qtFunctionInvoked = 48;
345         return *this;
346     }
347     Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
348         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
349         return *this;
350     }
351     Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
352         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
353         m_actuals << qVariantFromValue(arg);
354     }
355     Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
356         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
357         m_actuals << qVariantFromValue(arg);
358     }
359
360     void emitMySignal() {
361         emit mySignal();
362     }
363     void emitMySignalWithIntArg(int arg) {
364         emit mySignalWithIntArg(arg);
365     }
366     void emitMySignal2(bool arg) {
367         emit mySignal2(arg);
368     }
369     void emitMySignal2() {
370         emit mySignal2();
371     }
372     void emitMySignalWithDateTimeArg(QDateTime dt) {
373         emit mySignalWithDateTimeArg(dt);
374     }
375     void emitMySignalWithRegexArg(QRegExp r) {
376         emit mySignalWithRegexArg(r);
377     }
378
379 public Q_SLOTS:
380     void mySlot() {
381         m_qtFunctionInvoked = 20;
382     }
383     void mySlotWithIntArg(int arg) {
384         m_qtFunctionInvoked = 21;
385         m_actuals << arg;
386     }
387     void mySlotWithDoubleArg(double arg) {
388         m_qtFunctionInvoked = 22;
389         m_actuals << arg;
390     }
391     void mySlotWithStringArg(const QString &arg) {
392         m_qtFunctionInvoked = 23;
393         m_actuals << arg;
394     }
395
396     void myOverloadedSlot() {
397         m_qtFunctionInvoked = 24;
398     }
399     void myOverloadedSlot(QObject* arg) {
400         m_qtFunctionInvoked = 41;
401         m_actuals << arg;
402     }
403     void myOverloadedSlot(bool arg) {
404         m_qtFunctionInvoked = 25;
405         m_actuals << arg;
406     }
407     void myOverloadedSlot(const QStringList &arg) {
408         m_qtFunctionInvoked = 42;
409         m_actuals << arg;
410     }
411     void myOverloadedSlot(double arg) {
412         m_qtFunctionInvoked = 26;
413         m_actuals << arg;
414     }
415     void myOverloadedSlot(float arg) {
416         m_qtFunctionInvoked = 27;
417         m_actuals << arg;
418     }
419     void myOverloadedSlot(int arg) {
420         m_qtFunctionInvoked = 28;
421         m_actuals << arg;
422     }
423     void myOverloadedSlot(const QString &arg) {
424         m_qtFunctionInvoked = 29;
425         m_actuals << arg;
426     }
427     void myOverloadedSlot(const QColor &arg) {
428         m_qtFunctionInvoked = 30;
429         m_actuals << arg;
430     }
431     void myOverloadedSlot(const QBrush &arg) {
432         m_qtFunctionInvoked = 31;
433         m_actuals << arg;
434     }
435     void myOverloadedSlot(const QDateTime &arg) {
436         m_qtFunctionInvoked = 32;
437         m_actuals << arg;
438     }
439     void myOverloadedSlot(const QDate &arg) {
440         m_qtFunctionInvoked = 33;
441         m_actuals << arg;
442     }
443     void myOverloadedSlot(const QRegExp &arg) {
444         m_qtFunctionInvoked = 34;
445         m_actuals << arg;
446     }
447     void myOverloadedSlot(const QVariant &arg) {
448         m_qtFunctionInvoked = 35;
449         m_actuals << arg;
450     }
451
452     void qscript_call(int arg) {
453         m_qtFunctionInvoked = 40;
454         m_actuals << arg;
455     }
456
457 protected Q_SLOTS:
458     void myProtectedSlot() {
459         m_qtFunctionInvoked = 36;
460     }
461
462 private Q_SLOTS:
463     void myPrivateSlot() { }
464
465 Q_SIGNALS:
466     void mySignal();
467     void mySignalWithIntArg(int arg);
468     void mySignalWithDoubleArg(double arg);
469     void mySignal2(bool arg = false);
470     void mySignalWithDateTimeArg(QDateTime dt);
471     void mySignalWithRegexArg(QRegExp r);
472
473 private:
474     int m_intValue;
475     QVariant m_variantValue;
476     QVariantList m_variantListValue;
477     QString m_stringValue;
478     QStringList m_stringListValue;
479     QByteArray m_byteArrayValue;
480     QBrush m_brushValue;
481     double m_hiddenValue;
482     int m_writeOnlyValue;
483     int m_readOnlyValue;
484     QKeySequence m_shortcut;
485     CustomType m_customType;
486     int m_qtFunctionInvoked;
487     QVariantList m_actuals;
488 };
489
490 class MyOtherQObject : public MyQObject
491 {
492 public:
493     MyOtherQObject(QObject* parent = 0)
494         : MyQObject(parent) { }
495 };
496
497 class MyEnumTestQObject : public QObject
498 {
499     Q_OBJECT
500     Q_PROPERTY(QString p1 READ p1)
501     Q_PROPERTY(QString p2 READ p2)
502     Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
503     Q_PROPERTY(QString p4 READ p4)
504     Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
505     Q_PROPERTY(QString p6 READ p6)
506 public:
507     MyEnumTestQObject(QObject* parent = 0)
508         : QObject(parent) { }
509     QString p1() const {
510         return QLatin1String("p1");
511     }
512     QString p2() const {
513         return QLatin1String("p2");
514     }
515     QString p3() const {
516         return QLatin1String("p3");
517     }
518     QString p4() const {
519         return QLatin1String("p4");
520     }
521     QString p5() const {
522         return QLatin1String("p5");
523     }
524     QString p6() const {
525         return QLatin1String("p5");
526     }
527 public Q_SLOTS:
528     void mySlot() { }
529     void myOtherSlot() { }
530 Q_SIGNALS:
531     void mySignal();
532 };
533
534 class tst_QWebFrame : public QObject
535 {
536     Q_OBJECT
537
538 public:
539     tst_QWebFrame();
540     virtual ~tst_QWebFrame();
541
542 public slots:
543     void init();
544     void cleanup();
545
546 private slots:
547     void getSetStaticProperty();
548     void getSetDynamicProperty();
549     void getSetChildren();
550     void callQtInvokable();
551     void connectAndDisconnect();
552     void classEnums();
553     void classConstructor();
554     void overrideInvokable();
555     void transferInvokable();
556     void findChild();
557     void findChildren();
558     void overloadedSlots();
559     void enumerate_data();
560     void enumerate();
561     void objectDeleted();
562     void typeConversion();
563     void symmetricUrl();
564     void progressSignal();
565     void domCycles();
566     void setHtml();
567     void ipv6HostEncoding();
568 private:
569     QString  evalJS(const QString&s) {
570         // Convert an undefined return variant to the string "undefined"
571         QVariant ret = evalJSV(s);
572         if (ret.userType() == QMetaType::Void)
573             return "undefined";
574         else
575             return ret.toString();
576     }
577     QVariant evalJSV(const QString &s) {
578         return m_page->mainFrame()->evaluateJavaScript(s);
579     }
580
581     QString  evalJS(const QString&s, QString& type) {
582         return evalJSV(s, type).toString();
583     }
584     QVariant evalJSV(const QString &s, QString& type) {
585         // As a special measure, if we get an exception we set the type to 'error'
586         // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
587         // Similarly, an array is an object, but we'd prefer to have a type of 'array'
588         // Also, consider a QMetaType::Void QVariant to be undefined
589         QString escaped = s;
590         escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
591         evalJS("var retvalue;\
592                var typevalue; \
593                try {\
594                retvalue = eval('" + escaped + "'); \
595                typevalue = typeof retvalue; \
596                if (retvalue instanceof Array) \
597                typevalue = 'array'; \
598            } \
599                catch(e) {\
600                retvalue = e.name + ': ' + e.message;\
601                typevalue = 'error';\
602            }");
603         QVariant ret = evalJSV("retvalue");
604         if (ret.userType() != QMetaType::Void)
605             type = evalJS("typevalue");
606         else {
607             ret = QString("undefined");
608             type = sUndefined;
609         }
610         evalJS("delete retvalue; delete typevalue");
611         return ret;
612     }
613
614     const QString sTrue;
615     const QString sFalse;
616     const QString sUndefined;
617     const QString sArray;
618     const QString sFunction;
619     const QString sError;
620     const QString sString;
621     const QString sObject;
622     const QString sNumber;
623
624 private:
625     QWebView* m_view;
626     QWebPage* m_page;
627     MyQObject* m_myObject;
628 };
629
630 tst_QWebFrame::tst_QWebFrame()
631     : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
632         sString("string"), sObject("object"), sNumber("number")
633 {
634 }
635
636 tst_QWebFrame::~tst_QWebFrame()
637 {
638 }
639
640 void tst_QWebFrame::init()
641 {
642     m_view = new QWebView();
643     m_page = m_view->page();
644     m_myObject = new MyQObject();
645     m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
646 }
647
648 void tst_QWebFrame::cleanup()
649 {
650     delete m_view;
651     delete m_myObject;
652 }
653
654 void tst_QWebFrame::getSetStaticProperty()
655 {
656     QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
657
658     // initial value (set in MyQObject constructor)
659     {
660         QString type;
661         QVariant ret = evalJSV("myObject.intProperty", type);
662         QCOMPARE(type, sNumber);
663         QCOMPARE(ret.type(), QVariant::Double);
664         QCOMPARE(ret.toInt(), 123);
665     }
666     QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
667
668     {
669         QString type;
670         QVariant ret = evalJSV("myObject.variantProperty", type);
671         QCOMPARE(type, sString);
672         QCOMPARE(ret.type(), QVariant::String);
673         QCOMPARE(ret.toString(), QLatin1String("foo"));
674     }
675     QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
676
677     {
678         QString type;
679         QVariant ret = evalJSV("myObject.stringProperty", type);
680         QCOMPARE(type, sString);
681         QCOMPARE(ret.type(), QVariant::String);
682         QCOMPARE(ret.toString(), QLatin1String("bar"));
683     }
684     QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
685
686     {
687         QString type;
688         QVariant ret = evalJSV("myObject.variantListProperty", type);
689         QCOMPARE(type, sArray);
690         QCOMPARE(ret.type(), QVariant::List);
691         QVariantList vl = ret.value<QVariantList>();
692         QCOMPARE(vl.size(), 2);
693         QCOMPARE(vl.at(0).toInt(), 123);
694         QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
695     }
696     QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
697     QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
698     QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
699
700     {
701         QString type;
702         QVariant ret = evalJSV("myObject.stringListProperty", type);
703         QCOMPARE(type, sArray);
704         QCOMPARE(ret.type(), QVariant::List);
705         QVariantList vl = ret.value<QVariantList>();
706         QCOMPARE(vl.size(), 2);
707         QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
708         QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
709     }
710     QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
711     QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
712     QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
713     QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
714     QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
715
716     // property change in C++ should be reflected in script
717     m_myObject->setIntProperty(456);
718     QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
719     m_myObject->setIntProperty(789);
720     QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
721
722     m_myObject->setVariantProperty(QLatin1String("bar"));
723     QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
724     m_myObject->setVariantProperty(42);
725     QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
726     m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
727 //XFAIL
728 //  QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
729
730     m_myObject->setStringProperty(QLatin1String("baz"));
731     QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
732     m_myObject->setStringProperty(QLatin1String("zab"));
733     QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
734
735     // property change in script should be reflected in C++
736     QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
737     QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
738     QCOMPARE(m_myObject->intProperty(), 123);
739     QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
740                     "myObject.intProperty == 0"), sTrue);
741     QCOMPARE(m_myObject->intProperty(), 0);
742     QCOMPARE(evalJS("myObject.intProperty = '123';"
743                     "myObject.intProperty == 123"), sTrue);
744     QCOMPARE(m_myObject->intProperty(), 123);
745
746     QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
747     QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
748     QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
749     QCOMPARE(evalJS("myObject.stringProperty = 123;"
750                     "myObject.stringProperty"), QLatin1String("123"));
751     QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
752
753     QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
754                     "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
755     QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
756     QCOMPARE(evalJS("myObject.variantProperty = 42;"
757                     "myObject.variantProperty").toDouble(), 42.0);
758     QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
759
760
761     QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
762                     "myObject.variantListProperty.length == 3"), sTrue);
763     QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
764     QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
765     QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
766
767     QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
768                     "myObject.stringListProperty.length == 3"), sTrue);
769     QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
770     QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
771     QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
772     QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
773     QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
774     QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
775
776     // try to delete
777     QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
778     QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
779
780     QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
781     QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
782
783     // non-scriptable property
784     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
785     QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
786     QEXPECT_FAIL("", "undefined properties not supported", Continue);
787     QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
788                     "myObject.hiddenProperty == 123"), sTrue);
789     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
790
791     // write-only property
792     QCOMPARE(m_myObject->writeOnlyProperty(), 789);
793     QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
794     QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
795                     "typeof myObject.writeOnlyProperty"), sUndefined);
796     QCOMPARE(m_myObject->writeOnlyProperty(), 123);
797
798     // read-only property
799     QCOMPARE(m_myObject->readOnlyProperty(), 987);
800     QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
801     QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
802                     "myObject.readOnlyProperty == 987"), sTrue);
803     QCOMPARE(m_myObject->readOnlyProperty(), 987);
804 }
805
806 void tst_QWebFrame::getSetDynamicProperty()
807 {
808     // initially the object does not have the property
809     // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
810
811     //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
812     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
813
814     // add a dynamic property in C++
815     QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
816     //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
817     QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
818     QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
819
820     // property change in script should be reflected in C++
821     QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
822                     "myObject.dynamicProperty"), QLatin1String("foo"));
823     QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
824
825     // delete the property (XFAIL - can't delete properties)
826     QEXPECT_FAIL("", "can't delete properties", Continue);
827     QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
828     /*
829     QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
830     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
831     //    QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
832     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
833     */
834 }
835
836 void tst_QWebFrame::getSetChildren()
837 {
838     // initially the object does not have the child
839     // (again, no hasOwnProperty)
840
841     //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
842     QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
843
844     // add a child
845     MyQObject* child = new MyQObject(m_myObject);
846     child->setObjectName("child");
847 //  QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
848     QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
849
850     // add a grandchild
851     MyQObject* grandChild = new MyQObject(child);
852     grandChild->setObjectName("grandChild");
853 //  QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
854     QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
855
856     // delete grandchild
857     delete grandChild;
858 //  QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
859     QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
860
861     // delete child
862     delete child;
863 //  QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
864     QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
865 }
866
867 Q_DECLARE_METATYPE(QVector<int>)
868 Q_DECLARE_METATYPE(QVector<double>)
869 Q_DECLARE_METATYPE(QVector<QString>)
870
871 void tst_QWebFrame::callQtInvokable()
872 {
873     qRegisterMetaType<QObjectList>();
874
875     m_myObject->resetQtFunctionInvoked();
876     QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
877     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
878     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
879
880     // extra arguments should silently be ignored
881     m_myObject->resetQtFunctionInvoked();
882     QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
883     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
884     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
885
886     m_myObject->resetQtFunctionInvoked();
887     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
888     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
889     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
890     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
891
892     m_myObject->resetQtFunctionInvoked();
893     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
894     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
895     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
896     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
897
898     m_myObject->resetQtFunctionInvoked();
899     QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
900     QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
901     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
902     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
903
904     m_myObject->resetQtFunctionInvoked();
905     QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
906     QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
907     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
908     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
909
910     m_myObject->resetQtFunctionInvoked();
911     QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
912     QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
913     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
914     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
915
916     m_myObject->resetQtFunctionInvoked();
917     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
918     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
919     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
920     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
921
922     m_myObject->resetQtFunctionInvoked();
923     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
924     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
925     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
926     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
927
928     m_myObject->resetQtFunctionInvoked();
929     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
930     QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
931     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
932     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
933     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
934
935     m_myObject->resetQtFunctionInvoked();
936     QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
937     QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
938     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
939
940     m_myObject->resetQtFunctionInvoked();
941     QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
942     QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
943     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
944
945     m_myObject->resetQtFunctionInvoked();
946     QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
947     QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
948     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
949
950     m_myObject->resetQtFunctionInvoked();
951     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
952     QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
953     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
954     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
955     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
956
957     m_myObject->resetQtFunctionInvoked();
958     QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
959     QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
960     m_myObject->resetQtFunctionInvoked();
961     {
962         QString type;
963         QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
964         QCOMPARE(type, sError);
965         QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n    myInvokableWithVoidStarArg(void*)"));
966         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
967     }
968
969     m_myObject->resetQtFunctionInvoked();
970     {
971         QString type;
972         QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
973         QCOMPARE(type, sError);
974         QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n    myInvokableWithAmbiguousArg(int)\n    myInvokableWithAmbiguousArg(uint)"));
975     }
976
977     m_myObject->resetQtFunctionInvoked();
978     {
979         QString type;
980         QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
981         QCOMPARE(type, sUndefined);
982         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
983         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
984         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
985         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
986     }
987
988     m_myObject->resetQtFunctionInvoked();
989     {
990         QString type;
991         QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
992         QCOMPARE(type, sUndefined);
993         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
994         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
995         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
996         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
997     }
998
999     // calling function that returns (const)ref
1000     m_myObject->resetQtFunctionInvoked();
1001     {
1002         QString type;
1003         QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
1004         QCOMPARE(ret, sUndefined);
1005         //QVERIFY(!m_engine->hasUncaughtException());
1006         QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1007     }
1008
1009     m_myObject->resetQtFunctionInvoked();
1010     {
1011         QString type;
1012         QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
1013         QCOMPARE(ret, sUndefined);
1014         //QVERIFY(!m_engine->hasUncaughtException());
1015         QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1016     }
1017
1018     m_myObject->resetQtFunctionInvoked();
1019     {
1020         QString type;
1021         QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
1022         QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1023         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1024         QCOMPARE(type, sFunction);
1025         QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1026     }
1027
1028     m_myObject->resetQtFunctionInvoked();
1029     {
1030         QString type;
1031         QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
1032         QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1033         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1034         QCOMPARE(type, sArray);
1035         QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
1036         QVariantList vl = qvariant_cast<QVariantList>(ret);
1037         QCOMPARE(vl.count(), 1);
1038     }
1039
1040     m_myObject->resetQtFunctionInvoked();
1041     {
1042         QString type;
1043         m_myObject->setVariantProperty(QVariant(123));
1044         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
1045         QCOMPARE(type, sNumber);
1046         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1047         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1048         QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1049         QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
1050         QCOMPARE(ret.toInt(),123);
1051     }
1052
1053     /* XFAIL - variant support
1054     m_myObject->resetQtFunctionInvoked();
1055     {
1056         m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
1057         QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1058         QVERIFY(ret.isVariant());
1059         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1060         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1061         QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1062         QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1063     }
1064     */
1065
1066     m_myObject->resetQtFunctionInvoked();
1067     {
1068         QString type;
1069         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
1070         QCOMPARE(type, sNumber);
1071         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1072         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1073         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1074         QCOMPARE(ret.userType(), int(QMetaType::Double));
1075         QCOMPARE(ret.toInt(),123);
1076     }
1077
1078     m_myObject->resetQtFunctionInvoked();
1079     {
1080         QString type;
1081         QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
1082         QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1083         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1084
1085         QVariant v = m_myObject->qtFunctionActuals().at(0);
1086         QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1087
1088         QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1089         QCOMPARE(vmap.keys().size(), 2);
1090         QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1091         QCOMPARE(vmap.value("a"), QVariant(123));
1092         QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1093         QCOMPARE(vmap.value("b"), QVariant("ciao"));
1094
1095         QCOMPARE(type, sObject);
1096
1097         QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
1098         vmap = qvariant_cast<QVariantMap>(ret);
1099         QCOMPARE(vmap.keys().size(), 2);
1100         QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1101         QCOMPARE(vmap.value("a"), QVariant(123));
1102         QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1103         QCOMPARE(vmap.value("b"), QVariant("ciao"));
1104     }
1105
1106     m_myObject->resetQtFunctionInvoked();
1107     {
1108         QString type;
1109         QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
1110         QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1111         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1112         QVariant v = m_myObject->qtFunctionActuals().at(0);
1113         QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1114         QList<int> ilst = qvariant_cast<QList<int> >(v);
1115         QCOMPARE(ilst.size(), 2);
1116         QCOMPARE(ilst.at(0), 1);
1117         QCOMPARE(ilst.at(1), 5);
1118
1119         QCOMPARE(type, sArray);
1120         QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
1121         QVariantList vlst = qvariant_cast<QVariantList>(ret);
1122         QCOMPARE(vlst.size(), 2);
1123         QCOMPARE(vlst.at(0).toInt(), 1);
1124         QCOMPARE(vlst.at(1).toInt(), 5);
1125     }
1126
1127     m_myObject->resetQtFunctionInvoked();
1128     {
1129         QString type;
1130         QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
1131         QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1132         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1133         QVariant v = m_myObject->qtFunctionActuals().at(0);
1134         QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1135         QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
1136
1137         QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1138         QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
1139
1140         QCOMPARE(type, sFunction); // implements call, so Function, not object
1141     }
1142
1143     m_myObject->resetQtFunctionInvoked();
1144     {
1145         // no implicit conversion from integer to QObject*
1146         QString type;
1147         evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
1148         QCOMPARE(type, sError);
1149     }
1150
1151     /*
1152     m_myObject->resetQtFunctionInvoked();
1153     {
1154         QString fun = evalJS("myObject.myInvokableWithQBrushArg");
1155         Q_ASSERT(fun.isFunction());
1156         QColor color(10, 20, 30, 40);
1157         // QColor should be converted to a QBrush
1158         QVariant ret = fun.call(QString(), QStringList()
1159                                     << qScriptValueFromValue(m_engine, color));
1160         QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1161         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1162         QVariant v = m_myObject->qtFunctionActuals().at(0);
1163         QCOMPARE(v.userType(), int(QMetaType::QBrush));
1164         QCOMPARE(qvariant_cast<QColor>(v), color);
1165
1166         QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1167     }
1168     */
1169
1170     // private slots should not be part of the QObject binding
1171     QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
1172
1173     // protected slots should be fine
1174     m_myObject->resetQtFunctionInvoked();
1175     evalJS("myObject.myProtectedSlot()");
1176     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1177
1178     // call with too few arguments
1179     {
1180         QString type;
1181         QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
1182         QCOMPARE(type, sError);
1183         QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n    myInvokableWithIntArg(int,int)\n    myInvokableWithIntArg(int)"));
1184     }
1185
1186     // call function where not all types have been registered
1187     m_myObject->resetQtFunctionInvoked();
1188     {
1189         QString type;
1190         QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
1191         QCOMPARE(type, sError);
1192         QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
1193         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1194     }
1195
1196     // call function with incompatible argument type
1197     m_myObject->resetQtFunctionInvoked();
1198     {
1199         QString type;
1200         QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
1201         QCOMPARE(type, sError);
1202         QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n    myInvokableWithQBrushArg(QBrush)"));
1203         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1204     }
1205
1206     // qscript_call()
1207     {
1208         m_myObject->resetQtFunctionInvoked();
1209         QString type;
1210         evalJS("new myObject(123)", type);
1211         QCOMPARE(type, sObject);
1212         QCOMPARE(m_myObject->qtFunctionInvoked(), 40);
1213         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1214         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1215     }
1216     {
1217         m_myObject->resetQtFunctionInvoked();
1218         QString type;
1219         evalJS("myObject(123)", type);
1220         QCOMPARE(type, sUndefined);
1221         QCOMPARE(m_myObject->qtFunctionInvoked(), 40);
1222         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1223         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1224     }
1225 }
1226
1227 void tst_QWebFrame::connectAndDisconnect()
1228 {
1229     // connect(function)
1230     QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
1231     QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
1232     QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
1233
1234     {
1235         QString type;
1236         evalJS("myObject.mySignal.connect(123)", type);
1237         QCOMPARE(type, sError);
1238     }
1239
1240     evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
1241
1242     QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
1243
1244     evalJS("gotSignal = false");
1245     evalJS("myObject.mySignal()");
1246     QCOMPARE(evalJS("gotSignal"), sTrue);
1247     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1248     QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1249     QCOMPARE(evalJS("slotThisObject == window"), sTrue);
1250
1251     evalJS("gotSignal = false");
1252     m_myObject->emitMySignal();
1253     QCOMPARE(evalJS("gotSignal"), sTrue);
1254     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1255
1256     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
1257
1258     evalJS("gotSignal = false");
1259     m_myObject->emitMySignalWithIntArg(123);
1260     QCOMPARE(evalJS("gotSignal"), sTrue);
1261     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1262     QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
1263
1264     QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
1265     {
1266         QString type;
1267         evalJS("myObject.mySignal.disconnect(myHandler)", type);
1268         QCOMPARE(type, sError);
1269     }
1270
1271     evalJS("gotSignal = false");
1272     QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
1273     m_myObject->emitMySignal2(true);
1274     QCOMPARE(evalJS("gotSignal"), sTrue);
1275     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1276     QCOMPARE(evalJS("signalArgs[0]"), sTrue);
1277
1278     QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
1279
1280     QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
1281     QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
1282     QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
1283
1284     QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
1285
1286     evalJS("gotSignal = false");
1287     m_myObject->emitMySignal2();
1288     QCOMPARE(evalJS("gotSignal"), sTrue);
1289
1290     QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
1291
1292     // connect(object, function)
1293     evalJS("otherObject = { name:'foo' }");
1294     QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1295     QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1296     evalJS("gotSignal = false");
1297     m_myObject->emitMySignal();
1298     QCOMPARE(evalJS("gotSignal"), sFalse);
1299
1300     {
1301         QString type;
1302         evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
1303         QCOMPARE(type, sError);
1304     }
1305
1306     QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1307     evalJS("gotSignal = false");
1308     m_myObject->emitMySignal();
1309     QCOMPARE(evalJS("gotSignal"), sTrue);
1310     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1311     QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
1312     QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1313     QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
1314     QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1315
1316     evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
1317     QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
1318     evalJS("gotSignal = false");
1319     m_myObject->emitMySignal2(true);
1320     QCOMPARE(evalJS("gotSignal"), sTrue);
1321     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1322     QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
1323     QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1324     QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
1325     QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
1326
1327     QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
1328     evalJS("gotSignal = false");
1329     m_myObject->emitMySignal2(true);
1330     QCOMPARE(evalJS("gotSignal"), sTrue);
1331     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1332     QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
1333     QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1334     QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
1335
1336     // connect(obj, string)
1337     QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
1338     QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
1339     QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
1340     QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
1341
1342     // check that emitting signals from script works
1343
1344     // no arguments
1345     QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1346     m_myObject->resetQtFunctionInvoked();
1347     QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
1348     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1349     QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
1350
1351     // one argument
1352     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
1353     m_myObject->resetQtFunctionInvoked();
1354     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1355     QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
1356     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1357     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1358     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
1359
1360     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
1361     m_myObject->resetQtFunctionInvoked();
1362     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1363     QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
1364     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1365     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
1366     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
1367
1368     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
1369     m_myObject->resetQtFunctionInvoked();
1370     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1371     QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
1372     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1373     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1374     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
1375
1376     // connecting to overloaded slot
1377     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
1378     m_myObject->resetQtFunctionInvoked();
1379     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1380     QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
1381     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1382     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1383     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
1384
1385     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1386     m_myObject->resetQtFunctionInvoked();
1387     QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1388     QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1389     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1390     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1391     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1392
1393     // erroneous input
1394     {
1395         // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
1396         QString type;
1397         QString ret = evalJS("(function() { }).connect()", type);
1398         QCOMPARE(type, sError);
1399         QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression (function ()\n{\n}).connect) is not object."));
1400     }
1401     {
1402         QString type;
1403         QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect;  o.connect()", type);
1404         QCOMPARE(type, sError);
1405         QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression o.connect) is not object."));
1406     }
1407
1408     {
1409         QString type;
1410         QString ret = evalJS("(function() { }).connect(123)", type);
1411         QCOMPARE(type, sError);
1412         QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression (function ()\n{\n}).connect) is not object."));
1413     }
1414     {
1415         QString type;
1416         QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect;  o.connect(123)", type);
1417         QCOMPARE(type, sError);
1418         QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression o.connect) is not object."));
1419     }
1420
1421     {
1422         QString type;
1423         QString ret = evalJS("myObject.myInvokable.connect(123)", type);
1424         QCOMPARE(type, sError);
1425         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1426     }
1427     {
1428         QString type;
1429         QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
1430         QCOMPARE(type, sError);
1431         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1432     }
1433
1434     {
1435         QString type;
1436         QString ret = evalJS("myObject.mySignal.connect(123)", type);
1437         QCOMPARE(type, sError);
1438         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
1439     }
1440
1441     {
1442         QString type;
1443         QString ret = evalJS("myObject.mySignal.disconnect()", type);
1444         QCOMPARE(type, sError);
1445         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1446     }
1447     {
1448         QString type;
1449         QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect;  o.disconnect()", type);
1450         QCOMPARE(type, sError);
1451         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1452     }
1453
1454     /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
1455     {
1456         QString type;
1457         QString ret = evalJS("(function() { }).disconnect(123)", type);
1458         QCOMPARE(type, sError);
1459         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
1460     }
1461     */
1462
1463     {
1464         QString type;
1465         QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
1466         QCOMPARE(type, sError);
1467         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1468     }
1469
1470     {
1471         QString type;
1472         QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
1473         QCOMPARE(type, sError);
1474         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1475     }
1476     {
1477         QString type;
1478         QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
1479         QCOMPARE(type, sError);
1480         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1481     }
1482
1483     {
1484         QString type;
1485         QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
1486         QCOMPARE(type, sError);
1487         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
1488     }
1489
1490     {
1491         QString type;
1492         QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
1493         QCOMPARE(type, sError);
1494         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
1495     }
1496
1497     // when the wrapper dies, the connection stays alive
1498     QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1499     m_myObject->resetQtFunctionInvoked();
1500     m_myObject->emitMySignal();
1501     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1502     evalJS("myObject = null");
1503     evalJS("gc()");
1504     m_myObject->resetQtFunctionInvoked();
1505     m_myObject->emitMySignal();
1506     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1507 }
1508
1509 void tst_QWebFrame::classEnums()
1510 {
1511     // We don't do the meta thing currently, unfortunately!!!
1512     /*
1513     QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
1514     m_engine->globalObject().setProperty("MyQObject", myClass);
1515
1516     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
1517              MyQObject::FooPolicy);
1518     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
1519              MyQObject::BarPolicy);
1520     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
1521              MyQObject::BazPolicy);
1522
1523     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
1524              MyQObject::FooStrategy);
1525     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
1526              MyQObject::BarStrategy);
1527     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
1528              MyQObject::BazStrategy);
1529
1530     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
1531              MyQObject::NoAbility);
1532     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
1533              MyQObject::FooAbility);
1534     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
1535              MyQObject::BarAbility);
1536     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
1537              MyQObject::BazAbility);
1538     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
1539              MyQObject::AllAbility);
1540
1541     // enums from Qt are inherited through prototype
1542     QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
1543              Qt::StrongFocus);
1544     QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
1545              Qt::Key_Left);
1546
1547     QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
1548
1549     qRegisterMetaType<MyQObject::Policy>("Policy");
1550
1551     m_myObject->resetQtFunctionInvoked();
1552     QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
1553     QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
1554     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1555     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1556
1557     m_myObject->resetQtFunctionInvoked();
1558     QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
1559     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1560     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1561     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1562
1563     m_myObject->resetQtFunctionInvoked();
1564     {
1565         QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
1566         QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
1567         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1568         QCOMPARE(ret.isVariant());
1569     }
1570     m_myObject->resetQtFunctionInvoked();
1571     {
1572         QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
1573         QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
1574         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1575         QCOMPARE(ret.isNumber());
1576     }
1577     */
1578 }
1579
1580 void tst_QWebFrame::classConstructor()
1581 {
1582     /*
1583     QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
1584     m_engine->globalObject().setProperty("MyQObject", myClass);
1585
1586     QString myObj = evalJS("myObj = MyQObject()");
1587     QObject* qobj = myObj.toQObject();
1588     QVERIFY(qobj != 0);
1589     QCOMPARE(qobj->metaObject()->className(), "MyQObject");
1590     QCOMPARE(qobj->parent(), (QObject*)0);
1591
1592     QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
1593     m_engine->globalObject().setProperty("QObject", qobjectClass);
1594
1595     QString otherObj = evalJS("otherObj = QObject(myObj)");
1596     QObject* qqobj = otherObj.toQObject();
1597     QVERIFY(qqobj != 0);
1598     QCOMPARE(qqobj->metaObject()->className(), "QObject");
1599     QCOMPARE(qqobj->parent(), qobj);
1600
1601     delete qobj;
1602     */
1603 }
1604
1605 void tst_QWebFrame::overrideInvokable()
1606 {
1607     m_myObject->resetQtFunctionInvoked();
1608     QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
1609     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1610
1611     /* XFAIL - can't write to functions with RuntimeObject
1612     m_myObject->resetQtFunctionInvoked();
1613     evalJS("myObject.myInvokable = function() { window.a = 123; }");
1614     evalJS("myObject.myInvokable()");
1615     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1616     QCOMPARE(evalJS("window.a").toDouble(), 123.0);
1617
1618     evalJS("myObject.myInvokable = function() { window.a = 456; }");
1619     evalJS("myObject.myInvokable()");
1620     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1621     QCOMPARE(evalJS("window.a").toDouble(), 456.0);
1622     */
1623
1624     evalJS("delete myObject.myInvokable");
1625     evalJS("myObject.myInvokable()");
1626     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1627
1628     /* XFAIL - ditto
1629     m_myObject->resetQtFunctionInvoked();
1630     evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1631     evalJS("myObject.myInvokable(123)");
1632     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1633     */
1634
1635     evalJS("delete myObject.myInvokable");
1636     m_myObject->resetQtFunctionInvoked();
1637     // this form (with the '()') is read-only
1638     evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
1639     evalJS("myObject.myInvokable()");
1640     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1641 }
1642
1643 void tst_QWebFrame::transferInvokable()
1644 {
1645     /* XFAIL - can't put to functions with RuntimeObject
1646     m_myObject->resetQtFunctionInvoked();
1647     evalJS("myObject.foozball = myObject.myInvokable");
1648     evalJS("myObject.foozball()");
1649     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1650     m_myObject->resetQtFunctionInvoked();
1651     evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
1652     evalJS("myObject.foozball(123)");
1653     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1654     m_myObject->resetQtFunctionInvoked();
1655     evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1656     evalJS("myObject.myInvokable(123)");
1657     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1658
1659     MyOtherQObject other;
1660     m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
1661     evalJS("myOtherObject.foo = myObject.foozball");
1662     other.resetQtFunctionInvoked();
1663     evalJS("myOtherObject.foo(456)");
1664     QCOMPARE(other.qtFunctionInvoked(), 1);
1665     */
1666 }
1667
1668 void tst_QWebFrame::findChild()
1669 {
1670     /*
1671     QObject* child = new QObject(m_myObject);
1672     child->setObjectName(QLatin1String("myChildObject"));
1673
1674     {
1675         QString result = evalJS("myObject.findChild('noSuchChild')");
1676         QCOMPARE(result.isNull());
1677     }
1678
1679     {
1680         QString result = evalJS("myObject.findChild('myChildObject')");
1681         QCOMPARE(result.isQObject());
1682         QCOMPARE(result.toQObject(), child);
1683     }
1684
1685     delete child;
1686     */
1687 }
1688
1689 void tst_QWebFrame::findChildren()
1690 {
1691     /*
1692     QObject* child = new QObject(m_myObject);
1693     child->setObjectName(QLatin1String("myChildObject"));
1694
1695     {
1696         QString result = evalJS("myObject.findChildren('noSuchChild')");
1697         QCOMPARE(result.isArray());
1698         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
1699     }
1700
1701     {
1702         QString result = evalJS("myObject.findChildren('myChildObject')");
1703         QCOMPARE(result.isArray());
1704         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1705         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1706     }
1707
1708     QObject* namelessChild = new QObject(m_myObject);
1709
1710     {
1711         QString result = evalJS("myObject.findChildren('myChildObject')");
1712         QCOMPARE(result.isArray());
1713         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1714         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1715     }
1716
1717     QObject* anotherChild = new QObject(m_myObject);
1718     anotherChild->setObjectName(QLatin1String("anotherChildObject"));
1719
1720     {
1721         QString result = evalJS("myObject.findChildren('anotherChildObject')");
1722         QCOMPARE(result.isArray());
1723         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1724         QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
1725     }
1726
1727     anotherChild->setObjectName(QLatin1String("myChildObject"));
1728     {
1729         QString result = evalJS("myObject.findChildren('myChildObject')");
1730         QCOMPARE(result.isArray());
1731         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
1732         QObject* o1 = result.property(QLatin1String("0")).toQObject();
1733         QObject* o2 = result.property(QLatin1String("1")).toQObject();
1734         if (o1 != child) {
1735             QCOMPARE(o1, anotherChild);
1736             QCOMPARE(o2, child);
1737         } else {
1738             QCOMPARE(o1, child);
1739             QCOMPARE(o2, anotherChild);
1740         }
1741     }
1742
1743     // find all
1744     {
1745         QString result = evalJS("myObject.findChildren()");
1746         QVERIFY(result.isArray());
1747         int count = 3;
1748         QCOMPARE(result.property("length"), QLatin1String(count);
1749         for (int i = 0; i < 3; ++i) {
1750             QObject* o = result.property(i).toQObject();
1751             if (o == namelessChild || o == child || o == anotherChild)
1752                 --count;
1753         }
1754         QVERIFY(count == 0);
1755     }
1756
1757     delete anotherChild;
1758     delete namelessChild;
1759     delete child;
1760     */
1761 }
1762
1763 void tst_QWebFrame::overloadedSlots()
1764 {
1765     // should pick myOverloadedSlot(double)
1766     m_myObject->resetQtFunctionInvoked();
1767     evalJS("myObject.myOverloadedSlot(10)");
1768     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1769
1770     // should pick myOverloadedSlot(double)
1771     m_myObject->resetQtFunctionInvoked();
1772     evalJS("myObject.myOverloadedSlot(10.0)");
1773     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1774
1775     // should pick myOverloadedSlot(QString)
1776     m_myObject->resetQtFunctionInvoked();
1777     evalJS("myObject.myOverloadedSlot('10')");
1778     QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
1779
1780     // should pick myOverloadedSlot(bool)
1781     m_myObject->resetQtFunctionInvoked();
1782     evalJS("myObject.myOverloadedSlot(true)");
1783     QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
1784
1785     // should pick myOverloadedSlot(QDateTime)
1786     m_myObject->resetQtFunctionInvoked();
1787     evalJS("myObject.myOverloadedSlot(new Date())");
1788     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1789
1790     // should pick myOverloadedSlot(QRegExp)
1791     m_myObject->resetQtFunctionInvoked();
1792     evalJS("myObject.myOverloadedSlot(new RegExp())");
1793     QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
1794
1795     // should pick myOverloadedSlot(QVariant)
1796     /* XFAIL
1797     m_myObject->resetQtFunctionInvoked();
1798     QString f = evalJS("myObject.myOverloadedSlot");
1799     f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
1800     QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
1801     */
1802     // should pick myOverloadedSlot(QObject*)
1803     m_myObject->resetQtFunctionInvoked();
1804     evalJS("myObject.myOverloadedSlot(myObject)");
1805     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1806
1807     // should pick myOverloadedSlot(QObject*)
1808     m_myObject->resetQtFunctionInvoked();
1809     evalJS("myObject.myOverloadedSlot(null)");
1810     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1811
1812     // should pick myOverloadedSlot(QStringList)
1813     m_myObject->resetQtFunctionInvoked();
1814     evalJS("myObject.myOverloadedSlot(['hello'])");
1815     QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
1816 }
1817
1818 void tst_QWebFrame::enumerate_data()
1819 {
1820     QTest::addColumn<QStringList>("expectedNames");
1821
1822     QTest::newRow("enumerate all")
1823     << (QStringList()
1824         // meta-object-defined properties:
1825         //   inherited
1826         << "objectName"
1827         //   non-inherited
1828         << "p1" << "p2" << "p4" << "p6"
1829         // dynamic properties
1830         << "dp1" << "dp2" << "dp3"
1831         // inherited slots
1832         << "destroyed(QObject*)" << "destroyed()"
1833         << "deleteLater()"
1834         // not included because it's private:
1835         // << "_q_reregisterTimers(void*)"
1836         // signals
1837         << "mySignal()"
1838         // slots
1839         << "mySlot()" << "myOtherSlot()");
1840 }
1841
1842 void tst_QWebFrame::enumerate()
1843 {
1844     QFETCH(QStringList, expectedNames);
1845
1846     MyEnumTestQObject enumQObject;
1847     // give it some dynamic properties
1848     enumQObject.setProperty("dp1", "dp1");
1849     enumQObject.setProperty("dp2", "dp2");
1850     enumQObject.setProperty("dp3", "dp3");
1851     m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
1852
1853     // enumerate in script
1854     {
1855         evalJS("var enumeratedProperties = []");
1856         evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
1857         QStringList result = evalJSV("enumeratedProperties").toStringList();
1858         QCOMPARE(result.size(), expectedNames.size());
1859         for (int i = 0; i < expectedNames.size(); ++i)
1860             QCOMPARE(result.at(i), expectedNames.at(i));
1861     }
1862 }
1863
1864 void tst_QWebFrame::objectDeleted()
1865 {
1866     MyQObject* qobj = new MyQObject();
1867     m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
1868     evalJS("bar.objectName = 'foo';");
1869     QCOMPARE(qobj->objectName(), QLatin1String("foo"));
1870     evalJS("bar.intProperty = 123;");
1871     QCOMPARE(qobj->intProperty(), 123);
1872     qobj->resetQtFunctionInvoked();
1873     evalJS("bar.myInvokable.call(bar);");
1874     QCOMPARE(qobj->qtFunctionInvoked(), 0);
1875
1876     // do this, to ensure that we cache that it implements call
1877     evalJS("bar()");
1878
1879     // now delete the object
1880     delete qobj;
1881
1882     QCOMPARE(evalJS("typeof bar"), sFunction);
1883
1884     // any attempt to access properties of the object should result in an exception
1885     {
1886         QString type;
1887         QString ret = evalJS("bar.objectName", type);
1888         QCOMPARE(type, sError);
1889         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1890     }
1891     {
1892         QString type;
1893         QString ret = evalJS("bar.objectName = 'foo'", type);
1894         QCOMPARE(type, sError);
1895         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1896     }
1897
1898     {
1899         QString type;
1900         QString ret = evalJS("bar()", type);
1901         QCOMPARE(type, sError);
1902         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1903     }
1904
1905     // myInvokable is stored in member table (since we've accessed it before deletion)
1906     {
1907         QString type;
1908         evalJS("bar.myInvokable", type);
1909         QCOMPARE(type, sFunction);
1910     }
1911
1912     {
1913         QString type;
1914         QString ret = evalJS("bar.myInvokable.call(bar);", type);
1915         ret = evalJS("bar.myInvokable(bar)", type);
1916         QCOMPARE(type, sError);
1917         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1918     }
1919     // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
1920     {
1921         QString type;
1922         QString ret = evalJS("bar.myInvokableWithIntArg", type);
1923         QCOMPARE(type, sError);
1924         QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1925     }
1926
1927     // access from script
1928     evalJS("window.o = bar;");
1929     {
1930         QString type;
1931         QString ret = evalJS("o()", type);
1932         QCOMPARE(type, sError);
1933         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1934     }
1935     {
1936         QString type;
1937         QString ret = evalJS("o.objectName", type);
1938         QCOMPARE(type, sError);
1939         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1940     }
1941     {
1942         QString type;
1943         QString ret = evalJS("o.myInvokable()", type);
1944         QCOMPARE(type, sError);
1945         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1946     }
1947     {
1948         QString type;
1949         QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
1950         QCOMPARE(type, sError);
1951         QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1952     }
1953 }
1954
1955 void tst_QWebFrame::typeConversion()
1956 {
1957     m_myObject->resetQtFunctionInvoked();
1958
1959     QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
1960     QDateTime utclocaldt = localdt.toUTC();
1961     QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
1962
1963     // Dates in JS (default to local)
1964     evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
1965     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1966     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1967     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
1968
1969     m_myObject->resetQtFunctionInvoked();
1970     evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
1971     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1972     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1973     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
1974
1975     // Pushing QDateTimes into JS
1976     // Local
1977     evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
1978     evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1979     m_myObject->emitMySignalWithDateTimeArg(localdt);
1980     QCOMPARE(evalJS("window.__date_equals"), sTrue);
1981     evalJS("delete window.__date_equals");
1982     m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
1983     QCOMPARE(evalJS("window.__date_equals"), sTrue);
1984     evalJS("delete window.__date_equals");
1985     evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1986
1987     // UTC
1988     evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
1989     evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1990     m_myObject->emitMySignalWithDateTimeArg(utcdt);
1991     QCOMPARE(evalJS("window.__date_equals"), sTrue);
1992     evalJS("delete window.__date_equals");
1993     evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1994
1995     // ### RegExps
1996 }
1997
1998 void tst_QWebFrame::symmetricUrl()
1999 {
2000     QVERIFY(m_view->url().isEmpty());
2001
2002     QCOMPARE(m_view->history()->count(), 0);
2003
2004     QUrl dataUrl("data:text/html,<h1>Test");
2005
2006     m_view->setUrl(dataUrl);
2007     QCOMPARE(m_view->url(), dataUrl);
2008     QCOMPARE(m_view->history()->count(), 0);
2009
2010     // loading is _not_ immediate, so the text isn't set just yet.
2011     QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
2012
2013     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2014
2015     QCOMPARE(m_view->history()->count(), 1);
2016     QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
2017
2018     QUrl dataUrl2("data:text/html,<h1>Test2");
2019     QUrl dataUrl3("data:text/html,<h1>Test3");
2020
2021     m_view->setUrl(dataUrl2);
2022     m_view->setUrl(dataUrl3);
2023
2024     QCOMPARE(m_view->url(), dataUrl3);
2025
2026     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2027
2028     QCOMPARE(m_view->history()->count(), 2);
2029
2030     QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
2031 }
2032
2033 void tst_QWebFrame::progressSignal()
2034 {
2035     QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
2036
2037     QUrl dataUrl("data:text/html,<h1>Test");
2038     m_view->setUrl(dataUrl);
2039
2040     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2041
2042     QVERIFY(progressSpy.size() >= 2);
2043
2044     // WebKit defines initialProgressValue as 10%, not 0%
2045     QCOMPARE(progressSpy.first().first().toInt(), 10);
2046
2047     // But we always end at 100%
2048     QCOMPARE(progressSpy.last().first().toInt(), 100);
2049 }
2050
2051 void tst_QWebFrame::domCycles()
2052 {
2053     m_view->setHtml("<html><body>");
2054     QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
2055     QVERIFY(v.type() == QVariant::Map);
2056 }
2057
2058 void tst_QWebFrame::setHtml()
2059 {
2060     QString html("<html><body><p>hello world</p></body></html>");
2061     m_view->page()->mainFrame()->setHtml(html);
2062     QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2063 }
2064
2065 class TestNetworkManager : public QNetworkAccessManager
2066 {
2067 public:
2068     TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
2069
2070     QList<QUrl> requestedUrls;
2071
2072 protected:
2073     virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
2074         requestedUrls.append(request.url());
2075         QNetworkRequest redirectedRequest = request;
2076         redirectedRequest.setUrl(QUrl("data:text/html,<p>hello"));
2077         return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData);
2078     }
2079 };
2080
2081 void tst_QWebFrame::ipv6HostEncoding()
2082 {
2083     TestNetworkManager* networkManager = new TestNetworkManager(m_page);
2084     m_page->setNetworkAccessManager(networkManager);
2085     networkManager->requestedUrls.clear();
2086
2087     QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html");
2088     m_view->setHtml("<p>Hi", baseUrl);
2089     m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();"
2090             "r.open('GET', 'http://[::1]/test.xml', false);"
2091             "r.send(null);"
2092             );
2093     QCOMPARE(networkManager->requestedUrls.count(), 1);
2094     QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml"));
2095 }
2096
2097 QTEST_MAIN(tst_QWebFrame)
2098 #include "tst_qwebframe.moc"