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