WebKit/qt/tests/qwebframe/tst_qwebframe.cpp
changeset 2 303757a437d3
parent 0 4f2f89ce4247
equal deleted inserted replaced
0:4f2f89ce4247 2:303757a437d3
     1 /*
       
     2     Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
       
     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 <qwebelement.h>
       
    25 #include <qwidget.h>
       
    26 #include <qwebview.h>
       
    27 #include <qwebframe.h>
       
    28 #include <qwebhistory.h>
       
    29 #include <QAbstractItemView>
       
    30 #include <QApplication>
       
    31 #include <QComboBox>
       
    32 #include <QPicture>
       
    33 #include <QRegExp>
       
    34 #include <QNetworkRequest>
       
    35 #include <QNetworkReply>
       
    36 #ifndef QT_NO_OPENSSL
       
    37 #include <qsslerror.h>
       
    38 #endif
       
    39 #include "../util.h"
       
    40 
       
    41 struct CustomType {
       
    42     QString string;
       
    43 };
       
    44 Q_DECLARE_METATYPE(CustomType)
       
    45 
       
    46 Q_DECLARE_METATYPE(QBrush*)
       
    47 Q_DECLARE_METATYPE(QObjectList)
       
    48 Q_DECLARE_METATYPE(QList<int>)
       
    49 Q_DECLARE_METATYPE(Qt::BrushStyle)
       
    50 Q_DECLARE_METATYPE(QVariantList)
       
    51 Q_DECLARE_METATYPE(QVariantMap)
       
    52 
       
    53 class MyQObject : public QObject
       
    54 {
       
    55     Q_OBJECT
       
    56 
       
    57     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
       
    58     Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
       
    59     Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
       
    60     Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty)
       
    61     Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
       
    62     Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
       
    63     Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
       
    64     Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
       
    65     Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
       
    66     Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
       
    67     Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
       
    68     Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
       
    69     Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
       
    70     Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty)
       
    71     Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty)
       
    72     Q_ENUMS(Policy Strategy)
       
    73     Q_FLAGS(Ability)
       
    74 
       
    75 public:
       
    76     enum Policy {
       
    77         FooPolicy = 0,
       
    78         BarPolicy,
       
    79         BazPolicy
       
    80     };
       
    81 
       
    82     enum Strategy {
       
    83         FooStrategy = 10,
       
    84         BarStrategy,
       
    85         BazStrategy
       
    86     };
       
    87 
       
    88     enum AbilityFlag {
       
    89         NoAbility  = 0x000,
       
    90         FooAbility = 0x001,
       
    91         BarAbility = 0x080,
       
    92         BazAbility = 0x200,
       
    93         AllAbility = FooAbility | BarAbility | BazAbility
       
    94     };
       
    95 
       
    96     Q_DECLARE_FLAGS(Ability, AbilityFlag)
       
    97 
       
    98     MyQObject(QObject* parent = 0)
       
    99         : QObject(parent),
       
   100             m_intValue(123),
       
   101             m_variantValue(QLatin1String("foo")),
       
   102             m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
       
   103             m_stringValue(QLatin1String("bar")),
       
   104             m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
       
   105             m_brushValue(QColor(10, 20, 30, 40)),
       
   106             m_hiddenValue(456.0),
       
   107             m_writeOnlyValue(789),
       
   108             m_readOnlyValue(987),
       
   109             m_objectStar(0),
       
   110             m_qtFunctionInvoked(-1)
       
   111     {
       
   112         m_variantMapValue.insert("a", QVariant(123));
       
   113         m_variantMapValue.insert("b", QVariant(QLatin1String("foo")));
       
   114         m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this));
       
   115     }
       
   116 
       
   117     ~MyQObject() { }
       
   118 
       
   119     int intProperty() const {
       
   120         return m_intValue;
       
   121     }
       
   122     void setIntProperty(int value) {
       
   123         m_intValue = value;
       
   124     }
       
   125 
       
   126     QVariant variantProperty() const {
       
   127         return m_variantValue;
       
   128     }
       
   129     void setVariantProperty(const QVariant &value) {
       
   130         m_variantValue = value;
       
   131     }
       
   132 
       
   133     QVariantList variantListProperty() const {
       
   134         return m_variantListValue;
       
   135     }
       
   136     void setVariantListProperty(const QVariantList &value) {
       
   137         m_variantListValue = value;
       
   138     }
       
   139 
       
   140     QVariantMap variantMapProperty() const {
       
   141         return m_variantMapValue;
       
   142     }
       
   143     void setVariantMapProperty(const QVariantMap &value) {
       
   144         m_variantMapValue = value;
       
   145     }
       
   146 
       
   147     QString stringProperty() const {
       
   148         return m_stringValue;
       
   149     }
       
   150     void setStringProperty(const QString &value) {
       
   151         m_stringValue = value;
       
   152     }
       
   153 
       
   154     QStringList stringListProperty() const {
       
   155         return m_stringListValue;
       
   156     }
       
   157     void setStringListProperty(const QStringList &value) {
       
   158         m_stringListValue = value;
       
   159     }
       
   160 
       
   161     QByteArray byteArrayProperty() const {
       
   162         return m_byteArrayValue;
       
   163     }
       
   164     void setByteArrayProperty(const QByteArray &value) {
       
   165         m_byteArrayValue = value;
       
   166     }
       
   167 
       
   168     QBrush brushProperty() const {
       
   169         return m_brushValue;
       
   170     }
       
   171     Q_INVOKABLE void setBrushProperty(const QBrush &value) {
       
   172         m_brushValue = value;
       
   173     }
       
   174 
       
   175     double hiddenProperty() const {
       
   176         return m_hiddenValue;
       
   177     }
       
   178     void setHiddenProperty(double value) {
       
   179         m_hiddenValue = value;
       
   180     }
       
   181 
       
   182     int writeOnlyProperty() const {
       
   183         return m_writeOnlyValue;
       
   184     }
       
   185     void setWriteOnlyProperty(int value) {
       
   186         m_writeOnlyValue = value;
       
   187     }
       
   188 
       
   189     int readOnlyProperty() const {
       
   190         return m_readOnlyValue;
       
   191     }
       
   192 
       
   193     QKeySequence shortcut() const {
       
   194         return m_shortcut;
       
   195     }
       
   196     void setShortcut(const QKeySequence &seq) {
       
   197         m_shortcut = seq;
       
   198     }
       
   199 
       
   200     QWebElement webElementProperty() const {
       
   201         return m_webElement;
       
   202     }
       
   203 
       
   204     void setWebElementProperty(const QWebElement& element) {
       
   205         m_webElement = element;
       
   206     }
       
   207 
       
   208     CustomType propWithCustomType() const {
       
   209         return m_customType;
       
   210     }
       
   211     void setPropWithCustomType(const CustomType &c) {
       
   212         m_customType = c;
       
   213     }
       
   214 
       
   215     QObject* objectStarProperty() const {
       
   216         return m_objectStar;
       
   217     }
       
   218 
       
   219     void setObjectStarProperty(QObject* object) {
       
   220         m_objectStar = object;
       
   221     }
       
   222 
       
   223 
       
   224     int qtFunctionInvoked() const {
       
   225         return m_qtFunctionInvoked;
       
   226     }
       
   227 
       
   228     QVariantList qtFunctionActuals() const {
       
   229         return m_actuals;
       
   230     }
       
   231 
       
   232     void resetQtFunctionInvoked() {
       
   233         m_qtFunctionInvoked = -1;
       
   234         m_actuals.clear();
       
   235     }
       
   236 
       
   237     Q_INVOKABLE void myInvokable() {
       
   238         m_qtFunctionInvoked = 0;
       
   239     }
       
   240     Q_INVOKABLE void myInvokableWithIntArg(int arg) {
       
   241         m_qtFunctionInvoked = 1;
       
   242         m_actuals << arg;
       
   243     }
       
   244     Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
       
   245         m_qtFunctionInvoked = 2;
       
   246         m_actuals << arg;
       
   247     }
       
   248     Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
       
   249         m_qtFunctionInvoked = 3;
       
   250         m_actuals << arg;
       
   251     }
       
   252     Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
       
   253         m_qtFunctionInvoked = 4;
       
   254         m_actuals << arg;
       
   255     }
       
   256     Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
       
   257         m_qtFunctionInvoked = 5;
       
   258         m_actuals << arg;
       
   259     }
       
   260     Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
       
   261         m_qtFunctionInvoked = 6;
       
   262         m_actuals << arg1 << arg2;
       
   263     }
       
   264     Q_INVOKABLE int myInvokableReturningInt() {
       
   265         m_qtFunctionInvoked = 7;
       
   266         return 123;
       
   267     }
       
   268     Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
       
   269         m_qtFunctionInvoked = 39;
       
   270         return 456;
       
   271     }
       
   272     Q_INVOKABLE QString myInvokableReturningString() {
       
   273         m_qtFunctionInvoked = 8;
       
   274         return QLatin1String("ciao");
       
   275     }
       
   276     Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
       
   277         m_qtFunctionInvoked = 9;
       
   278         m_actuals << arg1 << arg2;
       
   279     }
       
   280     Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
       
   281         m_qtFunctionInvoked = 10;
       
   282         m_actuals << policy;
       
   283     }
       
   284     Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
       
   285         m_qtFunctionInvoked = 36;
       
   286         m_actuals << policy;
       
   287     }
       
   288     Q_INVOKABLE Policy myInvokableReturningEnum() {
       
   289         m_qtFunctionInvoked = 37;
       
   290         return BazPolicy;
       
   291     }
       
   292     Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
       
   293         m_qtFunctionInvoked = 38;
       
   294         return BazPolicy;
       
   295     }
       
   296     Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
       
   297         m_qtFunctionInvoked = 11;
       
   298         return QVector<int>();
       
   299     }
       
   300     Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
       
   301         m_qtFunctionInvoked = 12;
       
   302     }
       
   303     Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
       
   304         m_qtFunctionInvoked = 13;
       
   305         return this;
       
   306     }
       
   307     Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
       
   308         m_qtFunctionInvoked = 14;
       
   309         m_actuals << qVariantFromValue(lst);
       
   310         return lst;
       
   311     }
       
   312     Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
       
   313         m_qtFunctionInvoked = 15;
       
   314         m_actuals << v;
       
   315         return v;
       
   316     }
       
   317     Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
       
   318         m_qtFunctionInvoked = 16;
       
   319         m_actuals << vm;
       
   320         return vm;
       
   321     }
       
   322     Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
       
   323         m_qtFunctionInvoked = 17;
       
   324         m_actuals << qVariantFromValue(lst);
       
   325         return lst;
       
   326     }
       
   327     Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
       
   328         m_qtFunctionInvoked = 18;
       
   329         m_actuals << qVariantFromValue(obj);
       
   330         return obj;
       
   331     }
       
   332     Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
       
   333         m_qtFunctionInvoked = 19;
       
   334         m_actuals << qVariantFromValue(brush);
       
   335         return brush;
       
   336     }
       
   337     Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
       
   338         m_qtFunctionInvoked = 43;
       
   339         m_actuals << qVariantFromValue(style);
       
   340     }
       
   341     Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
       
   342         m_qtFunctionInvoked = 44;
       
   343         m_actuals << qVariantFromValue(arg);
       
   344     }
       
   345     Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
       
   346         m_qtFunctionInvoked = 45;
       
   347         m_actuals << qVariantFromValue(arg);
       
   348     }
       
   349     Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
       
   350         m_qtFunctionInvoked = 46;
       
   351         m_actuals << qVariantFromValue(arg);
       
   352     }
       
   353     Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
       
   354         m_qtFunctionInvoked = 47;
       
   355         m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2);
       
   356     }
       
   357     Q_INVOKABLE QObject& myInvokableReturningRef() {
       
   358         m_qtFunctionInvoked = 48;
       
   359         return *this;
       
   360     }
       
   361     Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
       
   362         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
       
   363         return *this;
       
   364     }
       
   365     Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
       
   366         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
       
   367         m_actuals << qVariantFromValue(arg);
       
   368     }
       
   369     Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
       
   370         const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
       
   371         m_actuals << qVariantFromValue(arg);
       
   372     }
       
   373     Q_INVOKABLE void myInvokableWithBoolArg(bool arg) {
       
   374         m_qtFunctionInvoked = 52;
       
   375         m_actuals << arg;
       
   376     }
       
   377 
       
   378     void emitMySignal() {
       
   379         emit mySignal();
       
   380     }
       
   381     void emitMySignalWithIntArg(int arg) {
       
   382         emit mySignalWithIntArg(arg);
       
   383     }
       
   384     void emitMySignal2(bool arg) {
       
   385         emit mySignal2(arg);
       
   386     }
       
   387     void emitMySignal2() {
       
   388         emit mySignal2();
       
   389     }
       
   390     void emitMySignalWithDateTimeArg(QDateTime dt) {
       
   391         emit mySignalWithDateTimeArg(dt);
       
   392     }
       
   393     void emitMySignalWithRegexArg(QRegExp r) {
       
   394         emit mySignalWithRegexArg(r);
       
   395     }
       
   396 
       
   397 public Q_SLOTS:
       
   398     void mySlot() {
       
   399         m_qtFunctionInvoked = 20;
       
   400     }
       
   401     void mySlotWithIntArg(int arg) {
       
   402         m_qtFunctionInvoked = 21;
       
   403         m_actuals << arg;
       
   404     }
       
   405     void mySlotWithDoubleArg(double arg) {
       
   406         m_qtFunctionInvoked = 22;
       
   407         m_actuals << arg;
       
   408     }
       
   409     void mySlotWithStringArg(const QString &arg) {
       
   410         m_qtFunctionInvoked = 23;
       
   411         m_actuals << arg;
       
   412     }
       
   413 
       
   414     void myOverloadedSlot() {
       
   415         m_qtFunctionInvoked = 24;
       
   416     }
       
   417     void myOverloadedSlot(QObject* arg) {
       
   418         m_qtFunctionInvoked = 41;
       
   419         m_actuals << qVariantFromValue(arg);
       
   420     }
       
   421     void myOverloadedSlot(bool arg) {
       
   422         m_qtFunctionInvoked = 25;
       
   423         m_actuals << arg;
       
   424     }
       
   425     void myOverloadedSlot(const QStringList &arg) {
       
   426         m_qtFunctionInvoked = 42;
       
   427         m_actuals << arg;
       
   428     }
       
   429     void myOverloadedSlot(double arg) {
       
   430         m_qtFunctionInvoked = 26;
       
   431         m_actuals << arg;
       
   432     }
       
   433     void myOverloadedSlot(float arg) {
       
   434         m_qtFunctionInvoked = 27;
       
   435         m_actuals << arg;
       
   436     }
       
   437     void myOverloadedSlot(int arg) {
       
   438         m_qtFunctionInvoked = 28;
       
   439         m_actuals << arg;
       
   440     }
       
   441     void myOverloadedSlot(const QString &arg) {
       
   442         m_qtFunctionInvoked = 29;
       
   443         m_actuals << arg;
       
   444     }
       
   445     void myOverloadedSlot(const QColor &arg) {
       
   446         m_qtFunctionInvoked = 30;
       
   447         m_actuals << arg;
       
   448     }
       
   449     void myOverloadedSlot(const QBrush &arg) {
       
   450         m_qtFunctionInvoked = 31;
       
   451         m_actuals << arg;
       
   452     }
       
   453     void myOverloadedSlot(const QDateTime &arg) {
       
   454         m_qtFunctionInvoked = 32;
       
   455         m_actuals << arg;
       
   456     }
       
   457     void myOverloadedSlot(const QDate &arg) {
       
   458         m_qtFunctionInvoked = 33;
       
   459         m_actuals << arg;
       
   460     }
       
   461     void myOverloadedSlot(const QRegExp &arg) {
       
   462         m_qtFunctionInvoked = 34;
       
   463         m_actuals << arg;
       
   464     }
       
   465     void myOverloadedSlot(const QVariant &arg) {
       
   466         m_qtFunctionInvoked = 35;
       
   467         m_actuals << arg;
       
   468     }
       
   469     void myOverloadedSlot(const QWebElement &arg) {
       
   470         m_qtFunctionInvoked = 36;
       
   471         m_actuals << QVariant::fromValue<QWebElement>(arg);
       
   472     }
       
   473 
       
   474     void qscript_call(int arg) {
       
   475         m_qtFunctionInvoked = 40;
       
   476         m_actuals << arg;
       
   477     }
       
   478 
       
   479 protected Q_SLOTS:
       
   480     void myProtectedSlot() {
       
   481         m_qtFunctionInvoked = 36;
       
   482     }
       
   483 
       
   484 private Q_SLOTS:
       
   485     void myPrivateSlot() { }
       
   486 
       
   487 Q_SIGNALS:
       
   488     void mySignal();
       
   489     void mySignalWithIntArg(int arg);
       
   490     void mySignalWithDoubleArg(double arg);
       
   491     void mySignal2(bool arg = false);
       
   492     void mySignalWithDateTimeArg(QDateTime dt);
       
   493     void mySignalWithRegexArg(QRegExp r);
       
   494 
       
   495 private:
       
   496     int m_intValue;
       
   497     QVariant m_variantValue;
       
   498     QVariantList m_variantListValue;
       
   499     QVariantMap m_variantMapValue;
       
   500     QString m_stringValue;
       
   501     QStringList m_stringListValue;
       
   502     QByteArray m_byteArrayValue;
       
   503     QBrush m_brushValue;
       
   504     double m_hiddenValue;
       
   505     int m_writeOnlyValue;
       
   506     int m_readOnlyValue;
       
   507     QKeySequence m_shortcut;
       
   508     QWebElement m_webElement;
       
   509     CustomType m_customType;
       
   510     QObject* m_objectStar;
       
   511     int m_qtFunctionInvoked;
       
   512     QVariantList m_actuals;
       
   513 };
       
   514 
       
   515 class MyOtherQObject : public MyQObject
       
   516 {
       
   517 public:
       
   518     MyOtherQObject(QObject* parent = 0)
       
   519         : MyQObject(parent) { }
       
   520 };
       
   521 
       
   522 class MyEnumTestQObject : public QObject
       
   523 {
       
   524     Q_OBJECT
       
   525     Q_PROPERTY(QString p1 READ p1)
       
   526     Q_PROPERTY(QString p2 READ p2)
       
   527     Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
       
   528     Q_PROPERTY(QString p4 READ p4)
       
   529     Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
       
   530     Q_PROPERTY(QString p6 READ p6)
       
   531 public:
       
   532     MyEnumTestQObject(QObject* parent = 0)
       
   533         : QObject(parent) { }
       
   534     QString p1() const {
       
   535         return QLatin1String("p1");
       
   536     }
       
   537     QString p2() const {
       
   538         return QLatin1String("p2");
       
   539     }
       
   540     QString p3() const {
       
   541         return QLatin1String("p3");
       
   542     }
       
   543     QString p4() const {
       
   544         return QLatin1String("p4");
       
   545     }
       
   546     QString p5() const {
       
   547         return QLatin1String("p5");
       
   548     }
       
   549     QString p6() const {
       
   550         return QLatin1String("p5");
       
   551     }
       
   552 public Q_SLOTS:
       
   553     void mySlot() { }
       
   554     void myOtherSlot() { }
       
   555 Q_SIGNALS:
       
   556     void mySignal();
       
   557 };
       
   558 
       
   559 class tst_QWebFrame : public QObject
       
   560 {
       
   561     Q_OBJECT
       
   562 
       
   563 public:
       
   564     tst_QWebFrame();
       
   565     virtual ~tst_QWebFrame();
       
   566     bool eventFilter(QObject* watched, QEvent* event);
       
   567 
       
   568 public slots:
       
   569     void init();
       
   570     void cleanup();
       
   571 
       
   572 private slots:
       
   573     void getSetStaticProperty();
       
   574     void getSetDynamicProperty();
       
   575     void getSetChildren();
       
   576     void callQtInvokable();
       
   577     void connectAndDisconnect();
       
   578     void classEnums();
       
   579     void classConstructor();
       
   580     void overrideInvokable();
       
   581     void transferInvokable();
       
   582     void findChild();
       
   583     void findChildren();
       
   584     void overloadedSlots();
       
   585     void enumerate_data();
       
   586     void enumerate();
       
   587     void objectDeleted();
       
   588     void typeConversion();
       
   589     void arrayObjectEnumerable();
       
   590     void symmetricUrl();
       
   591     void progressSignal();
       
   592     void urlChange();
       
   593     void domCycles();
       
   594     void requestedUrl();
       
   595     void javaScriptWindowObjectCleared_data();
       
   596     void javaScriptWindowObjectCleared();
       
   597     void javaScriptWindowObjectClearedOnEvaluate();
       
   598     void setHtml();
       
   599     void setHtmlWithResource();
       
   600     void setHtmlWithBaseURL();
       
   601     void setHtmlWithJSAlert();
       
   602     void ipv6HostEncoding();
       
   603     void metaData();
       
   604 #if !defined(Q_WS_MAEMO_5)
       
   605     // as maemo 5 does not use QComboBoxes to implement the popups
       
   606     // this test does not make sense for it.
       
   607     void popupFocus();
       
   608 #endif
       
   609     void inputFieldFocus();
       
   610     void hitTestContent();
       
   611     void jsByteArray();
       
   612     void ownership();
       
   613     void nullValue();
       
   614     void baseUrl_data();
       
   615     void baseUrl();
       
   616     void hasSetFocus();
       
   617     void render();
       
   618     void scrollPosition();
       
   619     void scrollToAnchor();
       
   620     void scrollbarsOff();
       
   621     void evaluateWillCauseRepaint();
       
   622     void qObjectWrapperWithSameIdentity();
       
   623     void introspectQtMethods_data();
       
   624     void introspectQtMethods();
       
   625 
       
   626 private:
       
   627     QString  evalJS(const QString&s) {
       
   628         // Convert an undefined return variant to the string "undefined"
       
   629         QVariant ret = evalJSV(s);
       
   630         if (ret.userType() == QMetaType::Void)
       
   631             return "undefined";
       
   632         else
       
   633             return ret.toString();
       
   634     }
       
   635     QVariant evalJSV(const QString &s) {
       
   636         return m_page->mainFrame()->evaluateJavaScript(s);
       
   637     }
       
   638 
       
   639     QString  evalJS(const QString&s, QString& type) {
       
   640         return evalJSV(s, type).toString();
       
   641     }
       
   642     QVariant evalJSV(const QString &s, QString& type) {
       
   643         // As a special measure, if we get an exception we set the type to 'error'
       
   644         // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
       
   645         // Similarly, an array is an object, but we'd prefer to have a type of 'array'
       
   646         // Also, consider a QMetaType::Void QVariant to be undefined
       
   647         QString escaped = s;
       
   648         escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
       
   649         evalJS("var retvalue;\
       
   650                var typevalue; \
       
   651                try {\
       
   652                retvalue = eval('" + escaped + "'); \
       
   653                typevalue = typeof retvalue; \
       
   654                if (retvalue instanceof Array) \
       
   655                typevalue = 'array'; \
       
   656            } \
       
   657                catch(e) {\
       
   658                retvalue = e.name + ': ' + e.message;\
       
   659                typevalue = 'error';\
       
   660            }");
       
   661         QVariant ret = evalJSV("retvalue");
       
   662         if (ret.userType() != QMetaType::Void)
       
   663             type = evalJS("typevalue");
       
   664         else {
       
   665             ret = QString("undefined");
       
   666             type = sUndefined;
       
   667         }
       
   668         evalJS("delete retvalue; delete typevalue");
       
   669         return ret;
       
   670     }
       
   671     QObject* firstChildByClassName(QObject* parent, const char* className) {
       
   672         const QObjectList & children = parent->children();
       
   673         foreach (QObject* child, children) {
       
   674             if (!strcmp(child->metaObject()->className(), className)) {
       
   675                 return child;
       
   676             }
       
   677         }
       
   678         return 0;
       
   679     }
       
   680 
       
   681     const QString sTrue;
       
   682     const QString sFalse;
       
   683     const QString sUndefined;
       
   684     const QString sArray;
       
   685     const QString sFunction;
       
   686     const QString sError;
       
   687     const QString sString;
       
   688     const QString sObject;
       
   689     const QString sNumber;
       
   690 
       
   691 private:
       
   692     QWebView* m_view;
       
   693     QWebPage* m_page;
       
   694     MyQObject* m_myObject;
       
   695     QWebView* m_inputFieldsTestView;
       
   696     int m_inputFieldTestPaintCount;
       
   697 };
       
   698 
       
   699 tst_QWebFrame::tst_QWebFrame()
       
   700     : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
       
   701         sString("string"), sObject("object"), sNumber("number"), m_inputFieldsTestView(0), m_inputFieldTestPaintCount(0)
       
   702 {
       
   703 }
       
   704 
       
   705 tst_QWebFrame::~tst_QWebFrame()
       
   706 {
       
   707 }
       
   708 
       
   709 bool tst_QWebFrame::eventFilter(QObject* watched, QEvent* event)
       
   710 {
       
   711     // used on the inputFieldFocus test
       
   712     if (watched == m_inputFieldsTestView) {
       
   713         if (event->type() == QEvent::Paint)
       
   714             m_inputFieldTestPaintCount++;
       
   715     }
       
   716     return QObject::eventFilter(watched, event);
       
   717 }
       
   718 
       
   719 void tst_QWebFrame::init()
       
   720 {
       
   721     m_view = new QWebView();
       
   722     m_page = m_view->page();
       
   723     m_myObject = new MyQObject();
       
   724     m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
       
   725 }
       
   726 
       
   727 void tst_QWebFrame::cleanup()
       
   728 {
       
   729     delete m_view;
       
   730     delete m_myObject;
       
   731 }
       
   732 
       
   733 void tst_QWebFrame::getSetStaticProperty()
       
   734 {
       
   735     m_page->mainFrame()->setHtml("<html><head><body></body></html>");
       
   736     QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
       
   737 
       
   738     // initial value (set in MyQObject constructor)
       
   739     {
       
   740         QString type;
       
   741         QVariant ret = evalJSV("myObject.intProperty", type);
       
   742         QCOMPARE(type, sNumber);
       
   743         QCOMPARE(ret.type(), QVariant::Double);
       
   744         QCOMPARE(ret.toInt(), 123);
       
   745     }
       
   746     QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
       
   747 
       
   748     {
       
   749         QString type;
       
   750         QVariant ret = evalJSV("myObject.variantProperty", type);
       
   751         QCOMPARE(type, sString);
       
   752         QCOMPARE(ret.type(), QVariant::String);
       
   753         QCOMPARE(ret.toString(), QLatin1String("foo"));
       
   754     }
       
   755     QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
       
   756 
       
   757     {
       
   758         QString type;
       
   759         QVariant ret = evalJSV("myObject.stringProperty", type);
       
   760         QCOMPARE(type, sString);
       
   761         QCOMPARE(ret.type(), QVariant::String);
       
   762         QCOMPARE(ret.toString(), QLatin1String("bar"));
       
   763     }
       
   764     QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
       
   765 
       
   766     {
       
   767         QString type;
       
   768         QVariant ret = evalJSV("myObject.variantListProperty", type);
       
   769         QCOMPARE(type, sArray);
       
   770         QCOMPARE(ret.type(), QVariant::List);
       
   771         QVariantList vl = ret.value<QVariantList>();
       
   772         QCOMPARE(vl.size(), 2);
       
   773         QCOMPARE(vl.at(0).toInt(), 123);
       
   774         QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
       
   775     }
       
   776     QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
       
   777     QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
       
   778     QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
       
   779 
       
   780     {
       
   781         QString type;
       
   782         QVariant ret = evalJSV("myObject.variantMapProperty", type);
       
   783         QCOMPARE(type, sObject);
       
   784         QCOMPARE(ret.type(), QVariant::Map);
       
   785         QVariantMap vm = ret.value<QVariantMap>();
       
   786         QCOMPARE(vm.size(), 3);
       
   787         QCOMPARE(vm.value("a").toInt(), 123);
       
   788         QCOMPARE(vm.value("b").toString(), QLatin1String("foo"));
       
   789         QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject));
       
   790     }
       
   791     QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue);
       
   792     QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue);
       
   793     QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue);
       
   794 
       
   795     {
       
   796         QString type;
       
   797         QVariant ret = evalJSV("myObject.stringListProperty", type);
       
   798         QCOMPARE(type, sArray);
       
   799         QCOMPARE(ret.type(), QVariant::List);
       
   800         QVariantList vl = ret.value<QVariantList>();
       
   801         QCOMPARE(vl.size(), 2);
       
   802         QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
       
   803         QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
       
   804     }
       
   805     QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
       
   806     QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
       
   807     QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
       
   808     QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
       
   809     QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
       
   810 
       
   811     // property change in C++ should be reflected in script
       
   812     m_myObject->setIntProperty(456);
       
   813     QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
       
   814     m_myObject->setIntProperty(789);
       
   815     QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
       
   816 
       
   817     m_myObject->setVariantProperty(QLatin1String("bar"));
       
   818     QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
       
   819     m_myObject->setVariantProperty(42);
       
   820     QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
       
   821     m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
       
   822 //XFAIL
       
   823 //  QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
       
   824 
       
   825     m_myObject->setStringProperty(QLatin1String("baz"));
       
   826     QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
       
   827     m_myObject->setStringProperty(QLatin1String("zab"));
       
   828     QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
       
   829 
       
   830     // property change in script should be reflected in C++
       
   831     QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
       
   832     QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
       
   833     QCOMPARE(m_myObject->intProperty(), 123);
       
   834     QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
       
   835                     "myObject.intProperty == 0"), sTrue);
       
   836     QCOMPARE(m_myObject->intProperty(), 0);
       
   837     QCOMPARE(evalJS("myObject.intProperty = '123';"
       
   838                     "myObject.intProperty == 123"), sTrue);
       
   839     QCOMPARE(m_myObject->intProperty(), 123);
       
   840 
       
   841     QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
       
   842     QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
       
   843     QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
       
   844     QCOMPARE(evalJS("myObject.stringProperty = 123;"
       
   845                     "myObject.stringProperty"), QLatin1String("123"));
       
   846     QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
       
   847     QCOMPARE(evalJS("myObject.stringProperty = null"), QString());
       
   848     QCOMPARE(evalJS("myObject.stringProperty"), QString());
       
   849     QCOMPARE(m_myObject->stringProperty(), QString());
       
   850     QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined);
       
   851     QCOMPARE(evalJS("myObject.stringProperty"), QString());
       
   852     QCOMPARE(m_myObject->stringProperty(), QString());
       
   853 
       
   854     QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);"
       
   855                     "myObject.variantProperty").toDouble(), 1234.0);
       
   856     QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0);
       
   857 
       
   858     QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);"
       
   859                     "myObject.variantProperty"), sTrue);
       
   860     QCOMPARE(m_myObject->variantProperty().toBool(), true);
       
   861 
       
   862     QCOMPARE(evalJS("myObject.variantProperty = null;"
       
   863                     "myObject.variantProperty.valueOf()"), sUndefined);
       
   864     QCOMPARE(m_myObject->variantProperty(), QVariant());
       
   865     QCOMPARE(evalJS("myObject.variantProperty = undefined;"
       
   866                     "myObject.variantProperty.valueOf()"), sUndefined);
       
   867     QCOMPARE(m_myObject->variantProperty(), QVariant());
       
   868 
       
   869     QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
       
   870                     "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
       
   871     QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
       
   872     QCOMPARE(evalJS("myObject.variantProperty = 42;"
       
   873                     "myObject.variantProperty").toDouble(), 42.0);
       
   874     QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
       
   875 
       
   876     QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
       
   877                     "myObject.variantListProperty.length == 3"), sTrue);
       
   878     QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
       
   879     QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
       
   880     QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
       
   881 
       
   882     QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
       
   883                     "myObject.stringListProperty.length == 3"), sTrue);
       
   884     QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
       
   885     QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
       
   886     QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
       
   887     QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
       
   888     QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
       
   889     QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
       
   890     evalJS("myObject.webElementProperty=document.body;");
       
   891     QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY"));
       
   892 
       
   893     // try to delete
       
   894     QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
       
   895     QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
       
   896 
       
   897     QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
       
   898     QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
       
   899 
       
   900     // custom property
       
   901     QCOMPARE(evalJS("myObject.customProperty"), sUndefined);
       
   902     QCOMPARE(evalJS("myObject.customProperty = 123;"
       
   903                     "myObject.customProperty == 123"), sTrue);
       
   904     QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty");
       
   905     QCOMPARE(v.type(), QVariant::Double);
       
   906     QCOMPARE(v.toInt(), 123);
       
   907 
       
   908     // non-scriptable property
       
   909     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
       
   910     QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
       
   911     QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
       
   912                     "myObject.hiddenProperty == 123"), sTrue);
       
   913     QCOMPARE(m_myObject->hiddenProperty(), 456.0);
       
   914 
       
   915     // write-only property
       
   916     QCOMPARE(m_myObject->writeOnlyProperty(), 789);
       
   917     QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
       
   918     QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
       
   919                     "typeof myObject.writeOnlyProperty"), sUndefined);
       
   920     QCOMPARE(m_myObject->writeOnlyProperty(), 123);
       
   921 
       
   922     // read-only property
       
   923     QCOMPARE(m_myObject->readOnlyProperty(), 987);
       
   924     QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
       
   925     QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
       
   926                     "myObject.readOnlyProperty == 987"), sTrue);
       
   927     QCOMPARE(m_myObject->readOnlyProperty(), 987);
       
   928 
       
   929     // QObject* property
       
   930     m_myObject->setObjectStarProperty(0);
       
   931     QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0);
       
   932     QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue);
       
   933     QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
       
   934     QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse);
       
   935     QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue);
       
   936     QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"),
       
   937         sUndefined);
       
   938     m_myObject->setObjectStarProperty(this);
       
   939     QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue);
       
   940     QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
       
   941     QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue);
       
   942     QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue);
       
   943 }
       
   944 
       
   945 void tst_QWebFrame::getSetDynamicProperty()
       
   946 {
       
   947     // initially the object does not have the property
       
   948     // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
       
   949 
       
   950     //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
       
   951     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
       
   952 
       
   953     // add a dynamic property in C++
       
   954     QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
       
   955     //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
       
   956     QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
       
   957     QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
       
   958 
       
   959     // property change in script should be reflected in C++
       
   960     QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
       
   961                     "myObject.dynamicProperty"), QLatin1String("foo"));
       
   962     QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
       
   963 
       
   964     // delete the property (XFAIL - can't delete properties)
       
   965     QEXPECT_FAIL("", "can't delete properties", Continue);
       
   966     QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
       
   967     /*
       
   968     QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
       
   969     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
       
   970     //    QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
       
   971     QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
       
   972     */
       
   973 }
       
   974 
       
   975 void tst_QWebFrame::getSetChildren()
       
   976 {
       
   977     // initially the object does not have the child
       
   978     // (again, no hasOwnProperty)
       
   979 
       
   980     //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
       
   981     QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
       
   982 
       
   983     // add a child
       
   984     MyQObject* child = new MyQObject(m_myObject);
       
   985     child->setObjectName("child");
       
   986 //  QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
       
   987     QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
       
   988 
       
   989     // add a grandchild
       
   990     MyQObject* grandChild = new MyQObject(child);
       
   991     grandChild->setObjectName("grandChild");
       
   992 //  QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
       
   993     QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
       
   994 
       
   995     // delete grandchild
       
   996     delete grandChild;
       
   997 //  QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
       
   998     QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
       
   999 
       
  1000     // delete child
       
  1001     delete child;
       
  1002 //  QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
       
  1003     QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
       
  1004 }
       
  1005 
       
  1006 Q_DECLARE_METATYPE(QVector<int>)
       
  1007 Q_DECLARE_METATYPE(QVector<double>)
       
  1008 Q_DECLARE_METATYPE(QVector<QString>)
       
  1009 
       
  1010 void tst_QWebFrame::callQtInvokable()
       
  1011 {
       
  1012     qRegisterMetaType<QObjectList>();
       
  1013 
       
  1014     m_myObject->resetQtFunctionInvoked();
       
  1015     QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
       
  1016     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1017     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1018 
       
  1019     // extra arguments should silently be ignored
       
  1020     m_myObject->resetQtFunctionInvoked();
       
  1021     QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
       
  1022     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1023     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1024 
       
  1025     m_myObject->resetQtFunctionInvoked();
       
  1026     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
       
  1027     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1028     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1029     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1030 
       
  1031     m_myObject->resetQtFunctionInvoked();
       
  1032     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
       
  1033     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1034     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1035     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1036 
       
  1037     m_myObject->resetQtFunctionInvoked();
       
  1038     QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
       
  1039     QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
       
  1040     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1041     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
       
  1042 
       
  1043     m_myObject->resetQtFunctionInvoked();
       
  1044     QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
       
  1045     QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
       
  1046     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1047     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
       
  1048 
       
  1049     m_myObject->resetQtFunctionInvoked();
       
  1050     QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
       
  1051     QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
       
  1052     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1053     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
       
  1054 
       
  1055     m_myObject->resetQtFunctionInvoked();
       
  1056     QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined);
       
  1057     QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
       
  1058     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1059     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5);
       
  1060 
       
  1061     m_myObject->resetQtFunctionInvoked();
       
  1062     QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined);
       
  1063     QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
       
  1064     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1065     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true);
       
  1066 
       
  1067     m_myObject->resetQtFunctionInvoked();
       
  1068     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
       
  1069     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1070     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1071     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
       
  1072 
       
  1073     m_myObject->resetQtFunctionInvoked();
       
  1074     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
       
  1075     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1076     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1077     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
       
  1078 
       
  1079     m_myObject->resetQtFunctionInvoked();
       
  1080     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined);
       
  1081     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1082     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1083     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
       
  1084     QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
       
  1085 
       
  1086     m_myObject->resetQtFunctionInvoked();
       
  1087     QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined);
       
  1088     QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
       
  1089     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1090     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
       
  1091     QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
       
  1092 
       
  1093     m_myObject->resetQtFunctionInvoked();
       
  1094     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
       
  1095     QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
       
  1096     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1097     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1098     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
       
  1099 
       
  1100     m_myObject->resetQtFunctionInvoked();
       
  1101     QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
       
  1102     QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
       
  1103     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1104 
       
  1105     m_myObject->resetQtFunctionInvoked();
       
  1106     QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
       
  1107     QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
       
  1108     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1109 
       
  1110     m_myObject->resetQtFunctionInvoked();
       
  1111     QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
       
  1112     QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
       
  1113     QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
       
  1114 
       
  1115     m_myObject->resetQtFunctionInvoked();
       
  1116     QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
       
  1117     QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
       
  1118     QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1119     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1120     QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
       
  1121 
       
  1122     m_myObject->resetQtFunctionInvoked();
       
  1123     QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
       
  1124     QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
       
  1125     m_myObject->resetQtFunctionInvoked();
       
  1126     {
       
  1127         QString type;
       
  1128         QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
       
  1129         QCOMPARE(type, sError);
       
  1130         QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n    myInvokableWithVoidStarArg(void*)"));
       
  1131         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1132     }
       
  1133 
       
  1134     m_myObject->resetQtFunctionInvoked();
       
  1135     {
       
  1136         QString type;
       
  1137         QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
       
  1138         QCOMPARE(type, sError);
       
  1139         QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n    myInvokableWithAmbiguousArg(int)\n    myInvokableWithAmbiguousArg(uint)"));
       
  1140     }
       
  1141 
       
  1142     m_myObject->resetQtFunctionInvoked();
       
  1143     {
       
  1144         QString type;
       
  1145         QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
       
  1146         QCOMPARE(type, sUndefined);
       
  1147         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
       
  1148         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1149         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1150         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
       
  1151     }
       
  1152 
       
  1153     m_myObject->resetQtFunctionInvoked();
       
  1154     {
       
  1155         QString type;
       
  1156         QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
       
  1157         QCOMPARE(type, sUndefined);
       
  1158         QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
       
  1159         QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
       
  1160         QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
       
  1161         QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
       
  1162     }
       
  1163 
       
  1164     // calling function that returns (const)ref
       
  1165     m_myObject->resetQtFunctionInvoked();
       
  1166     {
       
  1167         QString type;
       
  1168         QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
       
  1169         QCOMPARE(ret, sUndefined);
       
  1170         //QVERIFY(!m_engine->hasUncaughtException());
       
  1171         QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
       
  1172     }
       
  1173 
       
  1174     m_myObject->resetQtFunctionInvoked();
       
  1175     {
       
  1176         QString type;
       
  1177         QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
       
  1178         QCOMPARE(ret, sUndefined);
       
  1179         //QVERIFY(!m_engine->hasUncaughtException());
       
  1180         QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
       
  1181     }
       
  1182 
       
  1183     m_myObject->resetQtFunctionInvoked();
       
  1184     {
       
  1185         QString type;
       
  1186         QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
       
  1187         QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
       
  1188         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  1189         QCOMPARE(type, sObject);
       
  1190         QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
       
  1191     }
       
  1192 
       
  1193     m_myObject->resetQtFunctionInvoked();
       
  1194     {
       
  1195         QString type;
       
  1196         QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
       
  1197         QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
       
  1198         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1199         QCOMPARE(type, sArray);
       
  1200         QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
       
  1201         QVariantList vl = qvariant_cast<QVariantList>(ret);
       
  1202         QCOMPARE(vl.count(), 1);
       
  1203     }
       
  1204 
       
  1205     m_myObject->resetQtFunctionInvoked();
       
  1206     {
       
  1207         QString type;
       
  1208         m_myObject->setVariantProperty(QVariant(123));
       
  1209         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
       
  1210         QCOMPARE(type, sNumber);
       
  1211         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1212         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1213         QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
       
  1214         QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
       
  1215         QCOMPARE(ret.toInt(),123);
       
  1216     }
       
  1217 
       
  1218     m_myObject->resetQtFunctionInvoked();
       
  1219     {
       
  1220         QString type;
       
  1221         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type);
       
  1222         QCOMPARE(type, sObject);
       
  1223         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1224         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1225         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
       
  1226         QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
       
  1227     }
       
  1228 
       
  1229     m_myObject->resetQtFunctionInvoked();
       
  1230     {
       
  1231         QString type;
       
  1232         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type);
       
  1233         QCOMPARE(type, sObject);
       
  1234         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1235         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1236         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
       
  1237         QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
       
  1238     }
       
  1239 
       
  1240     /* XFAIL - variant support
       
  1241     m_myObject->resetQtFunctionInvoked();
       
  1242     {
       
  1243         m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
       
  1244         QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
       
  1245         QVERIFY(ret.isVariant());
       
  1246         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1247         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1248         QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
       
  1249         QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
       
  1250     }
       
  1251     */
       
  1252 
       
  1253     m_myObject->resetQtFunctionInvoked();
       
  1254     {
       
  1255         QString type;
       
  1256         QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
       
  1257         QCOMPARE(type, sNumber);
       
  1258         QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
       
  1259         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1260         QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
       
  1261         QCOMPARE(ret.userType(), int(QMetaType::Double));
       
  1262         QCOMPARE(ret.toInt(),123);
       
  1263     }
       
  1264 
       
  1265     m_myObject->resetQtFunctionInvoked();
       
  1266     {
       
  1267         QString type;
       
  1268         QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
       
  1269         QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
       
  1270         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1271 
       
  1272         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1273         QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
       
  1274 
       
  1275         QVariantMap vmap = qvariant_cast<QVariantMap>(v);
       
  1276         QCOMPARE(vmap.keys().size(), 2);
       
  1277         QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
       
  1278         QCOMPARE(vmap.value("a"), QVariant(123));
       
  1279         QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
       
  1280         QCOMPARE(vmap.value("b"), QVariant("ciao"));
       
  1281 
       
  1282         QCOMPARE(type, sObject);
       
  1283 
       
  1284         QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
       
  1285         vmap = qvariant_cast<QVariantMap>(ret);
       
  1286         QCOMPARE(vmap.keys().size(), 2);
       
  1287         QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
       
  1288         QCOMPARE(vmap.value("a"), QVariant(123));
       
  1289         QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
       
  1290         QCOMPARE(vmap.value("b"), QVariant("ciao"));
       
  1291     }
       
  1292 
       
  1293     m_myObject->resetQtFunctionInvoked();
       
  1294     {
       
  1295         QString type;
       
  1296         QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
       
  1297         QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
       
  1298         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1299         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1300         QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
       
  1301         QList<int> ilst = qvariant_cast<QList<int> >(v);
       
  1302         QCOMPARE(ilst.size(), 2);
       
  1303         QCOMPARE(ilst.at(0), 1);
       
  1304         QCOMPARE(ilst.at(1), 5);
       
  1305 
       
  1306         QCOMPARE(type, sArray);
       
  1307         QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
       
  1308         QVariantList vlst = qvariant_cast<QVariantList>(ret);
       
  1309         QCOMPARE(vlst.size(), 2);
       
  1310         QCOMPARE(vlst.at(0).toInt(), 1);
       
  1311         QCOMPARE(vlst.at(1).toInt(), 5);
       
  1312     }
       
  1313 
       
  1314     m_myObject->resetQtFunctionInvoked();
       
  1315     {
       
  1316         QString type;
       
  1317         QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
       
  1318         QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
       
  1319         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1320         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1321         QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
       
  1322         QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
       
  1323 
       
  1324         QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
       
  1325         QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
       
  1326 
       
  1327         QCOMPARE(type, sObject);
       
  1328     }
       
  1329 
       
  1330     m_myObject->resetQtFunctionInvoked();
       
  1331     {
       
  1332         // no implicit conversion from integer to QObject*
       
  1333         QString type;
       
  1334         evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
       
  1335         QCOMPARE(type, sError);
       
  1336     }
       
  1337 
       
  1338     /*
       
  1339     m_myObject->resetQtFunctionInvoked();
       
  1340     {
       
  1341         QString fun = evalJS("myObject.myInvokableWithQBrushArg");
       
  1342         Q_ASSERT(fun.isFunction());
       
  1343         QColor color(10, 20, 30, 40);
       
  1344         // QColor should be converted to a QBrush
       
  1345         QVariant ret = fun.call(QString(), QStringList()
       
  1346                                     << qScriptValueFromValue(m_engine, color));
       
  1347         QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
       
  1348         QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1349         QVariant v = m_myObject->qtFunctionActuals().at(0);
       
  1350         QCOMPARE(v.userType(), int(QMetaType::QBrush));
       
  1351         QCOMPARE(qvariant_cast<QColor>(v), color);
       
  1352 
       
  1353         QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
       
  1354     }
       
  1355     */
       
  1356 
       
  1357     // private slots should not be part of the QObject binding
       
  1358     QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
       
  1359 
       
  1360     // protected slots should be fine
       
  1361     m_myObject->resetQtFunctionInvoked();
       
  1362     evalJS("myObject.myProtectedSlot()");
       
  1363     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
       
  1364 
       
  1365     // call with too few arguments
       
  1366     {
       
  1367         QString type;
       
  1368         QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
       
  1369         QCOMPARE(type, sError);
       
  1370         QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n    myInvokableWithIntArg(int,int)\n    myInvokableWithIntArg(int)"));
       
  1371     }
       
  1372 
       
  1373     // call function where not all types have been registered
       
  1374     m_myObject->resetQtFunctionInvoked();
       
  1375     {
       
  1376         QString type;
       
  1377         QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
       
  1378         QCOMPARE(type, sError);
       
  1379         QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
       
  1380         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1381     }
       
  1382 
       
  1383     // call function with incompatible argument type
       
  1384     m_myObject->resetQtFunctionInvoked();
       
  1385     {
       
  1386         QString type;
       
  1387         QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
       
  1388         QCOMPARE(type, sError);
       
  1389         QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n    myInvokableWithQBrushArg(QBrush)"));
       
  1390         QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1391     }
       
  1392 }
       
  1393 
       
  1394 void tst_QWebFrame::connectAndDisconnect()
       
  1395 {
       
  1396     // connect(function)
       
  1397     QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
       
  1398     QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
       
  1399     QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
       
  1400 
       
  1401     {
       
  1402         QString type;
       
  1403         evalJS("myObject.mySignal.connect(123)", type);
       
  1404         QCOMPARE(type, sError);
       
  1405     }
       
  1406 
       
  1407     evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
       
  1408 
       
  1409     QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
       
  1410 
       
  1411     evalJS("gotSignal = false");
       
  1412     evalJS("myObject.mySignal()");
       
  1413     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1414     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
       
  1415     QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
       
  1416     QCOMPARE(evalJS("slotThisObject == window"), sTrue);
       
  1417 
       
  1418     evalJS("gotSignal = false");
       
  1419     m_myObject->emitMySignal();
       
  1420     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1421     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
       
  1422 
       
  1423     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
       
  1424 
       
  1425     evalJS("gotSignal = false");
       
  1426     m_myObject->emitMySignalWithIntArg(123);
       
  1427     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1428     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
       
  1429     QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
       
  1430 
       
  1431     QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
       
  1432     {
       
  1433         QString type;
       
  1434         evalJS("myObject.mySignal.disconnect(myHandler)", type);
       
  1435         QCOMPARE(type, sError);
       
  1436     }
       
  1437 
       
  1438     evalJS("gotSignal = false");
       
  1439     QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
       
  1440     m_myObject->emitMySignal2(true);
       
  1441     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1442     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
       
  1443     QCOMPARE(evalJS("signalArgs[0]"), sTrue);
       
  1444 
       
  1445     QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
       
  1446 
       
  1447     QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
       
  1448     QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
       
  1449     QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
       
  1450 
       
  1451     QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
       
  1452 
       
  1453     evalJS("gotSignal = false");
       
  1454     m_myObject->emitMySignal2();
       
  1455     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1456 
       
  1457     QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
       
  1458 
       
  1459     // connect(object, function)
       
  1460     evalJS("otherObject = { name:'foo' }");
       
  1461     QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
       
  1462     QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
       
  1463     evalJS("gotSignal = false");
       
  1464     m_myObject->emitMySignal();
       
  1465     QCOMPARE(evalJS("gotSignal"), sFalse);
       
  1466 
       
  1467     {
       
  1468         QString type;
       
  1469         evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
       
  1470         QCOMPARE(type, sError);
       
  1471     }
       
  1472 
       
  1473     QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
       
  1474     evalJS("gotSignal = false");
       
  1475     m_myObject->emitMySignal();
       
  1476     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1477     QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
       
  1478     QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
       
  1479     QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
       
  1480     QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
       
  1481     QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
       
  1482 
       
  1483     evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
       
  1484     QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
       
  1485     evalJS("gotSignal = false");
       
  1486     m_myObject->emitMySignal2(true);
       
  1487     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1488     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
       
  1489     QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
       
  1490     QCOMPARE(evalJS("signalSender == myObject"), sTrue);
       
  1491     QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
       
  1492     QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
       
  1493 
       
  1494     QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
       
  1495     evalJS("gotSignal = false");
       
  1496     m_myObject->emitMySignal2(true);
       
  1497     QCOMPARE(evalJS("gotSignal"), sTrue);
       
  1498     QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
       
  1499     QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
       
  1500     QCOMPARE(evalJS("signalSender == myObject"), sTrue);
       
  1501     QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
       
  1502 
       
  1503     // connect(obj, string)
       
  1504     QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
       
  1505     QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
       
  1506     QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
       
  1507     QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
       
  1508 
       
  1509     // check that emitting signals from script works
       
  1510 
       
  1511     // no arguments
       
  1512     QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
       
  1513     m_myObject->resetQtFunctionInvoked();
       
  1514     QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
       
  1515     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1516     QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
       
  1517 
       
  1518     // one argument
       
  1519     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
       
  1520     m_myObject->resetQtFunctionInvoked();
       
  1521     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
       
  1522     QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
       
  1523     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1524     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1525     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
       
  1526 
       
  1527     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
       
  1528     m_myObject->resetQtFunctionInvoked();
       
  1529     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
       
  1530     QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
       
  1531     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1532     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
       
  1533     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
       
  1534 
       
  1535     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
       
  1536     m_myObject->resetQtFunctionInvoked();
       
  1537     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
       
  1538     QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
       
  1539     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1540     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
       
  1541     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
       
  1542 
       
  1543     // connecting to overloaded slot
       
  1544     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
       
  1545     m_myObject->resetQtFunctionInvoked();
       
  1546     QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
       
  1547     QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
       
  1548     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1549     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
       
  1550     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
       
  1551 
       
  1552     QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
       
  1553     m_myObject->resetQtFunctionInvoked();
       
  1554     QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
       
  1555     QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
       
  1556     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1557     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
       
  1558     QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
       
  1559 
       
  1560     // erroneous input
       
  1561     {
       
  1562         // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
       
  1563         QString type;
       
  1564         QString ret = evalJS("(function() { }).connect()", type);
       
  1565         QCOMPARE(type, sError);
       
  1566         QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
       
  1567     }
       
  1568     {
       
  1569         QString type;
       
  1570         QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect;  o.connect()", type);
       
  1571         QCOMPARE(type, sError);
       
  1572         QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
       
  1573     }
       
  1574 
       
  1575     {
       
  1576         QString type;
       
  1577         QString ret = evalJS("(function() { }).connect(123)", type);
       
  1578         QCOMPARE(type, sError);
       
  1579         QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
       
  1580     }
       
  1581     {
       
  1582         QString type;
       
  1583         QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect;  o.connect(123)", type);
       
  1584         QCOMPARE(type, sError);
       
  1585         QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
       
  1586     }
       
  1587 
       
  1588     {
       
  1589         QString type;
       
  1590         QString ret = evalJS("myObject.myInvokable.connect(123)", type);
       
  1591         QCOMPARE(type, sError);
       
  1592         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
       
  1593     }
       
  1594     {
       
  1595         QString type;
       
  1596         QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
       
  1597         QCOMPARE(type, sError);
       
  1598         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
       
  1599     }
       
  1600 
       
  1601     {
       
  1602         QString type;
       
  1603         QString ret = evalJS("myObject.mySignal.connect(123)", type);
       
  1604         QCOMPARE(type, sError);
       
  1605         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
       
  1606     }
       
  1607 
       
  1608     {
       
  1609         QString type;
       
  1610         QString ret = evalJS("myObject.mySignal.disconnect()", type);
       
  1611         QCOMPARE(type, sError);
       
  1612         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
       
  1613     }
       
  1614     {
       
  1615         QString type;
       
  1616         QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect;  o.disconnect()", type);
       
  1617         QCOMPARE(type, sError);
       
  1618         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
       
  1619     }
       
  1620 
       
  1621     /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
       
  1622     {
       
  1623         QString type;
       
  1624         QString ret = evalJS("(function() { }).disconnect(123)", type);
       
  1625         QCOMPARE(type, sError);
       
  1626         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
       
  1627     }
       
  1628     */
       
  1629 
       
  1630     {
       
  1631         QString type;
       
  1632         QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
       
  1633         QCOMPARE(type, sError);
       
  1634         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
       
  1635     }
       
  1636 
       
  1637     {
       
  1638         QString type;
       
  1639         QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
       
  1640         QCOMPARE(type, sError);
       
  1641         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
       
  1642     }
       
  1643     {
       
  1644         QString type;
       
  1645         QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
       
  1646         QCOMPARE(type, sError);
       
  1647         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
       
  1648     }
       
  1649 
       
  1650     {
       
  1651         QString type;
       
  1652         QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
       
  1653         QCOMPARE(type, sError);
       
  1654         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
       
  1655     }
       
  1656 
       
  1657     {
       
  1658         QString type;
       
  1659         QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
       
  1660         QCOMPARE(type, sError);
       
  1661         QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
       
  1662     }
       
  1663 
       
  1664     // when the wrapper dies, the connection stays alive
       
  1665     QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
       
  1666     m_myObject->resetQtFunctionInvoked();
       
  1667     m_myObject->emitMySignal();
       
  1668     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1669     evalJS("myObject = null");
       
  1670     evalJS("gc()");
       
  1671     m_myObject->resetQtFunctionInvoked();
       
  1672     m_myObject->emitMySignal();
       
  1673     QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
       
  1674 }
       
  1675 
       
  1676 void tst_QWebFrame::classEnums()
       
  1677 {
       
  1678     // We don't do the meta thing currently, unfortunately!!!
       
  1679     /*
       
  1680     QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
       
  1681     m_engine->globalObject().setProperty("MyQObject", myClass);
       
  1682 
       
  1683     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
       
  1684              MyQObject::FooPolicy);
       
  1685     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
       
  1686              MyQObject::BarPolicy);
       
  1687     QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
       
  1688              MyQObject::BazPolicy);
       
  1689 
       
  1690     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
       
  1691              MyQObject::FooStrategy);
       
  1692     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
       
  1693              MyQObject::BarStrategy);
       
  1694     QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
       
  1695              MyQObject::BazStrategy);
       
  1696 
       
  1697     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
       
  1698              MyQObject::NoAbility);
       
  1699     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
       
  1700              MyQObject::FooAbility);
       
  1701     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
       
  1702              MyQObject::BarAbility);
       
  1703     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
       
  1704              MyQObject::BazAbility);
       
  1705     QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
       
  1706              MyQObject::AllAbility);
       
  1707 
       
  1708     // enums from Qt are inherited through prototype
       
  1709     QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
       
  1710              Qt::StrongFocus);
       
  1711     QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
       
  1712              Qt::Key_Left);
       
  1713 
       
  1714     QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
       
  1715 
       
  1716     qRegisterMetaType<MyQObject::Policy>("Policy");
       
  1717 
       
  1718     m_myObject->resetQtFunctionInvoked();
       
  1719     QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
       
  1720     QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
       
  1721     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1722     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
       
  1723 
       
  1724     m_myObject->resetQtFunctionInvoked();
       
  1725     QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
       
  1726     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
       
  1727     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  1728     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
       
  1729 
       
  1730     m_myObject->resetQtFunctionInvoked();
       
  1731     {
       
  1732         QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
       
  1733         QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
       
  1734         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  1735         QCOMPARE(ret.isVariant());
       
  1736     }
       
  1737     m_myObject->resetQtFunctionInvoked();
       
  1738     {
       
  1739         QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
       
  1740         QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
       
  1741         QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
       
  1742         QCOMPARE(ret.isNumber());
       
  1743     }
       
  1744     */
       
  1745 }
       
  1746 
       
  1747 void tst_QWebFrame::classConstructor()
       
  1748 {
       
  1749     /*
       
  1750     QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
       
  1751     m_engine->globalObject().setProperty("MyQObject", myClass);
       
  1752 
       
  1753     QString myObj = evalJS("myObj = MyQObject()");
       
  1754     QObject* qobj = myObj.toQObject();
       
  1755     QVERIFY(qobj != 0);
       
  1756     QCOMPARE(qobj->metaObject()->className(), "MyQObject");
       
  1757     QCOMPARE(qobj->parent(), (QObject*)0);
       
  1758 
       
  1759     QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
       
  1760     m_engine->globalObject().setProperty("QObject", qobjectClass);
       
  1761 
       
  1762     QString otherObj = evalJS("otherObj = QObject(myObj)");
       
  1763     QObject* qqobj = otherObj.toQObject();
       
  1764     QVERIFY(qqobj != 0);
       
  1765     QCOMPARE(qqobj->metaObject()->className(), "QObject");
       
  1766     QCOMPARE(qqobj->parent(), qobj);
       
  1767 
       
  1768     delete qobj;
       
  1769     */
       
  1770 }
       
  1771 
       
  1772 void tst_QWebFrame::overrideInvokable()
       
  1773 {
       
  1774     m_myObject->resetQtFunctionInvoked();
       
  1775     QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
       
  1776     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1777 
       
  1778     /* XFAIL - can't write to functions with RuntimeObject
       
  1779     m_myObject->resetQtFunctionInvoked();
       
  1780     evalJS("myObject.myInvokable = function() { window.a = 123; }");
       
  1781     evalJS("myObject.myInvokable()");
       
  1782     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1783     QCOMPARE(evalJS("window.a").toDouble(), 123.0);
       
  1784 
       
  1785     evalJS("myObject.myInvokable = function() { window.a = 456; }");
       
  1786     evalJS("myObject.myInvokable()");
       
  1787     QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
       
  1788     QCOMPARE(evalJS("window.a").toDouble(), 456.0);
       
  1789     */
       
  1790 
       
  1791     evalJS("delete myObject.myInvokable");
       
  1792     evalJS("myObject.myInvokable()");
       
  1793     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1794 
       
  1795     /* XFAIL - ditto
       
  1796     m_myObject->resetQtFunctionInvoked();
       
  1797     evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
       
  1798     evalJS("myObject.myInvokable(123)");
       
  1799     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1800     */
       
  1801 
       
  1802     evalJS("delete myObject.myInvokable");
       
  1803     m_myObject->resetQtFunctionInvoked();
       
  1804     // this form (with the '()') is read-only
       
  1805     evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
       
  1806     evalJS("myObject.myInvokable()");
       
  1807     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1808 }
       
  1809 
       
  1810 void tst_QWebFrame::transferInvokable()
       
  1811 {
       
  1812     /* XFAIL - can't put to functions with RuntimeObject
       
  1813     m_myObject->resetQtFunctionInvoked();
       
  1814     evalJS("myObject.foozball = myObject.myInvokable");
       
  1815     evalJS("myObject.foozball()");
       
  1816     QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
       
  1817     m_myObject->resetQtFunctionInvoked();
       
  1818     evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
       
  1819     evalJS("myObject.foozball(123)");
       
  1820     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1821     m_myObject->resetQtFunctionInvoked();
       
  1822     evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
       
  1823     evalJS("myObject.myInvokable(123)");
       
  1824     QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
       
  1825 
       
  1826     MyOtherQObject other;
       
  1827     m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
       
  1828     evalJS("myOtherObject.foo = myObject.foozball");
       
  1829     other.resetQtFunctionInvoked();
       
  1830     evalJS("myOtherObject.foo(456)");
       
  1831     QCOMPARE(other.qtFunctionInvoked(), 1);
       
  1832     */
       
  1833 }
       
  1834 
       
  1835 void tst_QWebFrame::findChild()
       
  1836 {
       
  1837     /*
       
  1838     QObject* child = new QObject(m_myObject);
       
  1839     child->setObjectName(QLatin1String("myChildObject"));
       
  1840 
       
  1841     {
       
  1842         QString result = evalJS("myObject.findChild('noSuchChild')");
       
  1843         QCOMPARE(result.isNull());
       
  1844     }
       
  1845 
       
  1846     {
       
  1847         QString result = evalJS("myObject.findChild('myChildObject')");
       
  1848         QCOMPARE(result.isQObject());
       
  1849         QCOMPARE(result.toQObject(), child);
       
  1850     }
       
  1851 
       
  1852     delete child;
       
  1853     */
       
  1854 }
       
  1855 
       
  1856 void tst_QWebFrame::findChildren()
       
  1857 {
       
  1858     /*
       
  1859     QObject* child = new QObject(m_myObject);
       
  1860     child->setObjectName(QLatin1String("myChildObject"));
       
  1861 
       
  1862     {
       
  1863         QString result = evalJS("myObject.findChildren('noSuchChild')");
       
  1864         QCOMPARE(result.isArray());
       
  1865         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
       
  1866     }
       
  1867 
       
  1868     {
       
  1869         QString result = evalJS("myObject.findChildren('myChildObject')");
       
  1870         QCOMPARE(result.isArray());
       
  1871         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
       
  1872         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
       
  1873     }
       
  1874 
       
  1875     QObject* namelessChild = new QObject(m_myObject);
       
  1876 
       
  1877     {
       
  1878         QString result = evalJS("myObject.findChildren('myChildObject')");
       
  1879         QCOMPARE(result.isArray());
       
  1880         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
       
  1881         QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
       
  1882     }
       
  1883 
       
  1884     QObject* anotherChild = new QObject(m_myObject);
       
  1885     anotherChild->setObjectName(QLatin1String("anotherChildObject"));
       
  1886 
       
  1887     {
       
  1888         QString result = evalJS("myObject.findChildren('anotherChildObject')");
       
  1889         QCOMPARE(result.isArray());
       
  1890         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
       
  1891         QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
       
  1892     }
       
  1893 
       
  1894     anotherChild->setObjectName(QLatin1String("myChildObject"));
       
  1895     {
       
  1896         QString result = evalJS("myObject.findChildren('myChildObject')");
       
  1897         QCOMPARE(result.isArray());
       
  1898         QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
       
  1899         QObject* o1 = result.property(QLatin1String("0")).toQObject();
       
  1900         QObject* o2 = result.property(QLatin1String("1")).toQObject();
       
  1901         if (o1 != child) {
       
  1902             QCOMPARE(o1, anotherChild);
       
  1903             QCOMPARE(o2, child);
       
  1904         } else {
       
  1905             QCOMPARE(o1, child);
       
  1906             QCOMPARE(o2, anotherChild);
       
  1907         }
       
  1908     }
       
  1909 
       
  1910     // find all
       
  1911     {
       
  1912         QString result = evalJS("myObject.findChildren()");
       
  1913         QVERIFY(result.isArray());
       
  1914         int count = 3;
       
  1915         QCOMPARE(result.property("length"), QLatin1String(count);
       
  1916         for (int i = 0; i < 3; ++i) {
       
  1917             QObject* o = result.property(i).toQObject();
       
  1918             if (o == namelessChild || o == child || o == anotherChild)
       
  1919                 --count;
       
  1920         }
       
  1921         QVERIFY(count == 0);
       
  1922     }
       
  1923 
       
  1924     delete anotherChild;
       
  1925     delete namelessChild;
       
  1926     delete child;
       
  1927     */
       
  1928 }
       
  1929 
       
  1930 void tst_QWebFrame::overloadedSlots()
       
  1931 {
       
  1932     // should pick myOverloadedSlot(double)
       
  1933     m_myObject->resetQtFunctionInvoked();
       
  1934     evalJS("myObject.myOverloadedSlot(10)");
       
  1935     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
       
  1936 
       
  1937     // should pick myOverloadedSlot(double)
       
  1938     m_myObject->resetQtFunctionInvoked();
       
  1939     evalJS("myObject.myOverloadedSlot(10.0)");
       
  1940     QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
       
  1941 
       
  1942     // should pick myOverloadedSlot(QString)
       
  1943     m_myObject->resetQtFunctionInvoked();
       
  1944     evalJS("myObject.myOverloadedSlot('10')");
       
  1945     QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
       
  1946 
       
  1947     // should pick myOverloadedSlot(bool)
       
  1948     m_myObject->resetQtFunctionInvoked();
       
  1949     evalJS("myObject.myOverloadedSlot(true)");
       
  1950     QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
       
  1951 
       
  1952     // should pick myOverloadedSlot(QDateTime)
       
  1953     m_myObject->resetQtFunctionInvoked();
       
  1954     evalJS("myObject.myOverloadedSlot(new Date())");
       
  1955     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
       
  1956 
       
  1957     // should pick myOverloadedSlot(QRegExp)
       
  1958     m_myObject->resetQtFunctionInvoked();
       
  1959     evalJS("myObject.myOverloadedSlot(new RegExp())");
       
  1960     QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
       
  1961 
       
  1962     // should pick myOverloadedSlot(QVariant)
       
  1963     /* XFAIL
       
  1964     m_myObject->resetQtFunctionInvoked();
       
  1965     QString f = evalJS("myObject.myOverloadedSlot");
       
  1966     f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
       
  1967     QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
       
  1968     */
       
  1969 
       
  1970     // should pick myOverloadedSlot(QRegExp)
       
  1971     m_myObject->resetQtFunctionInvoked();
       
  1972     evalJS("myObject.myOverloadedSlot(document.body)");
       
  1973     QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=37319", Continue);
       
  1974     QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
       
  1975 
       
  1976     // should pick myOverloadedSlot(QObject*)
       
  1977     m_myObject->resetQtFunctionInvoked();
       
  1978     evalJS("myObject.myOverloadedSlot(myObject)");
       
  1979     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
       
  1980 
       
  1981     // should pick myOverloadedSlot(QObject*)
       
  1982     m_myObject->resetQtFunctionInvoked();
       
  1983     evalJS("myObject.myOverloadedSlot(null)");
       
  1984     QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
       
  1985 
       
  1986     // should pick myOverloadedSlot(QStringList)
       
  1987     m_myObject->resetQtFunctionInvoked();
       
  1988     evalJS("myObject.myOverloadedSlot(['hello'])");
       
  1989     QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
       
  1990 }
       
  1991 
       
  1992 void tst_QWebFrame::enumerate_data()
       
  1993 {
       
  1994     QTest::addColumn<QStringList>("expectedNames");
       
  1995 
       
  1996     QTest::newRow("enumerate all")
       
  1997     << (QStringList()
       
  1998         // meta-object-defined properties:
       
  1999         //   inherited
       
  2000         << "objectName"
       
  2001         //   non-inherited
       
  2002         << "p1" << "p2" << "p4" << "p6"
       
  2003         // dynamic properties
       
  2004         << "dp1" << "dp2" << "dp3"
       
  2005         // inherited slots
       
  2006         << "destroyed(QObject*)" << "destroyed()"
       
  2007         << "deleteLater()"
       
  2008         // not included because it's private:
       
  2009         // << "_q_reregisterTimers(void*)"
       
  2010         // signals
       
  2011         << "mySignal()"
       
  2012         // slots
       
  2013         << "mySlot()" << "myOtherSlot()");
       
  2014 }
       
  2015 
       
  2016 void tst_QWebFrame::enumerate()
       
  2017 {
       
  2018     QFETCH(QStringList, expectedNames);
       
  2019 
       
  2020     MyEnumTestQObject enumQObject;
       
  2021     // give it some dynamic properties
       
  2022     enumQObject.setProperty("dp1", "dp1");
       
  2023     enumQObject.setProperty("dp2", "dp2");
       
  2024     enumQObject.setProperty("dp3", "dp3");
       
  2025     m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
       
  2026 
       
  2027     // enumerate in script
       
  2028     {
       
  2029         evalJS("var enumeratedProperties = []");
       
  2030         evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
       
  2031         QStringList result = evalJSV("enumeratedProperties").toStringList();
       
  2032         QCOMPARE(result.size(), expectedNames.size());
       
  2033         for (int i = 0; i < expectedNames.size(); ++i)
       
  2034             QCOMPARE(result.at(i), expectedNames.at(i));
       
  2035     }
       
  2036 }
       
  2037 
       
  2038 void tst_QWebFrame::objectDeleted()
       
  2039 {
       
  2040     MyQObject* qobj = new MyQObject();
       
  2041     m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
       
  2042     evalJS("bar.objectName = 'foo';");
       
  2043     QCOMPARE(qobj->objectName(), QLatin1String("foo"));
       
  2044     evalJS("bar.intProperty = 123;");
       
  2045     QCOMPARE(qobj->intProperty(), 123);
       
  2046     qobj->resetQtFunctionInvoked();
       
  2047     evalJS("bar.myInvokable.call(bar);");
       
  2048     QCOMPARE(qobj->qtFunctionInvoked(), 0);
       
  2049 
       
  2050     // do this, to ensure that we cache that it implements call
       
  2051     evalJS("bar()");
       
  2052 
       
  2053     // now delete the object
       
  2054     delete qobj;
       
  2055 
       
  2056     QCOMPARE(evalJS("typeof bar"), sObject);
       
  2057 
       
  2058     // any attempt to access properties of the object should result in an exception
       
  2059     {
       
  2060         QString type;
       
  2061         QString ret = evalJS("bar.objectName", type);
       
  2062         QCOMPARE(type, sError);
       
  2063         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2064     }
       
  2065     {
       
  2066         QString type;
       
  2067         QString ret = evalJS("bar.objectName = 'foo'", type);
       
  2068         QCOMPARE(type, sError);
       
  2069         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2070     }
       
  2071 
       
  2072     // myInvokable is stored in member table (since we've accessed it before deletion)
       
  2073     {
       
  2074         QString type;
       
  2075         evalJS("bar.myInvokable", type);
       
  2076         QCOMPARE(type, sFunction);
       
  2077     }
       
  2078 
       
  2079     {
       
  2080         QString type;
       
  2081         QString ret = evalJS("bar.myInvokable.call(bar);", type);
       
  2082         ret = evalJS("bar.myInvokable(bar)", type);
       
  2083         QCOMPARE(type, sError);
       
  2084         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
       
  2085     }
       
  2086     // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
       
  2087     {
       
  2088         QString type;
       
  2089         QString ret = evalJS("bar.myInvokableWithIntArg", type);
       
  2090         QCOMPARE(type, sError);
       
  2091         QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
       
  2092     }
       
  2093 
       
  2094     // access from script
       
  2095     evalJS("window.o = bar;");
       
  2096     {
       
  2097         QString type;
       
  2098         QString ret = evalJS("o.objectName", type);
       
  2099         QCOMPARE(type, sError);
       
  2100         QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
       
  2101     }
       
  2102     {
       
  2103         QString type;
       
  2104         QString ret = evalJS("o.myInvokable()", type);
       
  2105         QCOMPARE(type, sError);
       
  2106         QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
       
  2107     }
       
  2108     {
       
  2109         QString type;
       
  2110         QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
       
  2111         QCOMPARE(type, sError);
       
  2112         QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
       
  2113     }
       
  2114 }
       
  2115 
       
  2116 void tst_QWebFrame::typeConversion()
       
  2117 {
       
  2118     m_myObject->resetQtFunctionInvoked();
       
  2119 
       
  2120     QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
       
  2121     QDateTime utclocaldt = localdt.toUTC();
       
  2122     QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
       
  2123 
       
  2124     // Dates in JS (default to local)
       
  2125     evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
       
  2126     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
       
  2127     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  2128     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
       
  2129 
       
  2130     m_myObject->resetQtFunctionInvoked();
       
  2131     evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
       
  2132     QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
       
  2133     QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
       
  2134     QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
       
  2135 
       
  2136     // Pushing QDateTimes into JS
       
  2137     // Local
       
  2138     evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
       
  2139     evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
       
  2140     m_myObject->emitMySignalWithDateTimeArg(localdt);
       
  2141     QCOMPARE(evalJS("window.__date_equals"), sTrue);
       
  2142     evalJS("delete window.__date_equals");
       
  2143     m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
       
  2144     QCOMPARE(evalJS("window.__date_equals"), sTrue);
       
  2145     evalJS("delete window.__date_equals");
       
  2146     evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
       
  2147 
       
  2148     // UTC
       
  2149     evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
       
  2150     evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
       
  2151     m_myObject->emitMySignalWithDateTimeArg(utcdt);
       
  2152     QCOMPARE(evalJS("window.__date_equals"), sTrue);
       
  2153     evalJS("delete window.__date_equals");
       
  2154     evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
       
  2155 
       
  2156     // ### RegExps
       
  2157 }
       
  2158 
       
  2159 class StringListTestObject : public QObject {
       
  2160     Q_OBJECT
       
  2161 public Q_SLOTS:
       
  2162     QVariant stringList()
       
  2163     {
       
  2164         return QStringList() << "Q" << "t";
       
  2165     };
       
  2166 };
       
  2167 
       
  2168 void tst_QWebFrame::arrayObjectEnumerable()
       
  2169 {
       
  2170     QWebPage page;
       
  2171     QWebFrame* frame = page.mainFrame();
       
  2172     QObject* qobject = new StringListTestObject();
       
  2173     frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership);
       
  2174 
       
  2175     const QString script("var stringArray = test.stringList();"
       
  2176                          "var result = '';"
       
  2177                          "for (var i in stringArray) {"
       
  2178                          "    result += stringArray[i];"
       
  2179                          "}"
       
  2180                          "result;");
       
  2181     QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt"));
       
  2182 }
       
  2183 
       
  2184 void tst_QWebFrame::symmetricUrl()
       
  2185 {
       
  2186     QVERIFY(m_view->url().isEmpty());
       
  2187 
       
  2188     QCOMPARE(m_view->history()->count(), 0);
       
  2189 
       
  2190     QUrl dataUrl("data:text/html,<h1>Test");
       
  2191 
       
  2192     m_view->setUrl(dataUrl);
       
  2193     QCOMPARE(m_view->url(), dataUrl);
       
  2194     QCOMPARE(m_view->history()->count(), 0);
       
  2195 
       
  2196     // loading is _not_ immediate, so the text isn't set just yet.
       
  2197     QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
       
  2198 
       
  2199     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
       
  2200 
       
  2201     QCOMPARE(m_view->history()->count(), 1);
       
  2202     QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
       
  2203 
       
  2204     QUrl dataUrl2("data:text/html,<h1>Test2");
       
  2205     QUrl dataUrl3("data:text/html,<h1>Test3");
       
  2206 
       
  2207     m_view->setUrl(dataUrl2);
       
  2208     m_view->setUrl(dataUrl3);
       
  2209 
       
  2210     QCOMPARE(m_view->url(), dataUrl3);
       
  2211 
       
  2212     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
       
  2213 
       
  2214     QCOMPARE(m_view->history()->count(), 2);
       
  2215 
       
  2216     QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
       
  2217 }
       
  2218 
       
  2219 void tst_QWebFrame::progressSignal()
       
  2220 {
       
  2221     QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
       
  2222 
       
  2223     QUrl dataUrl("data:text/html,<h1>Test");
       
  2224     m_view->setUrl(dataUrl);
       
  2225 
       
  2226     ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
       
  2227 
       
  2228     QVERIFY(progressSpy.size() >= 2);
       
  2229 
       
  2230     // WebKit defines initialProgressValue as 10%, not 0%
       
  2231     QCOMPARE(progressSpy.first().first().toInt(), 10);
       
  2232 
       
  2233     // But we always end at 100%
       
  2234     QCOMPARE(progressSpy.last().first().toInt(), 100);
       
  2235 }
       
  2236 
       
  2237 void tst_QWebFrame::urlChange()
       
  2238 {
       
  2239     QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
       
  2240 
       
  2241     QUrl dataUrl("data:text/html,<h1>Test");
       
  2242     m_view->setUrl(dataUrl);
       
  2243 
       
  2244     ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
       
  2245 
       
  2246     QCOMPARE(urlSpy.size(), 1);
       
  2247 
       
  2248     QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>");
       
  2249     m_view->setUrl(dataUrl2);
       
  2250 
       
  2251     ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
       
  2252 
       
  2253     QCOMPARE(urlSpy.size(), 2);
       
  2254 }
       
  2255 
       
  2256 
       
  2257 void tst_QWebFrame::domCycles()
       
  2258 {
       
  2259     m_view->setHtml("<html><body>");
       
  2260     QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
       
  2261     QVERIFY(v.type() == QVariant::Map);
       
  2262 }
       
  2263 
       
  2264 class FakeReply : public QNetworkReply {
       
  2265     Q_OBJECT
       
  2266 
       
  2267 public:
       
  2268     FakeReply(const QNetworkRequest& request, QObject* parent = 0)
       
  2269         : QNetworkReply(parent)
       
  2270     {
       
  2271         setOperation(QNetworkAccessManager::GetOperation);
       
  2272         setRequest(request);
       
  2273         if (request.url() == QUrl("qrc:/test1.html")) {
       
  2274             setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html"));
       
  2275             setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html"));
       
  2276         }
       
  2277 #ifndef QT_NO_OPENSSL
       
  2278         else if (request.url() == QUrl("qrc:/fake-ssl-error.html"))
       
  2279             setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error !")); // force a ssl error
       
  2280 #endif
       
  2281         else if (request.url() == QUrl("http://abcdef.abcdef/"))
       
  2282             setError(QNetworkReply::HostNotFoundError, tr("Invalid URL"));
       
  2283 
       
  2284         open(QIODevice::ReadOnly);
       
  2285         QTimer::singleShot(0, this, SLOT(timeout()));
       
  2286     }
       
  2287     ~FakeReply()
       
  2288     {
       
  2289         close();
       
  2290     }
       
  2291     virtual void abort() {}
       
  2292     virtual void close() {}
       
  2293 
       
  2294 protected:
       
  2295     qint64 readData(char*, qint64)
       
  2296     {
       
  2297         return 0;
       
  2298     }
       
  2299 
       
  2300 private slots:
       
  2301     void timeout()
       
  2302     {
       
  2303         if (request().url() == QUrl("qrc://test1.html"))
       
  2304             emit error(this->error());
       
  2305         else if (request().url() == QUrl("http://abcdef.abcdef/"))
       
  2306             emit metaDataChanged();
       
  2307 #ifndef QT_NO_OPENSSL
       
  2308         else if (request().url() == QUrl("qrc:/fake-ssl-error.html"))
       
  2309             return;
       
  2310 #endif
       
  2311 
       
  2312         emit readyRead();
       
  2313         emit finished();
       
  2314     }
       
  2315 };
       
  2316 
       
  2317 class FakeNetworkManager : public QNetworkAccessManager {
       
  2318     Q_OBJECT
       
  2319 
       
  2320 public:
       
  2321     FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { }
       
  2322 
       
  2323 protected:
       
  2324     virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
       
  2325     {
       
  2326         QString url = request.url().toString();
       
  2327         if (op == QNetworkAccessManager::GetOperation) {
       
  2328             if (url == "qrc:/test1.html" ||  url == "http://abcdef.abcdef/")
       
  2329                 return new FakeReply(request, this);
       
  2330 #ifndef QT_NO_OPENSSL
       
  2331             else if (url == "qrc:/fake-ssl-error.html") {
       
  2332                 FakeReply* reply = new FakeReply(request, this);
       
  2333                 QList<QSslError> errors;
       
  2334                 emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError));
       
  2335                 return reply;
       
  2336             }
       
  2337 #endif
       
  2338        }
       
  2339 
       
  2340         return QNetworkAccessManager::createRequest(op, request, outgoingData);
       
  2341     }
       
  2342 };
       
  2343 
       
  2344 void tst_QWebFrame::requestedUrl()
       
  2345 {
       
  2346     QWebPage page;
       
  2347     QWebFrame* frame = page.mainFrame();
       
  2348 
       
  2349     // in few seconds, the image should be completely loaded
       
  2350     QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
       
  2351     FakeNetworkManager* networkManager = new FakeNetworkManager(&page);
       
  2352     page.setNetworkAccessManager(networkManager);
       
  2353 
       
  2354     frame->setUrl(QUrl("qrc:/test1.html"));
       
  2355     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2356     QCOMPARE(spy.count(), 1);
       
  2357     QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html"));
       
  2358     QCOMPARE(frame->url(), QUrl("qrc:/test2.html"));
       
  2359 
       
  2360     frame->setUrl(QUrl("qrc:/non-existent.html"));
       
  2361     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2362     QCOMPARE(spy.count(), 2);
       
  2363     QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html"));
       
  2364     QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html"));
       
  2365 
       
  2366     frame->setUrl(QUrl("http://abcdef.abcdef"));
       
  2367     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2368     QCOMPARE(spy.count(), 3);
       
  2369     QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/"));
       
  2370     QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/"));
       
  2371 
       
  2372 #ifndef QT_NO_OPENSSL
       
  2373     qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
       
  2374     qRegisterMetaType<QNetworkReply* >("QNetworkReply*");
       
  2375 
       
  2376     QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2377     frame->setUrl(QUrl("qrc:/fake-ssl-error.html"));
       
  2378     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2379     QCOMPARE(spy2.count(), 1);
       
  2380     QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html"));
       
  2381     QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html"));
       
  2382 #endif
       
  2383 }
       
  2384 
       
  2385 void tst_QWebFrame::javaScriptWindowObjectCleared_data()
       
  2386 {
       
  2387     QTest::addColumn<QString>("html");
       
  2388     QTest::addColumn<int>("signalCount");
       
  2389     QTest::newRow("with <script>") << "<html><body><script></script><p>hello world</p></body></html>" << 1;
       
  2390     QTest::newRow("without <script>") << "<html><body><p>hello world</p></body></html>" << 0;
       
  2391 }
       
  2392 
       
  2393 void tst_QWebFrame::javaScriptWindowObjectCleared()
       
  2394 {
       
  2395     QWebPage page;
       
  2396     QWebFrame* frame = page.mainFrame();
       
  2397     QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
       
  2398     QFETCH(QString, html);
       
  2399     frame->setHtml(html);
       
  2400 
       
  2401     QFETCH(int, signalCount);
       
  2402     QCOMPARE(spy.count(), signalCount);
       
  2403 }
       
  2404 
       
  2405 void tst_QWebFrame::javaScriptWindowObjectClearedOnEvaluate()
       
  2406 {
       
  2407     QWebPage page;
       
  2408     QWebFrame* frame = page.mainFrame();
       
  2409     QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
       
  2410     frame->setHtml("<html></html>");
       
  2411     QCOMPARE(spy.count(), 0);
       
  2412     frame->evaluateJavaScript("var a = 'a';");
       
  2413     QCOMPARE(spy.count(), 1);
       
  2414     // no new clear for a new script:
       
  2415     frame->evaluateJavaScript("var a = 1;");
       
  2416     QCOMPARE(spy.count(), 1);
       
  2417 }
       
  2418 
       
  2419 void tst_QWebFrame::setHtml()
       
  2420 {
       
  2421     QString html("<html><head></head><body><p>hello world</p></body></html>");
       
  2422     m_view->page()->mainFrame()->setHtml(html);
       
  2423     QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
       
  2424 }
       
  2425 
       
  2426 void tst_QWebFrame::setHtmlWithResource()
       
  2427 {
       
  2428     QString html("<html><body><p>hello world</p><img src='qrc:/image.png'/></body></html>");
       
  2429 
       
  2430     QWebPage page;
       
  2431     QWebFrame* frame = page.mainFrame();
       
  2432 
       
  2433     // in few seconds, the image should be completey loaded
       
  2434     QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
       
  2435     frame->setHtml(html);
       
  2436     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2437     QCOMPARE(spy.count(), 1);
       
  2438 
       
  2439     QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
       
  2440     QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
       
  2441     QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
       
  2442 
       
  2443     QString html2 =
       
  2444         "<html>"
       
  2445             "<head>"
       
  2446                 "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
       
  2447             "</head>"
       
  2448             "<body>"
       
  2449                 "<p id='idP'>some text</p>"
       
  2450             "</body>"
       
  2451         "</html>";
       
  2452 
       
  2453     // in few seconds, the CSS should be completey loaded
       
  2454     frame->setHtml(html2);
       
  2455     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2456     QCOMPARE(spy.size(), 2);
       
  2457 
       
  2458     QWebElement p = frame->documentElement().findAll("p").at(0);
       
  2459     QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("red"));
       
  2460 }
       
  2461 
       
  2462 void tst_QWebFrame::setHtmlWithBaseURL()
       
  2463 {
       
  2464     if (!QDir(TESTS_SOURCE_DIR).exists())
       
  2465         QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
       
  2466 
       
  2467     QDir::setCurrent(TESTS_SOURCE_DIR);
       
  2468 
       
  2469     QString html("<html><body><p>hello world</p><img src='resources/image2.png'/></body></html>");
       
  2470 
       
  2471     QWebPage page;
       
  2472     QWebFrame* frame = page.mainFrame();
       
  2473 
       
  2474     // in few seconds, the image should be completey loaded
       
  2475     QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
       
  2476 
       
  2477     frame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
       
  2478     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2479     QCOMPARE(spy.count(), 1);
       
  2480 
       
  2481     QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
       
  2482     QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
       
  2483     QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
       
  2484 
       
  2485     // no history item has to be added.
       
  2486     QCOMPARE(m_view->page()->history()->count(), 0);
       
  2487 }
       
  2488 
       
  2489 class MyPage : public QWebPage
       
  2490 {
       
  2491 public:
       
  2492     MyPage() :  QWebPage(), alerts(0) {}
       
  2493     int alerts;
       
  2494 
       
  2495 protected:
       
  2496     virtual void javaScriptAlert(QWebFrame*, const QString& msg)
       
  2497     {
       
  2498         alerts++;
       
  2499         QCOMPARE(msg, QString("foo"));
       
  2500         // Should not be enough to trigger deferred loading, since we've upped the HTML
       
  2501         // tokenizer delay in the Qt frameloader. See HTMLTokenizer::continueProcessing()
       
  2502         QTest::qWait(1000);
       
  2503     }
       
  2504 };
       
  2505 
       
  2506 void tst_QWebFrame::setHtmlWithJSAlert()
       
  2507 {
       
  2508     QString html("<html><head></head><body><script>alert('foo');</script><p>hello world</p></body></html>");
       
  2509     MyPage page;
       
  2510     m_view->setPage(&page);
       
  2511     page.mainFrame()->setHtml(html);
       
  2512     QCOMPARE(page.alerts, 1);
       
  2513     QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
       
  2514 }
       
  2515 
       
  2516 class TestNetworkManager : public QNetworkAccessManager
       
  2517 {
       
  2518 public:
       
  2519     TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
       
  2520 
       
  2521     QList<QUrl> requestedUrls;
       
  2522 
       
  2523 protected:
       
  2524     virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
       
  2525         requestedUrls.append(request.url());
       
  2526         QNetworkRequest redirectedRequest = request;
       
  2527         redirectedRequest.setUrl(QUrl("data:text/html,<p>hello"));
       
  2528         return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData);
       
  2529     }
       
  2530 };
       
  2531 
       
  2532 void tst_QWebFrame::ipv6HostEncoding()
       
  2533 {
       
  2534     TestNetworkManager* networkManager = new TestNetworkManager(m_page);
       
  2535     m_page->setNetworkAccessManager(networkManager);
       
  2536     networkManager->requestedUrls.clear();
       
  2537 
       
  2538     QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html");
       
  2539     m_view->setHtml("<p>Hi", baseUrl);
       
  2540     m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();"
       
  2541             "r.open('GET', 'http://[::1]/test.xml', false);"
       
  2542             "r.send(null);"
       
  2543             );
       
  2544     QCOMPARE(networkManager->requestedUrls.count(), 1);
       
  2545     QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml"));
       
  2546 }
       
  2547 
       
  2548 void tst_QWebFrame::metaData()
       
  2549 {
       
  2550     m_view->setHtml("<html>"
       
  2551                     "    <head>"
       
  2552                     "        <meta name=\"description\" content=\"Test description\">"
       
  2553                     "        <meta name=\"keywords\" content=\"HTML, JavaScript, Css\">"
       
  2554                     "    </head>"
       
  2555                     "</html>");
       
  2556 
       
  2557     QMultiMap<QString, QString> metaData = m_view->page()->mainFrame()->metaData();
       
  2558 
       
  2559     QCOMPARE(metaData.count(), 2);
       
  2560 
       
  2561     QCOMPARE(metaData.value("description"), QString("Test description"));
       
  2562     QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css"));
       
  2563     QCOMPARE(metaData.value("nonexistant"), QString());
       
  2564 
       
  2565     m_view->setHtml("<html>"
       
  2566                     "    <head>"
       
  2567                     "        <meta name=\"samekey\" content=\"FirstValue\">"
       
  2568                     "        <meta name=\"samekey\" content=\"SecondValue\">"
       
  2569                     "    </head>"
       
  2570                     "</html>");
       
  2571 
       
  2572     metaData = m_view->page()->mainFrame()->metaData();
       
  2573 
       
  2574     QCOMPARE(metaData.count(), 2);
       
  2575 
       
  2576     QStringList values = metaData.values("samekey");
       
  2577     QCOMPARE(values.count(), 2);
       
  2578 
       
  2579     QVERIFY(values.contains("FirstValue"));
       
  2580     QVERIFY(values.contains("SecondValue"));
       
  2581 
       
  2582     QCOMPARE(metaData.value("nonexistant"), QString());
       
  2583 }
       
  2584 
       
  2585 #if !defined(Q_WS_MAEMO_5)
       
  2586 void tst_QWebFrame::popupFocus()
       
  2587 {
       
  2588     QWebView view;
       
  2589     view.setHtml("<html>"
       
  2590                  "    <body>"
       
  2591                  "        <select name=\"select\">"
       
  2592                  "            <option>1</option>"
       
  2593                  "            <option>2</option>"
       
  2594                  "        </select>"
       
  2595                  "        <input type=\"text\"> </input>"
       
  2596                  "        <textarea name=\"text_area\" rows=\"3\" cols=\"40\">"
       
  2597                  "This test checks whether showing and hiding a popup"
       
  2598                  "takes the focus away from the webpage."
       
  2599                  "        </textarea>"
       
  2600                  "    </body>"
       
  2601                  "</html>");
       
  2602     view.resize(400, 100);
       
  2603     view.show();
       
  2604     view.setFocus();
       
  2605     QTRY_VERIFY(view.hasFocus());
       
  2606 
       
  2607     // open the popup by clicking. check if focus is on the popup
       
  2608     QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(25, 25));
       
  2609     QObject* webpopup = firstChildByClassName(&view, "QComboBox");
       
  2610     QComboBox* combo = qobject_cast<QComboBox*>(webpopup);
       
  2611     QVERIFY(combo != 0);
       
  2612     QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup
       
  2613 
       
  2614     // hide the popup and check if focus is on the page
       
  2615     combo->hidePopup();
       
  2616     QTRY_VERIFY(view.hasFocus() && !combo->view()->hasFocus()); // Focus should be back on the WebView
       
  2617 }
       
  2618 #endif
       
  2619 
       
  2620 void tst_QWebFrame::inputFieldFocus()
       
  2621 {
       
  2622     QWebView view;
       
  2623     view.setHtml("<html><body><input type=\"text\"></input></body></html>");
       
  2624     view.resize(400, 100);
       
  2625     view.show();
       
  2626     view.setFocus();
       
  2627     QTRY_VERIFY(view.hasFocus());
       
  2628 
       
  2629     // double the flashing time, should at least blink once already
       
  2630     int delay = qApp->cursorFlashTime() * 2;
       
  2631 
       
  2632     // focus the lineedit and check if it blinks
       
  2633     QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(25, 25));
       
  2634     m_inputFieldsTestView = &view;
       
  2635     view.installEventFilter( this );
       
  2636     QTest::qWait(delay);
       
  2637     QVERIFY2(m_inputFieldTestPaintCount >= 3,
       
  2638              "The input field should have a blinking caret");
       
  2639 }
       
  2640 
       
  2641 void tst_QWebFrame::hitTestContent()
       
  2642 {
       
  2643     QString html("<html><body><p>A paragraph</p><br/><br/><br/><a href=\"about:blank\" target=\"_foo\">link text</a></body></html>");
       
  2644 
       
  2645     QWebPage page;
       
  2646     QWebFrame* frame = page.mainFrame();
       
  2647     frame->setHtml(html);
       
  2648     page.setViewportSize(QSize(200, 0)); //no height so link is not visible
       
  2649     QWebHitTestResult result = frame->hitTestContent(QPoint(10, 100));
       
  2650     QCOMPARE(result.linkText(), QString("link text"));
       
  2651     QWebElement link = result.linkElement();
       
  2652     QCOMPARE(link.attribute("target"), QString("_foo"));
       
  2653 }
       
  2654 
       
  2655 void tst_QWebFrame::jsByteArray()
       
  2656 {
       
  2657     QByteArray ba("hello world");
       
  2658     m_myObject->setByteArrayProperty(ba);
       
  2659 
       
  2660     // read-only property
       
  2661     QCOMPARE(m_myObject->byteArrayProperty(), ba);
       
  2662     QString type;
       
  2663     QVariant v = evalJSV("myObject.byteArrayProperty");
       
  2664     QCOMPARE(int(v.type()), int(QVariant::ByteArray));
       
  2665 
       
  2666     QCOMPARE(v.toByteArray(), ba);
       
  2667 }
       
  2668 
       
  2669 void tst_QWebFrame::ownership()
       
  2670 {
       
  2671     // test ownership
       
  2672     {
       
  2673         QPointer<QObject> ptr = new QObject();
       
  2674         QVERIFY(ptr != 0);
       
  2675         {
       
  2676             QWebPage page;
       
  2677             QWebFrame* frame = page.mainFrame();
       
  2678             frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::ScriptOwnership);
       
  2679         }
       
  2680         QVERIFY(ptr == 0);
       
  2681     }
       
  2682     {
       
  2683         QPointer<QObject> ptr = new QObject();
       
  2684         QVERIFY(ptr != 0);
       
  2685         QObject* before = ptr;
       
  2686         {
       
  2687             QWebPage page;
       
  2688             QWebFrame* frame = page.mainFrame();
       
  2689             frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::QtOwnership);
       
  2690         }
       
  2691         QVERIFY(ptr == before);
       
  2692         delete ptr;
       
  2693     }
       
  2694     {
       
  2695         QObject* parent = new QObject();
       
  2696         QObject* child = new QObject(parent);
       
  2697         QWebPage page;
       
  2698         QWebFrame* frame = page.mainFrame();
       
  2699         frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership);
       
  2700         QVariant v = frame->evaluateJavaScript("test");
       
  2701         QCOMPARE(qvariant_cast<QObject*>(v), child);
       
  2702         delete parent;
       
  2703         v = frame->evaluateJavaScript("test");
       
  2704         QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0);
       
  2705     }
       
  2706     {
       
  2707         QPointer<QObject> ptr = new QObject();
       
  2708         QVERIFY(ptr != 0);
       
  2709         {
       
  2710             QWebPage page;
       
  2711             QWebFrame* frame = page.mainFrame();
       
  2712             frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::AutoOwnership);
       
  2713         }
       
  2714         // no parent, so it should be like ScriptOwnership
       
  2715         QVERIFY(ptr == 0);
       
  2716     }
       
  2717     {
       
  2718         QObject* parent = new QObject();
       
  2719         QPointer<QObject> child = new QObject(parent);
       
  2720         QVERIFY(child != 0);
       
  2721         {
       
  2722             QWebPage page;
       
  2723             QWebFrame* frame = page.mainFrame();
       
  2724             frame->addToJavaScriptWindowObject("test", child, QScriptEngine::AutoOwnership);
       
  2725         }
       
  2726         // has parent, so it should be like QtOwnership
       
  2727         QVERIFY(child != 0);
       
  2728         delete parent;
       
  2729     }
       
  2730 }
       
  2731 
       
  2732 void tst_QWebFrame::nullValue()
       
  2733 {
       
  2734     QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null");
       
  2735     QVERIFY(v.isNull());
       
  2736 }
       
  2737 
       
  2738 void tst_QWebFrame::baseUrl_data()
       
  2739 {
       
  2740     QTest::addColumn<QString>("html");
       
  2741     QTest::addColumn<QUrl>("loadUrl");
       
  2742     QTest::addColumn<QUrl>("url");
       
  2743     QTest::addColumn<QUrl>("baseUrl");
       
  2744 
       
  2745     QTest::newRow("null") << QString() << QUrl()
       
  2746                           << QUrl("about:blank") << QUrl("about:blank");
       
  2747 
       
  2748     QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/")
       
  2749                          << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/");
       
  2750 
       
  2751     QString html = "<html>"
       
  2752         "<head>"
       
  2753             "<base href=\"http://foobaz.bar/\" />"
       
  2754         "</head>"
       
  2755     "</html>";
       
  2756     QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/")
       
  2757                                    << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/");
       
  2758 }
       
  2759 
       
  2760 void tst_QWebFrame::baseUrl()
       
  2761 {
       
  2762     QFETCH(QString, html);
       
  2763     QFETCH(QUrl, loadUrl);
       
  2764     QFETCH(QUrl, url);
       
  2765     QFETCH(QUrl, baseUrl);
       
  2766 
       
  2767     m_page->mainFrame()->setHtml(html, loadUrl);
       
  2768     QCOMPARE(m_page->mainFrame()->url(), url);
       
  2769     QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl);
       
  2770 }
       
  2771 
       
  2772 void tst_QWebFrame::hasSetFocus()
       
  2773 {
       
  2774     QString html("<html><body><p>top</p>" \
       
  2775                     "<iframe width='80%' height='30%'/>" \
       
  2776                  "</body></html>");
       
  2777 
       
  2778     QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
       
  2779     m_page->mainFrame()->setHtml(html);
       
  2780 
       
  2781     waitForSignal(m_page->mainFrame(), SIGNAL(loadFinished(bool)), 200);
       
  2782     QCOMPARE(loadSpy.size(), 1);
       
  2783 
       
  2784     QList<QWebFrame*> children = m_page->mainFrame()->childFrames();
       
  2785     QWebFrame* frame = children.at(0);
       
  2786     QString innerHtml("<html><body><p>another iframe</p>" \
       
  2787                         "<iframe width='80%' height='30%'/>" \
       
  2788                       "</body></html>");
       
  2789     frame->setHtml(innerHtml);
       
  2790 
       
  2791     waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
       
  2792     QCOMPARE(loadSpy.size(), 2);
       
  2793 
       
  2794     m_page->mainFrame()->setFocus();
       
  2795     QTRY_VERIFY(m_page->mainFrame()->hasFocus());
       
  2796 
       
  2797     for (int i = 0; i < children.size(); ++i) {
       
  2798         children.at(i)->setFocus();
       
  2799         QTRY_VERIFY(children.at(i)->hasFocus());
       
  2800         QVERIFY(!m_page->mainFrame()->hasFocus());
       
  2801     }
       
  2802 
       
  2803     m_page->mainFrame()->setFocus();
       
  2804     QTRY_VERIFY(m_page->mainFrame()->hasFocus());
       
  2805 }
       
  2806 
       
  2807 void tst_QWebFrame::render()
       
  2808 {
       
  2809     QString html("<html>" \
       
  2810                     "<head><style>" \
       
  2811                        "body, iframe { margin: 0px; border: none; }" \
       
  2812                     "</style></head>" \
       
  2813                     "<body><iframe width='100px' height='100px'/></body>" \
       
  2814                  "</html>");
       
  2815 
       
  2816     QWebPage page;
       
  2817     page.mainFrame()->setHtml(html);
       
  2818 
       
  2819     QList<QWebFrame*> frames = page.mainFrame()->childFrames();
       
  2820     QWebFrame *frame = frames.at(0);
       
  2821     QString innerHtml("<body style='margin: 0px;'><img src='qrc:/image.png'/></body>");
       
  2822     frame->setHtml(innerHtml);
       
  2823 
       
  2824     QPicture picture;
       
  2825 
       
  2826     QSize size = page.mainFrame()->contentsSize();
       
  2827     page.setViewportSize(size);
       
  2828 
       
  2829     // render contents layer only (the iframe is smaller than the image, so it will have scrollbars)
       
  2830     QPainter painter1(&picture);
       
  2831     frame->render(&painter1, QWebFrame::ContentsLayer);
       
  2832     painter1.end();
       
  2833 
       
  2834     QCOMPARE(size.width(), picture.boundingRect().width() + frame->scrollBarGeometry(Qt::Vertical).width());
       
  2835     QCOMPARE(size.height(), picture.boundingRect().height() + frame->scrollBarGeometry(Qt::Horizontal).height());
       
  2836 
       
  2837     // render everything, should be the size of the iframe
       
  2838     QPainter painter2(&picture);
       
  2839     frame->render(&painter2, QWebFrame::AllLayers);
       
  2840     painter2.end();
       
  2841 
       
  2842     QCOMPARE(size.width(), picture.boundingRect().width());   // width: 100px
       
  2843     QCOMPARE(size.height(), picture.boundingRect().height()); // height: 100px
       
  2844 }
       
  2845 
       
  2846 void tst_QWebFrame::scrollPosition()
       
  2847 {
       
  2848     // enlarged image in a small viewport, to provoke the scrollbars to appear
       
  2849     QString html("<html><body><img src='qrc:/image.png' height=500 width=500/></body></html>");
       
  2850 
       
  2851     QWebPage page;
       
  2852     page.setViewportSize(QSize(200, 200));
       
  2853 
       
  2854     QWebFrame* frame = page.mainFrame();
       
  2855     frame->setHtml(html);
       
  2856     frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
       
  2857     frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
       
  2858 
       
  2859     // try to set the scroll offset programmatically
       
  2860     frame->setScrollPosition(QPoint(23, 29));
       
  2861     QCOMPARE(frame->scrollPosition().x(), 23);
       
  2862     QCOMPARE(frame->scrollPosition().y(), 29);
       
  2863 
       
  2864     int x = frame->evaluateJavaScript("window.scrollX").toInt();
       
  2865     int y = frame->evaluateJavaScript("window.scrollY").toInt();
       
  2866     QCOMPARE(x, 23);
       
  2867     QCOMPARE(y, 29);
       
  2868 }
       
  2869 
       
  2870 void tst_QWebFrame::scrollToAnchor()
       
  2871 {
       
  2872     QWebPage page;
       
  2873     page.setViewportSize(QSize(480, 800));
       
  2874     QWebFrame* frame = page.mainFrame();
       
  2875 
       
  2876     QString html("<html><body><p style=\"margin-bottom: 1500px;\">Hello.</p>"
       
  2877                  "<p><a id=\"foo\">This</a> is an anchor</p>"
       
  2878                  "<p style=\"margin-bottom: 1500px;\"><a id=\"bar\">This</a> is another anchor</p>"
       
  2879                  "</body></html>");
       
  2880     frame->setHtml(html);
       
  2881     frame->setScrollPosition(QPoint(0, 0));
       
  2882     QCOMPARE(frame->scrollPosition().x(), 0);
       
  2883     QCOMPARE(frame->scrollPosition().y(), 0);
       
  2884 
       
  2885     QWebElement fooAnchor = frame->findFirstElement("a[id=foo]");
       
  2886 
       
  2887     frame->scrollToAnchor("foo");
       
  2888     QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
       
  2889 
       
  2890     frame->scrollToAnchor("bar");
       
  2891     frame->scrollToAnchor("foo");
       
  2892     QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
       
  2893 
       
  2894     frame->scrollToAnchor("top");
       
  2895     QCOMPARE(frame->scrollPosition().y(), 0);
       
  2896 
       
  2897     frame->scrollToAnchor("bar");
       
  2898     frame->scrollToAnchor("notexist");
       
  2899     QVERIFY(frame->scrollPosition().y() != 0);
       
  2900 }
       
  2901 
       
  2902 
       
  2903 void tst_QWebFrame::scrollbarsOff()
       
  2904 {
       
  2905     QWebView view;
       
  2906     QWebFrame* mainFrame = view.page()->mainFrame();
       
  2907 
       
  2908     mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
       
  2909     mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
       
  2910 
       
  2911     QString html("<script>" \
       
  2912                  "   function checkScrollbar() {" \
       
  2913                  "       if (innerWidth === document.documentElement.offsetWidth)" \
       
  2914                  "           document.getElementById('span1').innerText = 'SUCCESS';" \
       
  2915                  "       else" \
       
  2916                  "           document.getElementById('span1').innerText = 'FAIL';" \
       
  2917                  "   }" \
       
  2918                  "</script>" \
       
  2919                  "<body>" \
       
  2920                  "   <div style='margin-top:1000px ; margin-left:1000px'>" \
       
  2921                  "       <a id='offscreen' href='a'>End</a>" \
       
  2922                  "   </div>" \
       
  2923                  "<span id='span1'></span>" \
       
  2924                  "</body>");
       
  2925 
       
  2926 
       
  2927     view.setHtml(html);
       
  2928     ::waitForSignal(&view, SIGNAL(loadFinished(bool)));
       
  2929 
       
  2930     mainFrame->evaluateJavaScript("checkScrollbar();");
       
  2931     QCOMPARE(mainFrame->documentElement().findAll("span").at(0).toPlainText(), QString("SUCCESS"));
       
  2932 }
       
  2933 
       
  2934 void tst_QWebFrame::evaluateWillCauseRepaint()
       
  2935 {
       
  2936     QWebView view;
       
  2937     QString html("<html><body>top<div id=\"junk\" style=\"display: block;\">"
       
  2938                     "junk</div>bottom</body></html>");
       
  2939     view.setHtml(html);
       
  2940     view.show();
       
  2941 
       
  2942 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
       
  2943     QTest::qWaitForWindowShown(&view);
       
  2944 #else
       
  2945     QTest::qWait(2000);
       
  2946 #endif
       
  2947 
       
  2948     view.page()->mainFrame()->evaluateJavaScript(
       
  2949         "document.getElementById('junk').style.display = 'none';");
       
  2950 
       
  2951     ::waitForSignal(view.page(), SIGNAL(repaintRequested(QRect)));
       
  2952 }
       
  2953 
       
  2954 class TestFactory : public QObject
       
  2955 {
       
  2956     Q_OBJECT
       
  2957 public:
       
  2958     TestFactory()
       
  2959         : obj(0), counter(0)
       
  2960     {}
       
  2961 
       
  2962     Q_INVOKABLE QObject* getNewObject()
       
  2963     {
       
  2964         delete obj;
       
  2965         obj = new QObject(this);
       
  2966         obj->setObjectName(QLatin1String("test") + QString::number(++counter));
       
  2967         return obj;
       
  2968 
       
  2969     }
       
  2970 
       
  2971     QObject* obj;
       
  2972     int counter;
       
  2973 };
       
  2974 
       
  2975 void tst_QWebFrame::qObjectWrapperWithSameIdentity()
       
  2976 {
       
  2977     m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>"
       
  2978                     "<body><span id='span1'>test</span></body>");
       
  2979 
       
  2980     QWebFrame* mainFrame = m_view->page()->mainFrame();
       
  2981     QCOMPARE(mainFrame->toPlainText(), QString("test"));
       
  2982 
       
  2983     mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership);
       
  2984 
       
  2985     mainFrame->evaluateJavaScript("triggerBug();");
       
  2986     QCOMPARE(mainFrame->toPlainText(), QString("test1"));
       
  2987 
       
  2988     mainFrame->evaluateJavaScript("triggerBug();");
       
  2989     QCOMPARE(mainFrame->toPlainText(), QString("test2"));
       
  2990 }
       
  2991 
       
  2992 void tst_QWebFrame::introspectQtMethods_data()
       
  2993 {
       
  2994     QTest::addColumn<QString>("objectExpression");
       
  2995     QTest::addColumn<QString>("methodName");
       
  2996     QTest::addColumn<QStringList>("expectedPropertyNames");
       
  2997 
       
  2998     QTest::newRow("myObject.mySignal")
       
  2999         << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name");
       
  3000     QTest::newRow("myObject.mySlot")
       
  3001         << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name");
       
  3002     QTest::newRow("myObject.myInvokable")
       
  3003         << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name");
       
  3004     QTest::newRow("myObject.mySignal.connect")
       
  3005         << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name");
       
  3006     QTest::newRow("myObject.mySignal.disconnect")
       
  3007         << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name");
       
  3008 }
       
  3009 
       
  3010 void tst_QWebFrame::introspectQtMethods()
       
  3011 {
       
  3012     QFETCH(QString, objectExpression);
       
  3013     QFETCH(QString, methodName);
       
  3014     QFETCH(QStringList, expectedPropertyNames);
       
  3015 
       
  3016     QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName);
       
  3017     QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames);
       
  3018 
       
  3019     for (int i = 0; i < expectedPropertyNames.size(); ++i) {
       
  3020         QString name = expectedPropertyNames.at(i);
       
  3021         QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue);
       
  3022         evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name));
       
  3023         QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object"));
       
  3024         QCOMPARE(evalJS("descriptor.get"), sUndefined);
       
  3025         QCOMPARE(evalJS("descriptor.set"), sUndefined);
       
  3026         QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
       
  3027         QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
       
  3028         QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse);
       
  3029     }
       
  3030 
       
  3031     QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty());
       
  3032 }
       
  3033 
       
  3034 QTEST_MAIN(tst_QWebFrame)
       
  3035 #include "tst_qwebframe.moc"