diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-01 22:05:29 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-01 22:05:29 +0200 |
commit | 0bb233d1f7c4317bb772d72cc3f92cbcdb4027de (patch) | |
tree | 47b40aab26fdaa15ec446b7d6de9bdf7efd7bbbb /Source/WebKit/qt/tests | |
parent | b1e9e47fa11f608ae16bc07f97a2acf95bf80272 (diff) |
Imported WebKit commit f2da9451cbccb8b7921d55483aa0bc656ff9cf53 (http://svn.webkit.org/repository/webkit/trunk@119269)
New snapshot that includes fix for using -Werror only in developer builds
Diffstat (limited to 'Source/WebKit/qt/tests')
4 files changed, 2209 insertions, 2285 deletions
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp index f9421e3cf..b1722a6fb 100644 --- a/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp +++ b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp @@ -477,30 +477,30 @@ void tst_QDeclarativeWebView::settings() QVERIFY(s); QStringList settingsList; - settingsList << QString::fromAscii("autoLoadImages") - << QString::fromAscii("developerExtrasEnabled") - << QString::fromAscii("javaEnabled") - << QString::fromAscii("javascriptCanAccessClipboard") - << QString::fromAscii("javascriptCanOpenWindows") - << QString::fromAscii("javascriptEnabled") - << QString::fromAscii("linksIncludedInFocusChain") - << QString::fromAscii("localContentCanAccessRemoteUrls") - << QString::fromAscii("localStorageDatabaseEnabled") - << QString::fromAscii("offlineStorageDatabaseEnabled") - << QString::fromAscii("offlineWebApplicationCacheEnabled") - << QString::fromAscii("pluginsEnabled") - << QString::fromAscii("printElementBackgrounds") - << QString::fromAscii("privateBrowsingEnabled") - << QString::fromAscii("zoomTextOnly"); + settingsList << QString::fromLatin1("autoLoadImages") + << QString::fromLatin1("developerExtrasEnabled") + << QString::fromLatin1("javaEnabled") + << QString::fromLatin1("javascriptCanAccessClipboard") + << QString::fromLatin1("javascriptCanOpenWindows") + << QString::fromLatin1("javascriptEnabled") + << QString::fromLatin1("linksIncludedInFocusChain") + << QString::fromLatin1("localContentCanAccessRemoteUrls") + << QString::fromLatin1("localStorageDatabaseEnabled") + << QString::fromLatin1("offlineStorageDatabaseEnabled") + << QString::fromLatin1("offlineWebApplicationCacheEnabled") + << QString::fromLatin1("pluginsEnabled") + << QString::fromLatin1("printElementBackgrounds") + << QString::fromLatin1("privateBrowsingEnabled") + << QString::fromLatin1("zoomTextOnly"); // Merely tests that setting gets stored (in QWebSettings), behavioural tests are in WebKit. for (int b = 0; b <= 1; b++) { bool value = !!b; foreach (const QString& name, settingsList) - s->setProperty(name.toAscii().data(), value); + s->setProperty(name.toLatin1().data(), value); for (int i = 0; i < 2; i++) { foreach (const QString& name, settingsList) - QCOMPARE(s->property(name.toAscii().data()).toBool(), value); + QCOMPARE(s->property(name.toLatin1().data()).toBool(), value); } } } diff --git a/Source/WebKit/qt/tests/qobjectbridge/qobjectbridge.pro b/Source/WebKit/qt/tests/qobjectbridge/qobjectbridge.pro new file mode 100644 index 000000000..f434ccbc1 --- /dev/null +++ b/Source/WebKit/qt/tests/qobjectbridge/qobjectbridge.pro @@ -0,0 +1,3 @@ +include(../tests.pri) +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc + diff --git a/Source/WebKit/qt/tests/qobjectbridge/tst_qobjectbridge.cpp b/Source/WebKit/qt/tests/qobjectbridge/tst_qobjectbridge.cpp new file mode 100644 index 000000000..32e8233ea --- /dev/null +++ b/Source/WebKit/qt/tests/qobjectbridge/tst_qobjectbridge.cpp @@ -0,0 +1,2189 @@ +/* + Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QtTest/QtTest> + +#include <qbrush.h> +#include <qwebelement.h> +#include <qwebframe.h> +#include <qwebpage.h> +#include <qwebview.h> + +struct CustomType { + QString string; +}; +Q_DECLARE_METATYPE(CustomType) + +Q_DECLARE_METATYPE(QBrush*) +Q_DECLARE_METATYPE(QObjectList) +Q_DECLARE_METATYPE(QList<int>) +Q_DECLARE_METATYPE(Qt::BrushStyle) +Q_DECLARE_METATYPE(QVariantList) +Q_DECLARE_METATYPE(QVariantMap) + +class MyQObject : public QObject { + Q_OBJECT + + Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) + Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty) + Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty) + Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty) + Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) + Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty) + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty) + Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty) + Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false) + Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty) + Q_PROPERTY(int readOnlyProperty READ readOnlyProperty) + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) + Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType) + Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty) + Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty) + Q_ENUMS(Policy Strategy) + Q_FLAGS(Ability) + +public: + enum Policy { + FooPolicy = 0, + BarPolicy, + BazPolicy + }; + + enum Strategy { + FooStrategy = 10, + BarStrategy, + BazStrategy + }; + + enum AbilityFlag { + NoAbility = 0x000, + FooAbility = 0x001, + BarAbility = 0x080, + BazAbility = 0x200, + AllAbility = FooAbility | BarAbility | BazAbility + }; + + Q_DECLARE_FLAGS(Ability, AbilityFlag) + + MyQObject(QObject* parent = 0) + : QObject(parent), + m_intValue(123), + m_variantValue(QLatin1String("foo")), + m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))), + m_stringValue(QLatin1String("bar")), + m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")), + m_brushValue(QColor(10, 20, 30, 40)), + m_hiddenValue(456.0), + m_writeOnlyValue(789), + m_readOnlyValue(987), + m_objectStar(0), + m_qtFunctionInvoked(-1) + { + m_variantMapValue.insert("a", QVariant(123)); + m_variantMapValue.insert("b", QVariant(QLatin1String("foo"))); + m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this)); + } + + ~MyQObject() { } + + int intProperty() const + { + return m_intValue; + } + void setIntProperty(int value) + { + m_intValue = value; + } + + QVariant variantProperty() const + { + return m_variantValue; + } + void setVariantProperty(const QVariant& value) + { + m_variantValue = value; + } + + QVariantList variantListProperty() const + { + return m_variantListValue; + } + void setVariantListProperty(const QVariantList& value) + { + m_variantListValue = value; + } + + QVariantMap variantMapProperty() const + { + return m_variantMapValue; + } + void setVariantMapProperty(const QVariantMap& value) + { + m_variantMapValue = value; + } + + QString stringProperty() const + { + return m_stringValue; + } + void setStringProperty(const QString& value) + { + m_stringValue = value; + } + + QStringList stringListProperty() const + { + return m_stringListValue; + } + void setStringListProperty(const QStringList& value) + { + m_stringListValue = value; + } + + QByteArray byteArrayProperty() const + { + return m_byteArrayValue; + } + void setByteArrayProperty(const QByteArray& value) + { + m_byteArrayValue = value; + } + + QBrush brushProperty() const + { + return m_brushValue; + } + void setBrushProperty(const QBrush& value) + { + m_brushValue = value; + } + + double hiddenProperty() const + { + return m_hiddenValue; + } + void setHiddenProperty(double value) + { + m_hiddenValue = value; + } + + int writeOnlyProperty() const + { + return m_writeOnlyValue; + } + void setWriteOnlyProperty(int value) + { + m_writeOnlyValue = value; + } + + int readOnlyProperty() const + { + return m_readOnlyValue; + } + + QKeySequence shortcut() const + { + return m_shortcut; + } + void setShortcut(const QKeySequence& seq) + { + m_shortcut = seq; + } + + QWebElement webElementProperty() const + { + return m_webElement; + } + void setWebElementProperty(const QWebElement& element) + { + m_webElement = element; + } + + CustomType propWithCustomType() const + { + return m_customType; + } + void setPropWithCustomType(const CustomType& c) + { + m_customType = c; + } + + QObject* objectStarProperty() const + { + return m_objectStar; + } + void setObjectStarProperty(QObject* object) + { + m_objectStar = object; + } + + + int qtFunctionInvoked() const + { + return m_qtFunctionInvoked; + } + + QVariantList qtFunctionActuals() const + { + return m_actuals; + } + + void resetQtFunctionInvoked() + { + m_qtFunctionInvoked = -1; + m_actuals.clear(); + } + + Q_INVOKABLE void myInvokable() + { + m_qtFunctionInvoked = 0; + } + Q_INVOKABLE void myInvokableWithIntArg(int arg) + { + m_qtFunctionInvoked = 1; + m_actuals << arg; + } + Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) + { + m_qtFunctionInvoked = 2; + m_actuals << arg; + } + Q_INVOKABLE void myInvokableWithFloatArg(float arg) + { + m_qtFunctionInvoked = 3; + m_actuals << arg; + } + Q_INVOKABLE void myInvokableWithDoubleArg(double arg) + { + m_qtFunctionInvoked = 4; + m_actuals << arg; + } + Q_INVOKABLE void myInvokableWithStringArg(const QString& arg) + { + m_qtFunctionInvoked = 5; + m_actuals << arg; + } + Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) + { + m_qtFunctionInvoked = 6; + m_actuals << arg1 << arg2; + } + Q_INVOKABLE int myInvokableReturningInt() + { + m_qtFunctionInvoked = 7; + return 123; + } + Q_INVOKABLE qlonglong myInvokableReturningLongLong() + { + m_qtFunctionInvoked = 39; + return 456; + } + Q_INVOKABLE QString myInvokableReturningString() + { + m_qtFunctionInvoked = 8; + return QLatin1String("ciao"); + } + Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // Overload. + { + m_qtFunctionInvoked = 9; + m_actuals << arg1 << arg2; + } + Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) + { + m_qtFunctionInvoked = 10; + m_actuals << policy; + } + Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) + { + m_qtFunctionInvoked = 36; + m_actuals << policy; + } + Q_INVOKABLE Policy myInvokableReturningEnum() + { + m_qtFunctionInvoked = 37; + return BazPolicy; + } + Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() + { + m_qtFunctionInvoked = 38; + return BazPolicy; + } + Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() + { + m_qtFunctionInvoked = 11; + return QVector<int>(); + } + Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int>&) + { + m_qtFunctionInvoked = 12; + } + Q_INVOKABLE QObject* myInvokableReturningQObjectStar() + { + m_qtFunctionInvoked = 13; + return this; + } + Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList& lst) + { + m_qtFunctionInvoked = 14; + m_actuals << QVariant::fromValue(lst); + return lst; + } + Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant& v) + { + m_qtFunctionInvoked = 15; + m_actuals << v; + return v; + } + Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap& vm) + { + m_qtFunctionInvoked = 16; + m_actuals << vm; + return vm; + } + Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int>& lst) + { + m_qtFunctionInvoked = 17; + m_actuals << QVariant::fromValue(lst); + return lst; + } + Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) + { + m_qtFunctionInvoked = 18; + m_actuals << QVariant::fromValue(obj); + return obj; + } + Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush& brush) + { + m_qtFunctionInvoked = 19; + m_actuals << QVariant::fromValue(brush); + return brush; + } + Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) + { + m_qtFunctionInvoked = 43; + m_actuals << QVariant::fromValue(style); + } + Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) + { + m_qtFunctionInvoked = 44; + m_actuals << QVariant::fromValue(arg); + } + Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) + { + m_qtFunctionInvoked = 45; + m_actuals << QVariant::fromValue(arg); + } + Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) + { + m_qtFunctionInvoked = 46; + m_actuals << QVariant::fromValue(arg); + } + Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString& arg2 = QString()) + { + m_qtFunctionInvoked = 47; + m_actuals << QVariant::fromValue(arg1) << qVariantFromValue(arg2); + } + Q_INVOKABLE QObject& myInvokableReturningRef() + { + m_qtFunctionInvoked = 48; + return *this; + } + Q_INVOKABLE const QObject& myInvokableReturningConstRef() const + { + const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49; + return *this; + } + Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) { + const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50; + m_actuals << QVariant::fromValue(arg); + } + Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) { + const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51; + m_actuals << QVariant::fromValue(arg); + } + Q_INVOKABLE void myInvokableWithBoolArg(bool arg) { + m_qtFunctionInvoked = 52; + m_actuals << arg; + } + + void emitMySignal() + { + emit mySignal(); + } + void emitMySignalWithIntArg(int arg) + { + emit mySignalWithIntArg(arg); + } + void emitMySignal2(bool arg) + { + emit mySignal2(arg); + } + void emitMySignal2() + { + emit mySignal2(); + } + void emitMySignalWithDateTimeArg(QDateTime dt) + { + emit mySignalWithDateTimeArg(dt); + } + void emitMySignalWithRegexArg(QRegExp r) + { + emit mySignalWithRegexArg(r); + } + +public Q_SLOTS: + void mySlot() + { + m_qtFunctionInvoked = 20; + } + + void mySlotWithIntArg(int arg) + { + m_qtFunctionInvoked = 21; + m_actuals << arg; + } + + void mySlotWithDoubleArg(double arg) + { + m_qtFunctionInvoked = 22; + m_actuals << arg; + } + + void mySlotWithStringArg(const QString &arg) + { + m_qtFunctionInvoked = 23; + m_actuals << arg; + } + + void myOverloadedSlot() + { + m_qtFunctionInvoked = 24; + } + + void myOverloadedSlot(QObject* arg) + { + m_qtFunctionInvoked = 41; + m_actuals << QVariant::fromValue(arg); + } + + void myOverloadedSlot(bool arg) + { + m_qtFunctionInvoked = 25; + m_actuals << arg; + } + + void myOverloadedSlot(const QStringList &arg) + { + m_qtFunctionInvoked = 42; + m_actuals << arg; + } + + void myOverloadedSlot(double arg) + { + m_qtFunctionInvoked = 26; + m_actuals << arg; + } + + void myOverloadedSlot(float arg) + { + m_qtFunctionInvoked = 27; + m_actuals << arg; + } + + void myOverloadedSlot(int arg) + { + m_qtFunctionInvoked = 28; + m_actuals << arg; + } + + void myOverloadedSlot(const QString &arg) + { + m_qtFunctionInvoked = 29; + m_actuals << arg; + } + + void myOverloadedSlot(const QColor &arg) + { + m_qtFunctionInvoked = 30; + m_actuals << arg; + } + + void myOverloadedSlot(const QBrush &arg) + { + m_qtFunctionInvoked = 31; + m_actuals << arg; + } + + void myOverloadedSlot(const QDateTime &arg) + { + m_qtFunctionInvoked = 32; + m_actuals << arg; + } + + void myOverloadedSlot(const QDate &arg) + { + m_qtFunctionInvoked = 33; + m_actuals << arg; + } + + void myOverloadedSlot(const QRegExp &arg) + { + m_qtFunctionInvoked = 34; + m_actuals << arg; + } + + void myOverloadedSlot(const QVariant &arg) + { + m_qtFunctionInvoked = 35; + m_actuals << arg; + } + + void myOverloadedSlot(const QWebElement &arg) + { + m_qtFunctionInvoked = 36; + m_actuals << QVariant::fromValue<QWebElement>(arg); + } + +protected Q_SLOTS: + void myProtectedSlot() + { + m_qtFunctionInvoked = 36; + } + +private Q_SLOTS: + void myPrivateSlot() { } + +Q_SIGNALS: + void mySignal(); + void mySignalWithIntArg(int); + void mySignalWithDoubleArg(double); + void mySignal2(bool arg = false); + void mySignalWithDateTimeArg(QDateTime); + void mySignalWithRegexArg(QRegExp); + +private: + int m_intValue; + QVariant m_variantValue; + QVariantList m_variantListValue; + QVariantMap m_variantMapValue; + QString m_stringValue; + QStringList m_stringListValue; + QByteArray m_byteArrayValue; + QBrush m_brushValue; + double m_hiddenValue; + int m_writeOnlyValue; + int m_readOnlyValue; + QKeySequence m_shortcut; + QWebElement m_webElement; + CustomType m_customType; + QObject* m_objectStar; + int m_qtFunctionInvoked; + QVariantList m_actuals; +}; + +class MyWebElementSlotOnlyObject : public QObject { + Q_OBJECT + Q_PROPERTY(QString tagName READ tagName) +public slots: + void doSomethingWithWebElement(const QWebElement& element) + { + m_tagName = element.tagName(); + } + +public: + QString tagName() const + { + return m_tagName; + } +private: + QString m_tagName; +}; + +class MyOtherQObject : public MyQObject { +public: + MyOtherQObject(QObject* parent = 0) + : MyQObject(parent) { } +}; + +class tst_QObjectBridge : public QObject { + Q_OBJECT + +public: + tst_QObjectBridge(); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetStaticProperty(); + void getSetDynamicProperty(); + void getSetChildren(); + void callQtInvokable(); + void connectAndDisconnect(); + void overrideInvokable(); + void overloadedSlots(); + void webElementSlotOnly(); + void enumerate_data(); + void enumerate(); + void objectDeleted(); + void typeConversion(); + void arrayObjectEnumerable(); + void domCycles(); + void jsByteArray(); + void ownership(); + void nullValue(); + void qObjectWrapperWithSameIdentity(); + void introspectQtMethods_data(); + void introspectQtMethods(); + +private: + QString evalJS(const QString& s) + { + // Convert an undefined return variant to the string "undefined" + QVariant ret = evalJSV(s); + if (ret.userType() == QMetaType::Void) + return "undefined"; + return ret.toString(); + } + + QVariant evalJSV(const QString& s) + { + return m_page->mainFrame()->evaluateJavaScript(s); + } + + QString evalJS(const QString& s, QString& type) + { + return evalJSV(s, type).toString(); + } + + QVariant evalJSV(const QString& s, QString& type) + { + // As a special measure, if we get an exception we set the type to 'error' + // (in ecma, an Error object has typeof object, but qtscript has a convenience function) + // Similarly, an array is an object, but we'd prefer to have a type of 'array' + // Also, consider a QMetaType::Void QVariant to be undefined + QString escaped = s; + escaped.replace('\'', "\\'"); // Don't preescape your single quotes! + QString code("var retvalue; " + "var typevalue; " + "try { " + " retvalue = eval('%1'); " + " typevalue = typeof retvalue; " + " if (retvalue instanceof Array) " + " typevalue = 'array'; " + "} catch(e) { " + " retvalue = e.name + ': ' + e.message; " + " typevalue = 'error'; " + "}"); + evalJS(code.arg(escaped)); + + QVariant ret = evalJSV("retvalue"); + if (ret.userType() != QMetaType::Void) + type = evalJS("typevalue"); + else { + ret = QString("undefined"); + type = sUndefined; + } + evalJS("delete retvalue; delete typevalue"); + return ret; + } + + const QString sTrue; + const QString sFalse; + const QString sUndefined; + const QString sArray; + const QString sFunction; + const QString sError; + const QString sString; + const QString sObject; + const QString sNumber; + +private: + QWebView* m_view; + QWebPage* m_page; + MyQObject* m_myObject; +}; + +tst_QObjectBridge::tst_QObjectBridge() + : sTrue("true") + , sFalse("false") + , sUndefined("undefined") + , sArray("array") + , sFunction("function") + , sError("error") + , sString("string") + , sObject("object") + , sNumber("number") +{ +} + +void tst_QObjectBridge::init() +{ + m_view = new QWebView(); + m_page = m_view->page(); + m_myObject = new MyQObject(); + m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject); +} + +void tst_QObjectBridge::cleanup() +{ + delete m_view; + delete m_myObject; +} + +void tst_QObjectBridge::getSetStaticProperty() +{ + m_page->mainFrame()->setHtml("<html><head><body></body></html>"); + QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined); + + // initial value (set in MyQObject constructor) + { + QString type; + QVariant ret = evalJSV("myObject.intProperty", type); + QCOMPARE(type, sNumber); + QCOMPARE(ret.type(), QVariant::Double); + QCOMPARE(ret.toInt(), 123); + } + QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue); + + { + QString type; + QVariant ret = evalJSV("myObject.variantProperty", type); + QCOMPARE(type, sString); + QCOMPARE(ret.type(), QVariant::String); + QCOMPARE(ret.toString(), QLatin1String("foo")); + } + QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue); + + { + QString type; + QVariant ret = evalJSV("myObject.stringProperty", type); + QCOMPARE(type, sString); + QCOMPARE(ret.type(), QVariant::String); + QCOMPARE(ret.toString(), QLatin1String("bar")); + } + QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue); + + { + QString type; + QVariant ret = evalJSV("myObject.variantListProperty", type); + QCOMPARE(type, sArray); + QCOMPARE(ret.type(), QVariant::List); + QVariantList vl = ret.value<QVariantList>(); + QCOMPARE(vl.size(), 2); + QCOMPARE(vl.at(0).toInt(), 123); + QCOMPARE(vl.at(1).toString(), QLatin1String("foo")); + } + QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue); + QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue); + QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue); + + { + QString type; + QVariant ret = evalJSV("myObject.variantMapProperty", type); + QCOMPARE(type, sObject); + QCOMPARE(ret.type(), QVariant::Map); + QVariantMap vm = ret.value<QVariantMap>(); + QCOMPARE(vm.size(), 3); + QCOMPARE(vm.value("a").toInt(), 123); + QCOMPARE(vm.value("b").toString(), QLatin1String("foo")); + QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject)); + } + QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue); + QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue); + QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue); + + { + QString type; + QVariant ret = evalJSV("myObject.stringListProperty", type); + QCOMPARE(type, sArray); + QCOMPARE(ret.type(), QVariant::List); + QVariantList vl = ret.value<QVariantList>(); + QCOMPARE(vl.size(), 2); + QCOMPARE(vl.at(0).toString(), QLatin1String("zig")); + QCOMPARE(vl.at(1).toString(), QLatin1String("zag")); + } + QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue); + QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString); + QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig")); + QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString); + QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag")); + + // property change in C++ should be reflected in script + m_myObject->setIntProperty(456); + QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue); + m_myObject->setIntProperty(789); + QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue); + + m_myObject->setVariantProperty(QLatin1String("bar")); + QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue); + m_myObject->setVariantProperty(42); + QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue); + m_myObject->setVariantProperty(QVariant::fromValue(QBrush())); + + m_myObject->setStringProperty(QLatin1String("baz")); + QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue); + m_myObject->setStringProperty(QLatin1String("zab")); + QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue); + + // property change in script should be reflected in C++ + QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123")); + QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue); + QCOMPARE(m_myObject->intProperty(), 123); + QCOMPARE(evalJS("myObject.intProperty = 'ciao!';" + "myObject.intProperty == 0"), sTrue); + QCOMPARE(m_myObject->intProperty(), 0); + QCOMPARE(evalJS("myObject.intProperty = '123';" + "myObject.intProperty == 123"), sTrue); + QCOMPARE(m_myObject->intProperty(), 123); + + QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao")); + QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao")); + QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao")); + QCOMPARE(evalJS("myObject.stringProperty = 123;" + "myObject.stringProperty"), QLatin1String("123")); + QCOMPARE(m_myObject->stringProperty(), QLatin1String("123")); + QCOMPARE(evalJS("myObject.stringProperty = null"), QString()); + QCOMPARE(evalJS("myObject.stringProperty"), QString()); + QCOMPARE(m_myObject->stringProperty(), QString()); + QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined); + QCOMPARE(evalJS("myObject.stringProperty"), QString()); + QCOMPARE(m_myObject->stringProperty(), QString()); + + QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);" + "myObject.variantProperty").toDouble(), 1234.0); + QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0); + + QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);" + "myObject.variantProperty"), sTrue); + QCOMPARE(m_myObject->variantProperty().toBool(), true); + + QCOMPARE(evalJS("myObject.variantProperty = null;" + "myObject.variantProperty.valueOf()"), sUndefined); + QCOMPARE(m_myObject->variantProperty(), QVariant()); + QCOMPARE(evalJS("myObject.variantProperty = undefined;" + "myObject.variantProperty.valueOf()"), sUndefined); + QCOMPARE(m_myObject->variantProperty(), QVariant()); + + QCOMPARE(evalJS("myObject.variantProperty = 'foo';" + "myObject.variantProperty.valueOf()"), QLatin1String("foo")); + QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo"))); + QCOMPARE(evalJS("myObject.variantProperty = 42;" + "myObject.variantProperty").toDouble(), 42.0); + QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0); + + QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];" + "myObject.variantListProperty.length == 3"), sTrue); + QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue); + QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two")); + QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue); + + QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];" + "myObject.stringListProperty.length == 3"), sTrue); + QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString); + QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue); + QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString); + QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two")); + QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString); + QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true")); + evalJS("myObject.webElementProperty=document.body;"); + QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY")); + + // try to delete + QCOMPARE(evalJS("delete myObject.intProperty"), sFalse); + QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue); + + QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse); + QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0); + + // custom property + QCOMPARE(evalJS("myObject.customProperty"), sUndefined); + QCOMPARE(evalJS("myObject.customProperty = 123;" + "myObject.customProperty == 123"), sTrue); + QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty"); + QCOMPARE(v.type(), QVariant::Double); + QCOMPARE(v.toInt(), 123); + + // non-scriptable property + QCOMPARE(m_myObject->hiddenProperty(), 456.0); + QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined); + QCOMPARE(evalJS("myObject.hiddenProperty = 123;" + "myObject.hiddenProperty == 123"), sTrue); + QCOMPARE(m_myObject->hiddenProperty(), 456.0); + + // write-only property + QCOMPARE(m_myObject->writeOnlyProperty(), 789); + QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined); + QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;" + "typeof myObject.writeOnlyProperty"), sUndefined); + QCOMPARE(m_myObject->writeOnlyProperty(), 123); + + // read-only property + QCOMPARE(m_myObject->readOnlyProperty(), 987); + QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue); + QCOMPARE(evalJS("myObject.readOnlyProperty = 654;" + "myObject.readOnlyProperty == 987"), sTrue); + QCOMPARE(m_myObject->readOnlyProperty(), 987); + + // QObject* property + m_myObject->setObjectStarProperty(0); + QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0); + QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue); + QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject); + QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse); + QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue); + QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"), + sUndefined); + m_myObject->setObjectStarProperty(this); + QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue); + QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject); + QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue); + QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue); +} + +void tst_QObjectBridge::getSetDynamicProperty() +{ + // initially the object does not have the property + // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty + + // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse); + QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); + + // add a dynamic property in C++ + QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); + // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue); + QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue); + QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue); + + // property change in script should be reflected in C++ + QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';" + "myObject.dynamicProperty"), QLatin1String("foo")); + QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo")); + + // delete the property (XFAIL - can't delete properties) + QEXPECT_FAIL("", "can't delete properties", Continue); + QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue); + /* + QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false); + QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); + // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse); + QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); + */ +} + +void tst_QObjectBridge::getSetChildren() +{ + // initially the object does not have the child + // (again, no hasOwnProperty) + + // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse); + QCOMPARE(evalJS("typeof myObject.child"), sUndefined); + + // add a child + MyQObject* child = new MyQObject(m_myObject); + child->setObjectName("child"); +// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue); + QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue); + + // add a grandchild + MyQObject* grandChild = new MyQObject(child); + grandChild->setObjectName("grandChild"); +// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue); + QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue); + + // delete grandchild + delete grandChild; +// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse); + QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue); + + // delete child + delete child; +// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse); + QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue); +} + +Q_DECLARE_METATYPE(QVector<int>) +Q_DECLARE_METATYPE(QVector<double>) +Q_DECLARE_METATYPE(QVector<QString>) + +void tst_QObjectBridge::callQtInvokable() +{ + qRegisterMetaType<QObjectList>(); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + // extra arguments should silently be ignored + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123)); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 3); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 4); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 4); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 52); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao")); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); + QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); + QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 6); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123")); + QCOMPARE(m_myObject->qtFunctionInvoked(), 7); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456")); + QCOMPARE(m_myObject->qtFunctionInvoked(), 39); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao")); + QCOMPARE(m_myObject->qtFunctionInvoked(), 8); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 9); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 44); + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)")); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type); + QCOMPARE(type, sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 47); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello")); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type); + QCOMPARE(type, sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 47); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString()); + } + + // calling function that returns (const)ref + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("typeof myObject.myInvokableReturningRef()"); + QCOMPARE(ret, sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 48); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()"); + QCOMPARE(ret, sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 49); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type); + QCOMPARE(m_myObject->qtFunctionInvoked(), 13); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); + QCOMPARE(type, sObject); + QCOMPARE(ret.userType(), int(QMetaType::QObjectStar)); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type); + QCOMPARE(m_myObject->qtFunctionInvoked(), 14); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(type, sArray); + QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList + QVariantList vl = qvariant_cast<QVariantList>(ret); + QCOMPARE(vl.count(), 1); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + m_myObject->setVariantProperty(QVariant(123)); + QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type); + QCOMPARE(type, sNumber); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty()); + QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int + QCOMPARE(ret.toInt(), 123); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type); + QCOMPARE(type, sObject); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); + QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid()); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type); + QCOMPARE(type, sObject); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); + QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid()); + } + + /* XFAIL - variant support + m_myObject->resetQtFunctionInvoked(); + { + m_myObject->setVariantProperty(QVariant::fromValue(QBrush())); + QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); + QVERIFY(ret.isVariant()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0)); + QCOMPARE(ret.toVariant(), m_myObject->variantProperty()); + } + */ + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type); + QCOMPARE(type, sNumber); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123)); + QCOMPARE(ret.userType(), int(QMetaType::Double)); + QCOMPARE(ret.toInt(), 123); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type); + QCOMPARE(m_myObject->qtFunctionInvoked(), 16); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QVariantMap)); + + QVariantMap vmap = qvariant_cast<QVariantMap>(v); + QCOMPARE(vmap.keys().size(), 2); + QCOMPARE(vmap.keys().at(0), QLatin1String("a")); + QCOMPARE(vmap.value("a"), QVariant(123)); + QCOMPARE(vmap.keys().at(1), QLatin1String("b")); + QCOMPARE(vmap.value("b"), QVariant("ciao")); + + QCOMPARE(type, sObject); + + QCOMPARE(ret.userType(), int(QMetaType::QVariantMap)); + vmap = qvariant_cast<QVariantMap>(ret); + QCOMPARE(vmap.keys().size(), 2); + QCOMPARE(vmap.keys().at(0), QLatin1String("a")); + QCOMPARE(vmap.value("a"), QVariant(123)); + QCOMPARE(vmap.keys().at(1), QLatin1String("b")); + QCOMPARE(vmap.value("b"), QVariant("ciao")); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type); + QCOMPARE(m_myObject->qtFunctionInvoked(), 17); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), qMetaTypeId<QList<int> >()); + QList<int> ilst = qvariant_cast<QList<int> >(v); + QCOMPARE(ilst.size(), 2); + QCOMPARE(ilst.at(0), 1); + QCOMPARE(ilst.at(1), 5); + + QCOMPARE(type, sArray); + QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist + QVariantList vlst = qvariant_cast<QVariantList>(ret); + QCOMPARE(vlst.size(), 2); + QCOMPARE(vlst.at(0).toInt(), 1); + QCOMPARE(vlst.at(1).toInt(), 5); + } + + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type); + QCOMPARE(m_myObject->qtFunctionInvoked(), 18); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); + QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject); + + QCOMPARE(ret.userType(), int(QMetaType::QObjectStar)); + QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject); + + QCOMPARE(type, sObject); + } + + m_myObject->resetQtFunctionInvoked(); + { + // no implicit conversion from integer to QObject* + QString type; + evalJS("myObject.myInvokableWithQObjectStarArg(123)", type); + QCOMPARE(type, sError); + } + + /* + m_myObject->resetQtFunctionInvoked(); + { + QString fun = evalJS("myObject.myInvokableWithQBrushArg"); + Q_ASSERT(fun.isFunction()); + QColor color(10, 20, 30, 40); + // QColor should be converted to a QBrush + QVariant ret = fun.call(QString(), QStringList() + << qScriptValueFromValue(m_engine, color)); + QCOMPARE(m_myObject->qtFunctionInvoked(), 19); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QBrush)); + QCOMPARE(qvariant_cast<QColor>(v), color); + + QCOMPARE(qscriptvalue_cast<QColor>(ret), color); + } + */ + + // private slots should not be part of the QObject binding + QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined); + + // protected slots should be fine + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myProtectedSlot()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 36); + + // call with too few arguments + { + QString type; + QString ret = evalJS("myObject.myInvokableWithIntArg()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)")); + } + + // call function where not all types have been registered + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } + + // call function with incompatible argument type + m_myObject->resetQtFunctionInvoked(); + { + QString type; + QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } +} + +void tst_QObjectBridge::connectAndDisconnect() +{ + // connect(function) + QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction); + QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction); + QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction); + + { + QString type; + evalJS("myObject.mySignal.connect(123)", type); + QCOMPARE(type, sError); + } + + evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }"); + + QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined); + + evalJS("gotSignal = false"); + evalJS("myObject.mySignal()"); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); + QCOMPARE(evalJS("signalSender"), evalJS("myObject")); + QCOMPARE(evalJS("slotThisObject == window"), sTrue); + + evalJS("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); + + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined); + + evalJS("gotSignal = false"); + m_myObject->emitMySignalWithIntArg(123); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); + QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue); + + QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined); + { + QString type; + evalJS("myObject.mySignal.disconnect(myHandler)", type); + QCOMPARE(type, sError); + } + + evalJS("gotSignal = false"); + QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined); + m_myObject->emitMySignal2(true); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); + QCOMPARE(evalJS("signalArgs[0]"), sTrue); + + QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined); + + QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction); + QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction); + QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction); + + QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined); + + evalJS("gotSignal = false"); + m_myObject->emitMySignal2(); + QCOMPARE(evalJS("gotSignal"), sTrue); + + QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined); + + // connect(object, function) + evalJS("otherObject = { name:'foo' }"); + QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined); + QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined); + evalJS("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(evalJS("gotSignal"), sFalse); + + { + QString type; + evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type); + QCOMPARE(type, sError); + } + + QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined); + evalJS("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); + QCOMPARE(evalJS("slotThisObject"), evalJS("otherObject")); + QCOMPARE(evalJS("signalSender"), evalJS("myObject")); + QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo")); + QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined); + + evalJS("yetAnotherObject = { name:'bar', func : function() { } }"); + QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined); + evalJS("gotSignal = false"); + m_myObject->emitMySignal2(true); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); + QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue); + QCOMPARE(evalJS("signalSender == myObject"), sTrue); + QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar")); + QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined); + + QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined); + evalJS("gotSignal = false"); + m_myObject->emitMySignal2(true); + QCOMPARE(evalJS("gotSignal"), sTrue); + QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); + QCOMPARE(evalJS("slotThisObject == myObject"), sTrue); + QCOMPARE(evalJS("signalSender == myObject"), sTrue); + QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined); + + // connect(obj, string) + QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined); + QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined); + QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined); + QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined); + + // check that emitting signals from script works + + // no arguments + QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignal()"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); + QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined); + + // one argument + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 21); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined); + + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 22); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0); + QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined); + + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 23); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); + QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined); + + // connecting to overloaded slot + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined); + + QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); + QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined); + + // erroneous input + { + // ### QtScript adds .connect to all functions, WebKit does only to signals/slots + QString type; + QString ret = evalJS("(function() { }).connect()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); + } + { + QString type; + QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); + } + + { + QString type; + QString ret = evalJS("(function() { }).connect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); + } + { + QString type; + QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); + } + + { + QString type; + QString ret = evalJS("myObject.myInvokable.connect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal")); + } + { + QString type; + QString ret = evalJS("myObject.myInvokable.connect(function() { })", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal")); + } + + { + QString type; + QString ret = evalJS("myObject.mySignal.connect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function")); + } + + { + QString type; + QString ret = evalJS("myObject.mySignal.disconnect()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given")); + } + { + QString type; + QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given")); + } + + /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots + { + QString type; + QString ret = evalJS("(function() { }).disconnect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal")); + } + */ + + { + QString type; + QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); + } + + { + QString type; + QString ret = evalJS("myObject.myInvokable.disconnect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); + } + { + QString type; + QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); + } + + { + QString type; + QString ret = evalJS("myObject.mySignal.disconnect(123)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function")); + } + + { + QString type; + QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()")); + } + + // when the wrapper dies, the connection stays alive + QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined); + m_myObject->resetQtFunctionInvoked(); + m_myObject->emitMySignal(); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); + evalJS("myObject = null"); + evalJS("gc()"); + m_myObject->resetQtFunctionInvoked(); + m_myObject->emitMySignal(); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); +} + +void tst_QObjectBridge::overrideInvokable() +{ + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + + /* XFAIL - can't write to functions with RuntimeObject + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myInvokable = function() { window.a = 123; }"); + evalJS("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + QCOMPARE(evalJS("window.a").toDouble(), 123.0); + + evalJS("myObject.myInvokable = function() { window.a = 456; }"); + evalJS("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + QCOMPARE(evalJS("window.a").toDouble(), 456.0); + */ + + evalJS("delete myObject.myInvokable"); + evalJS("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + + /* XFAIL - ditto + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg"); + evalJS("myObject.myInvokable(123)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + */ + + evalJS("delete myObject.myInvokable"); + m_myObject->resetQtFunctionInvoked(); + // this form (with the '()') is read-only + evalJS("myObject['myInvokable()'] = function() { window.a = 123; }"); + evalJS("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); +} + +void tst_QObjectBridge::overloadedSlots() +{ + // should pick myOverloadedSlot(double) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(10)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); + + // should pick myOverloadedSlot(double) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(10.0)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); + + // should pick myOverloadedSlot(QString) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot('10')"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 29); + + // should pick myOverloadedSlot(bool) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(true)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 25); + + // should pick myOverloadedSlot(QDateTime) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(new Date())"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 32); + + // should pick myOverloadedSlot(QRegExp) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(new RegExp())"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 34); + + // should pick myOverloadedSlot(QVariant) + /* XFAIL + m_myObject->resetQtFunctionInvoked(); + QString f = evalJS("myObject.myOverloadedSlot"); + f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao"))); + QCOMPARE(m_myObject->qtFunctionInvoked(), 35); + */ + + // Should pick myOverloadedSlot(QWebElement). + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(document.body)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 36); + + // should pick myOverloadedSlot(QObject*) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(myObject)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 41); + + // should pick myOverloadedSlot(QObject*) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(null)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 41); + + // should pick myOverloadedSlot(QStringList) + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(['hello'])"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 42); +} + +class MyEnumTestQObject : public QObject { + Q_OBJECT + Q_PROPERTY(QString p1 READ p1) + Q_PROPERTY(QString p2 READ p2) + Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false) + Q_PROPERTY(QString p4 READ p4) + Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false) + Q_PROPERTY(QString p6 READ p6) +public: + MyEnumTestQObject(QObject* parent = 0) + : QObject(parent) { } + + QString p1() const { return QLatin1String("p1"); } + QString p2() const { return QLatin1String("p2"); } + QString p3() const { return QLatin1String("p3"); } + QString p4() const { return QLatin1String("p4"); } + QString p5() const { return QLatin1String("p5"); } + QString p6() const { return QLatin1String("p6"); } + +public Q_SLOTS: + void mySlot() { } + void myOtherSlot() { } +Q_SIGNALS: + void mySignal(); +}; + +void tst_QObjectBridge::enumerate_data() +{ + QTest::addColumn<QStringList>("expectedNames"); + + QTest::newRow("enumerate all") + << (QStringList() + // meta-object-defined properties: + // inherited + << "objectName" + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // inherited signals and slots + << "destroyed(QObject*)" << "destroyed()" +#if defined(HAVE_QT5) && HAVE_QT5 + << "objectNameChanged(QString)" +#endif + << "deleteLater()" + // not included because it's private: + // << "_q_reregisterTimers(void*)" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); +} + +void tst_QObjectBridge::enumerate() +{ + QFETCH(QStringList, expectedNames); + + MyEnumTestQObject enumQObject; + // give it some dynamic properties + enumQObject.setProperty("dp1", "dp1"); + enumQObject.setProperty("dp2", "dp2"); + enumQObject.setProperty("dp3", "dp3"); + m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject); + + // enumerate in script + { + evalJS("var enumeratedProperties = []"); + evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }"); + QStringList result = evalJSV("enumeratedProperties").toStringList(); + QCOMPARE(result.size(), expectedNames.size()); + for (int i = 0; i < expectedNames.size(); ++i) + QCOMPARE(result.at(i), expectedNames.at(i)); + } +} + +void tst_QObjectBridge::objectDeleted() +{ + MyQObject* qobj = new MyQObject(); + m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj); + evalJS("bar.objectName = 'foo';"); + QCOMPARE(qobj->objectName(), QLatin1String("foo")); + evalJS("bar.intProperty = 123;"); + QCOMPARE(qobj->intProperty(), 123); + qobj->resetQtFunctionInvoked(); + evalJS("bar.myInvokable.call(bar);"); + QCOMPARE(qobj->qtFunctionInvoked(), 0); + + // do this, to ensure that we cache that it implements call + evalJS("bar()"); + + // now delete the object + delete qobj; + + QCOMPARE(evalJS("typeof bar"), sObject); + + // any attempt to access properties of the object should result in an exception + { + QString type; + QString ret = evalJS("bar.objectName", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + { + QString type; + QString ret = evalJS("bar.objectName = 'foo'", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + + // myInvokable is stored in member table (since we've accessed it before deletion) + { + QString type; + evalJS("bar.myInvokable", type); + QCOMPARE(type, sFunction); + } + + { + QString type; + QString ret = evalJS("bar.myInvokable.call(bar);", type); + ret = evalJS("bar.myInvokable(bar)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject")); + } + // myInvokableWithIntArg is not stored in member table (since we've not accessed it) + { + QString type; + QString ret = evalJS("bar.myInvokableWithIntArg", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); + } + + // access from script + evalJS("window.o = bar;"); + { + QString type; + QString ret = evalJS("o.objectName", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + { + QString type; + QString ret = evalJS("o.myInvokable()", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject")); + } + { + QString type; + QString ret = evalJS("o.myInvokableWithIntArg(10)", type); + QCOMPARE(type, sError); + QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); + } +} + +void tst_QObjectBridge::typeConversion() +{ + m_myObject->resetQtFunctionInvoked(); + + QDateTime localdt(QDate(2008, 1, 18), QTime(12, 31, 0)); + QDateTime utclocaldt = localdt.toUTC(); + QDateTime utcdt(QDate(2008, 1, 18), QTime(12, 31, 0), Qt::UTC); + + // Dates in JS (default to local) + evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 32); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt); + + m_myObject->resetQtFunctionInvoked(); + evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 32); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt); + + // Pushing QDateTimes into JS + // Local + evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}"); + evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)"); + m_myObject->emitMySignalWithDateTimeArg(localdt); + QCOMPARE(evalJS("window.__date_equals"), sTrue); + evalJS("delete window.__date_equals"); + m_myObject->emitMySignalWithDateTimeArg(utclocaldt); + QCOMPARE(evalJS("window.__date_equals"), sTrue); + evalJS("delete window.__date_equals"); + evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;"); + + // UTC + evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }"); + evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)"); + m_myObject->emitMySignalWithDateTimeArg(utcdt); + QCOMPARE(evalJS("window.__date_equals"), sTrue); + evalJS("delete window.__date_equals"); + evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;"); + + // ### RegExps +} + +class StringListTestObject : public QObject { + Q_OBJECT +public Q_SLOTS: + QVariant stringList() + { + return QStringList() << "Q" << "t"; + }; +}; + +void tst_QObjectBridge::arrayObjectEnumerable() +{ + QWebPage page; + QWebFrame* frame = page.mainFrame(); + QObject* qobject = new StringListTestObject(); + frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership); + + const QString script("var stringArray = test.stringList();" + "var result = '';" + "for (var i in stringArray) {" + " result += stringArray[i];" + "}" + "result;"); + QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt")); +} + +void tst_QObjectBridge::domCycles() +{ + m_view->setHtml("<html><body>"); + QVariant v = m_page->mainFrame()->evaluateJavaScript("document"); + QVERIFY(v.type() == QVariant::Map); +} + +void tst_QObjectBridge::jsByteArray() +{ + QByteArray ba("hello world"); + m_myObject->setByteArrayProperty(ba); + + // read-only property + QCOMPARE(m_myObject->byteArrayProperty(), ba); + QString type; + QVariant v = evalJSV("myObject.byteArrayProperty"); + QCOMPARE(int(v.type()), int(QVariant::ByteArray)); + + QCOMPARE(v.toByteArray(), ba); +} + +void tst_QObjectBridge::ownership() +{ + // test ownership + { + QWeakPointer<QObject> ptr = new QObject(); + QVERIFY(ptr); + { + QWebPage page; + QWebFrame* frame = page.mainFrame(); + frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::ScriptOwnership); + } + QVERIFY(!ptr); + } + { + QWeakPointer<QObject> ptr = new QObject(); + QVERIFY(ptr); + QObject* before = ptr.data(); + { + QWebPage page; + QWebFrame* frame = page.mainFrame(); + frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::QtOwnership); + } + QVERIFY(ptr.data() == before); + delete ptr.data(); + } + { + QObject* parent = new QObject(); + QObject* child = new QObject(parent); + QWebPage page; + QWebFrame* frame = page.mainFrame(); + frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership); + QVariant v = frame->evaluateJavaScript("test"); + QCOMPARE(qvariant_cast<QObject*>(v), child); + delete parent; + v = frame->evaluateJavaScript("test"); + QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0); + } + { + QWeakPointer<QObject> ptr = new QObject(); + QVERIFY(ptr); + { + QWebPage page; + QWebFrame* frame = page.mainFrame(); + frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::AutoOwnership); + } + // no parent, so it should be like ScriptOwnership + QVERIFY(!ptr); + } + { + QObject* parent = new QObject(); + QWeakPointer<QObject> child = new QObject(parent); + QVERIFY(child); + { + QWebPage page; + QWebFrame* frame = page.mainFrame(); + frame->addToJavaScriptWindowObject("test", child.data(), QScriptEngine::AutoOwnership); + } + // has parent, so it should be like QtOwnership + QVERIFY(child); + delete parent; + } +} + +void tst_QObjectBridge::nullValue() +{ + QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null"); + QVERIFY(v.isNull()); +} + +class TestFactory : public QObject { + Q_OBJECT +public: + TestFactory() + : obj(0), counter(0) + { } + + Q_INVOKABLE QObject* getNewObject() + { + delete obj; + obj = new QObject(this); + obj->setObjectName(QLatin1String("test") + QString::number(++counter)); + return obj; + + } + + QObject* obj; + int counter; +}; + +void tst_QObjectBridge::qObjectWrapperWithSameIdentity() +{ + m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>" + "<body><span id='span1'>test</span></body>"); + + QWebFrame* mainFrame = m_view->page()->mainFrame(); + QCOMPARE(mainFrame->toPlainText(), QString("test")); + + mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership); + + mainFrame->evaluateJavaScript("triggerBug();"); + QCOMPARE(mainFrame->toPlainText(), QString("test1")); + + mainFrame->evaluateJavaScript("triggerBug();"); + QCOMPARE(mainFrame->toPlainText(), QString("test2")); +} + +void tst_QObjectBridge::introspectQtMethods_data() +{ + QTest::addColumn<QString>("objectExpression"); + QTest::addColumn<QString>("methodName"); + QTest::addColumn<QStringList>("expectedPropertyNames"); + + QTest::newRow("myObject.mySignal") + << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name"); + QTest::newRow("myObject.mySlot") + << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name"); + QTest::newRow("myObject.myInvokable") + << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name"); + QTest::newRow("myObject.mySignal.connect") + << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name"); + QTest::newRow("myObject.mySignal.disconnect") + << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name"); +} + +void tst_QObjectBridge::introspectQtMethods() +{ + QFETCH(QString, objectExpression); + QFETCH(QString, methodName); + QFETCH(QStringList, expectedPropertyNames); + + QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName); + QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames); + + for (int i = 0; i < expectedPropertyNames.size(); ++i) { + QString name = expectedPropertyNames.at(i); + QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue); + evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name)); + QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object")); + QCOMPARE(evalJS("descriptor.get"), sUndefined); + QCOMPARE(evalJS("descriptor.set"), sUndefined); + QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue); + QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse); + QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse); + } + + QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty()); +} + +void tst_QObjectBridge::webElementSlotOnly() +{ + MyWebElementSlotOnlyObject object; + m_page->mainFrame()->setHtml("<html><head><body></body></html>"); + m_page->mainFrame()->addToJavaScriptWindowObject("myWebElementSlotObject", &object); + evalJS("myWebElementSlotObject.doSomethingWithWebElement(document.body)"); + QCOMPARE(evalJS("myWebElementSlotObject.tagName"), QString("BODY")); +} + +QTEST_MAIN(tst_QObjectBridge) +#include "tst_qobjectbridge.moc" diff --git a/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp index 3d8a2b3ce..31d87b75a 100644 --- a/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp +++ b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp @@ -22,7 +22,6 @@ #include <qwebpage.h> #include <qwebelement.h> -#include <qwidget.h> #include <qwebview.h> #include <qwebframe.h> #include <qwebhistory.h> @@ -40,549 +39,11 @@ #endif #include "../util.h" -struct CustomType { - QString string; -}; -Q_DECLARE_METATYPE(CustomType) - -Q_DECLARE_METATYPE(QBrush*) -Q_DECLARE_METATYPE(QObjectList) -Q_DECLARE_METATYPE(QList<int>) -Q_DECLARE_METATYPE(Qt::BrushStyle) -Q_DECLARE_METATYPE(QVariantList) -Q_DECLARE_METATYPE(QVariantMap) - -class MyQObject : public QObject -{ - Q_OBJECT - - Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) - Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty) - Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty) - Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty) - Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) - Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty) - Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty) - Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty) - Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false) - Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty) - Q_PROPERTY(int readOnlyProperty READ readOnlyProperty) - Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) - Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType) - Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty) - Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty) - Q_ENUMS(Policy Strategy) - Q_FLAGS(Ability) - -public: - enum Policy { - FooPolicy = 0, - BarPolicy, - BazPolicy - }; - - enum Strategy { - FooStrategy = 10, - BarStrategy, - BazStrategy - }; - - enum AbilityFlag { - NoAbility = 0x000, - FooAbility = 0x001, - BarAbility = 0x080, - BazAbility = 0x200, - AllAbility = FooAbility | BarAbility | BazAbility - }; - - Q_DECLARE_FLAGS(Ability, AbilityFlag) - - MyQObject(QObject* parent = 0) - : QObject(parent), - m_intValue(123), - m_variantValue(QLatin1String("foo")), - m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))), - m_stringValue(QLatin1String("bar")), - m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")), - m_brushValue(QColor(10, 20, 30, 40)), - m_hiddenValue(456.0), - m_writeOnlyValue(789), - m_readOnlyValue(987), - m_objectStar(0), - m_qtFunctionInvoked(-1) - { - m_variantMapValue.insert("a", QVariant(123)); - m_variantMapValue.insert("b", QVariant(QLatin1String("foo"))); - m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this)); - } - - ~MyQObject() { } - - int intProperty() const { - return m_intValue; - } - void setIntProperty(int value) { - m_intValue = value; - } - - QVariant variantProperty() const { - return m_variantValue; - } - void setVariantProperty(const QVariant &value) { - m_variantValue = value; - } - - QVariantList variantListProperty() const { - return m_variantListValue; - } - void setVariantListProperty(const QVariantList &value) { - m_variantListValue = value; - } - - QVariantMap variantMapProperty() const { - return m_variantMapValue; - } - void setVariantMapProperty(const QVariantMap &value) { - m_variantMapValue = value; - } - - QString stringProperty() const { - return m_stringValue; - } - void setStringProperty(const QString &value) { - m_stringValue = value; - } - - QStringList stringListProperty() const { - return m_stringListValue; - } - void setStringListProperty(const QStringList &value) { - m_stringListValue = value; - } - - QByteArray byteArrayProperty() const { - return m_byteArrayValue; - } - void setByteArrayProperty(const QByteArray &value) { - m_byteArrayValue = value; - } - - QBrush brushProperty() const { - return m_brushValue; - } - Q_INVOKABLE void setBrushProperty(const QBrush &value) { - m_brushValue = value; - } - - double hiddenProperty() const { - return m_hiddenValue; - } - void setHiddenProperty(double value) { - m_hiddenValue = value; - } - - int writeOnlyProperty() const { - return m_writeOnlyValue; - } - void setWriteOnlyProperty(int value) { - m_writeOnlyValue = value; - } - - int readOnlyProperty() const { - return m_readOnlyValue; - } - - QKeySequence shortcut() const { - return m_shortcut; - } - void setShortcut(const QKeySequence &seq) { - m_shortcut = seq; - } - - QWebElement webElementProperty() const { - return m_webElement; - } - - void setWebElementProperty(const QWebElement& element) { - m_webElement = element; - } - - CustomType propWithCustomType() const { - return m_customType; - } - void setPropWithCustomType(const CustomType &c) { - m_customType = c; - } - - QObject* objectStarProperty() const { - return m_objectStar; - } - - void setObjectStarProperty(QObject* object) { - m_objectStar = object; - } - - - int qtFunctionInvoked() const { - return m_qtFunctionInvoked; - } - - QVariantList qtFunctionActuals() const { - return m_actuals; - } - - void resetQtFunctionInvoked() { - m_qtFunctionInvoked = -1; - m_actuals.clear(); - } - - Q_INVOKABLE void myInvokable() { - m_qtFunctionInvoked = 0; - } - Q_INVOKABLE void myInvokableWithIntArg(int arg) { - m_qtFunctionInvoked = 1; - m_actuals << arg; - } - Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) { - m_qtFunctionInvoked = 2; - m_actuals << arg; - } - Q_INVOKABLE void myInvokableWithFloatArg(float arg) { - m_qtFunctionInvoked = 3; - m_actuals << arg; - } - Q_INVOKABLE void myInvokableWithDoubleArg(double arg) { - m_qtFunctionInvoked = 4; - m_actuals << arg; - } - Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) { - m_qtFunctionInvoked = 5; - m_actuals << arg; - } - Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) { - m_qtFunctionInvoked = 6; - m_actuals << arg1 << arg2; - } - Q_INVOKABLE int myInvokableReturningInt() { - m_qtFunctionInvoked = 7; - return 123; - } - Q_INVOKABLE qlonglong myInvokableReturningLongLong() { - m_qtFunctionInvoked = 39; - return 456; - } - Q_INVOKABLE QString myInvokableReturningString() { - m_qtFunctionInvoked = 8; - return QLatin1String("ciao"); - } - Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload - m_qtFunctionInvoked = 9; - m_actuals << arg1 << arg2; - } - Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) { - m_qtFunctionInvoked = 10; - m_actuals << policy; - } - Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) { - m_qtFunctionInvoked = 36; - m_actuals << policy; - } - Q_INVOKABLE Policy myInvokableReturningEnum() { - m_qtFunctionInvoked = 37; - return BazPolicy; - } - Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() { - m_qtFunctionInvoked = 38; - return BazPolicy; - } - Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() { - m_qtFunctionInvoked = 11; - return QVector<int>(); - } - Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) { - m_qtFunctionInvoked = 12; - } - Q_INVOKABLE QObject* myInvokableReturningQObjectStar() { - m_qtFunctionInvoked = 13; - return this; - } - Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) { - m_qtFunctionInvoked = 14; - m_actuals << QVariant::fromValue(lst); - return lst; - } - Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) { - m_qtFunctionInvoked = 15; - m_actuals << v; - return v; - } - Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) { - m_qtFunctionInvoked = 16; - m_actuals << vm; - return vm; - } - Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) { - m_qtFunctionInvoked = 17; - m_actuals << QVariant::fromValue(lst); - return lst; - } - Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) { - m_qtFunctionInvoked = 18; - m_actuals << QVariant::fromValue(obj); - return obj; - } - Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) { - m_qtFunctionInvoked = 19; - m_actuals << QVariant::fromValue(brush); - return brush; - } - Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) { - m_qtFunctionInvoked = 43; - m_actuals << QVariant::fromValue(style); - } - Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) { - m_qtFunctionInvoked = 44; - m_actuals << QVariant::fromValue(arg); - } - Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) { - m_qtFunctionInvoked = 45; - m_actuals << QVariant::fromValue(arg); - } - Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) { - m_qtFunctionInvoked = 46; - m_actuals << QVariant::fromValue(arg); - } - Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") { - m_qtFunctionInvoked = 47; - m_actuals << QVariant::fromValue(arg1) << qVariantFromValue(arg2); - } - Q_INVOKABLE QObject& myInvokableReturningRef() { - m_qtFunctionInvoked = 48; - return *this; - } - Q_INVOKABLE const QObject& myInvokableReturningConstRef() const { - const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49; - return *this; - } - Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) { - const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50; - m_actuals << QVariant::fromValue(arg); - } - Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) { - const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51; - m_actuals << QVariant::fromValue(arg); - } - Q_INVOKABLE void myInvokableWithBoolArg(bool arg) { - m_qtFunctionInvoked = 52; - m_actuals << arg; - } - - void emitMySignal() { - emit mySignal(); - } - void emitMySignalWithIntArg(int arg) { - emit mySignalWithIntArg(arg); - } - void emitMySignal2(bool arg) { - emit mySignal2(arg); - } - void emitMySignal2() { - emit mySignal2(); - } - void emitMySignalWithDateTimeArg(QDateTime dt) { - emit mySignalWithDateTimeArg(dt); - } - void emitMySignalWithRegexArg(QRegExp r) { - emit mySignalWithRegexArg(r); - } - -public Q_SLOTS: - void mySlot() { - m_qtFunctionInvoked = 20; - } - void mySlotWithIntArg(int arg) { - m_qtFunctionInvoked = 21; - m_actuals << arg; - } - void mySlotWithDoubleArg(double arg) { - m_qtFunctionInvoked = 22; - m_actuals << arg; - } - void mySlotWithStringArg(const QString &arg) { - m_qtFunctionInvoked = 23; - m_actuals << arg; - } - - void myOverloadedSlot() { - m_qtFunctionInvoked = 24; - } - void myOverloadedSlot(QObject* arg) { - m_qtFunctionInvoked = 41; - m_actuals << QVariant::fromValue(arg); - } - void myOverloadedSlot(bool arg) { - m_qtFunctionInvoked = 25; - m_actuals << arg; - } - void myOverloadedSlot(const QStringList &arg) { - m_qtFunctionInvoked = 42; - m_actuals << arg; - } - void myOverloadedSlot(double arg) { - m_qtFunctionInvoked = 26; - m_actuals << arg; - } - void myOverloadedSlot(float arg) { - m_qtFunctionInvoked = 27; - m_actuals << arg; - } - void myOverloadedSlot(int arg) { - m_qtFunctionInvoked = 28; - m_actuals << arg; - } - void myOverloadedSlot(const QString &arg) { - m_qtFunctionInvoked = 29; - m_actuals << arg; - } - void myOverloadedSlot(const QColor &arg) { - m_qtFunctionInvoked = 30; - m_actuals << arg; - } - void myOverloadedSlot(const QBrush &arg) { - m_qtFunctionInvoked = 31; - m_actuals << arg; - } - void myOverloadedSlot(const QDateTime &arg) { - m_qtFunctionInvoked = 32; - m_actuals << arg; - } - void myOverloadedSlot(const QDate &arg) { - m_qtFunctionInvoked = 33; - m_actuals << arg; - } - void myOverloadedSlot(const QRegExp &arg) { - m_qtFunctionInvoked = 34; - m_actuals << arg; - } - void myOverloadedSlot(const QVariant &arg) { - m_qtFunctionInvoked = 35; - m_actuals << arg; - } - void myOverloadedSlot(const QWebElement &arg) { - m_qtFunctionInvoked = 36; - m_actuals << QVariant::fromValue<QWebElement>(arg); - } - - void qscript_call(int arg) { - m_qtFunctionInvoked = 40; - m_actuals << arg; - } - -protected Q_SLOTS: - void myProtectedSlot() { - m_qtFunctionInvoked = 36; - } - -private Q_SLOTS: - void myPrivateSlot() { } - -Q_SIGNALS: - void mySignal(); - void mySignalWithIntArg(int arg); - void mySignalWithDoubleArg(double arg); - void mySignal2(bool arg = false); - void mySignalWithDateTimeArg(QDateTime dt); - void mySignalWithRegexArg(QRegExp r); - -private: - int m_intValue; - QVariant m_variantValue; - QVariantList m_variantListValue; - QVariantMap m_variantMapValue; - QString m_stringValue; - QStringList m_stringListValue; - QByteArray m_byteArrayValue; - QBrush m_brushValue; - double m_hiddenValue; - int m_writeOnlyValue; - int m_readOnlyValue; - QKeySequence m_shortcut; - QWebElement m_webElement; - CustomType m_customType; - QObject* m_objectStar; - int m_qtFunctionInvoked; - QVariantList m_actuals; -}; - -class MyWebElementSlotOnlyObject : public QObject { - Q_OBJECT - Q_PROPERTY(QString tagName READ tagName) -public slots: - void doSomethingWithWebElement(const QWebElement& element) - { - m_tagName = element.tagName(); - } - -public: - QString tagName() const - { - return m_tagName; - } -private: - QString m_tagName; -}; - -class MyOtherQObject : public MyQObject -{ -public: - MyOtherQObject(QObject* parent = 0) - : MyQObject(parent) { } -}; - -class MyEnumTestQObject : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString p1 READ p1) - Q_PROPERTY(QString p2 READ p2) - Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false) - Q_PROPERTY(QString p4 READ p4) - Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false) - Q_PROPERTY(QString p6 READ p6) -public: - MyEnumTestQObject(QObject* parent = 0) - : QObject(parent) { } - QString p1() const { - return QLatin1String("p1"); - } - QString p2() const { - return QLatin1String("p2"); - } - QString p3() const { - return QLatin1String("p3"); - } - QString p4() const { - return QLatin1String("p4"); - } - QString p5() const { - return QLatin1String("p5"); - } - QString p6() const { - return QLatin1String("p5"); - } -public Q_SLOTS: - void mySlot() { } - void myOtherSlot() { } -Q_SIGNALS: - void mySignal(); -}; - class tst_QWebFrame : public QObject { Q_OBJECT public: - tst_QWebFrame(); - virtual ~tst_QWebFrame(); bool eventFilter(QObject* watched, QEvent* event); public slots: @@ -591,28 +52,9 @@ public slots: private slots: void horizontalScrollAfterBack(); - void getSetStaticProperty(); - void getSetDynamicProperty(); - void getSetChildren(); - void callQtInvokable(); - void connectAndDisconnect(); - void classEnums(); - void classConstructor(); - void overrideInvokable(); - void transferInvokable(); - void findChild(); - void findChildren(); - void overloadedSlots(); - void webElementSlotOnly(); - void enumerate_data(); - void enumerate(); - void objectDeleted(); - void typeConversion(); - void arrayObjectEnumerable(); void symmetricUrl(); void progressSignal(); void urlChange(); - void domCycles(); void requestedUrl(); void requestedUrlAfterSetAndLoadFailures(); void javaScriptWindowObjectCleared_data(); @@ -630,9 +72,6 @@ private slots: #endif void inputFieldFocus(); void hitTestContent(); - void jsByteArray(); - void ownership(); - void nullValue(); void baseUrl_data(); void baseUrl(); void hasSetFocus(); @@ -642,9 +81,6 @@ private slots: void scrollToAnchor(); void scrollbarsOff(); void evaluateWillCauseRepaint(); - void qObjectWrapperWithSameIdentity(); - void introspectQtMethods_data(); - void introspectQtMethods(); void setContent_data(); void setContent(); void setCacheLoadControlAttribute(); @@ -662,80 +98,12 @@ private slots: void loadInSignalHandlers(); private: - QString evalJS(const QString&s) { - // Convert an undefined return variant to the string "undefined" - QVariant ret = evalJSV(s); - if (ret.userType() == QMetaType::Void) - return "undefined"; - else - return ret.toString(); - } - QVariant evalJSV(const QString &s) { - return m_page->mainFrame()->evaluateJavaScript(s); - } - - QString evalJS(const QString&s, QString& type) { - return evalJSV(s, type).toString(); - } - QVariant evalJSV(const QString &s, QString& type) { - // As a special measure, if we get an exception we set the type to 'error' - // (in ecma, an Error object has typeof object, but qtscript has a convenience function) - // Similarly, an array is an object, but we'd prefer to have a type of 'array' - // Also, consider a QMetaType::Void QVariant to be undefined - QString escaped = s; - escaped.replace('\'', "\\'"); // Don't preescape your single quotes! - QString code("var retvalue; " - "var typevalue; " - "try { " - " retvalue = eval('%1'); " - " typevalue = typeof retvalue; " - " if (retvalue instanceof Array) " - " typevalue = 'array'; " - "} catch(e) { " - " retvalue = e.name + ': ' + e.message; " - " typevalue = 'error'; " - "}"); - evalJS(code.arg(escaped)); - - QVariant ret = evalJSV("retvalue"); - if (ret.userType() != QMetaType::Void) - type = evalJS("typevalue"); - else { - ret = QString("undefined"); - type = sUndefined; - } - evalJS("delete retvalue; delete typevalue"); - return ret; - } - - const QString sTrue; - const QString sFalse; - const QString sUndefined; - const QString sArray; - const QString sFunction; - const QString sError; - const QString sString; - const QString sObject; - const QString sNumber; - -private: QWebView* m_view; QWebPage* m_page; - MyQObject* m_myObject; QWebView* m_inputFieldsTestView; int m_inputFieldTestPaintCount; }; -tst_QWebFrame::tst_QWebFrame() - : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"), - sString("string"), sObject("object"), sNumber("number"), m_inputFieldsTestView(0), m_inputFieldTestPaintCount(0) -{ -} - -tst_QWebFrame::~tst_QWebFrame() -{ -} - bool tst_QWebFrame::eventFilter(QObject* watched, QEvent* event) { // used on the inputFieldFocus test @@ -750,1467 +118,11 @@ void tst_QWebFrame::init() { m_view = new QWebView(); m_page = m_view->page(); - m_myObject = new MyQObject(); - m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject); } void tst_QWebFrame::cleanup() { delete m_view; - delete m_myObject; -} - -void tst_QWebFrame::getSetStaticProperty() -{ - m_page->mainFrame()->setHtml("<html><head><body></body></html>"); - QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined); - - // initial value (set in MyQObject constructor) - { - QString type; - QVariant ret = evalJSV("myObject.intProperty", type); - QCOMPARE(type, sNumber); - QCOMPARE(ret.type(), QVariant::Double); - QCOMPARE(ret.toInt(), 123); - } - QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue); - - { - QString type; - QVariant ret = evalJSV("myObject.variantProperty", type); - QCOMPARE(type, sString); - QCOMPARE(ret.type(), QVariant::String); - QCOMPARE(ret.toString(), QLatin1String("foo")); - } - QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue); - - { - QString type; - QVariant ret = evalJSV("myObject.stringProperty", type); - QCOMPARE(type, sString); - QCOMPARE(ret.type(), QVariant::String); - QCOMPARE(ret.toString(), QLatin1String("bar")); - } - QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue); - - { - QString type; - QVariant ret = evalJSV("myObject.variantListProperty", type); - QCOMPARE(type, sArray); - QCOMPARE(ret.type(), QVariant::List); - QVariantList vl = ret.value<QVariantList>(); - QCOMPARE(vl.size(), 2); - QCOMPARE(vl.at(0).toInt(), 123); - QCOMPARE(vl.at(1).toString(), QLatin1String("foo")); - } - QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue); - QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue); - QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue); - - { - QString type; - QVariant ret = evalJSV("myObject.variantMapProperty", type); - QCOMPARE(type, sObject); - QCOMPARE(ret.type(), QVariant::Map); - QVariantMap vm = ret.value<QVariantMap>(); - QCOMPARE(vm.size(), 3); - QCOMPARE(vm.value("a").toInt(), 123); - QCOMPARE(vm.value("b").toString(), QLatin1String("foo")); - QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject)); - } - QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue); - QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue); - QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue); - - { - QString type; - QVariant ret = evalJSV("myObject.stringListProperty", type); - QCOMPARE(type, sArray); - QCOMPARE(ret.type(), QVariant::List); - QVariantList vl = ret.value<QVariantList>(); - QCOMPARE(vl.size(), 2); - QCOMPARE(vl.at(0).toString(), QLatin1String("zig")); - QCOMPARE(vl.at(1).toString(), QLatin1String("zag")); - } - QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue); - QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString); - QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig")); - QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString); - QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag")); - - // property change in C++ should be reflected in script - m_myObject->setIntProperty(456); - QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue); - m_myObject->setIntProperty(789); - QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue); - - m_myObject->setVariantProperty(QLatin1String("bar")); - QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue); - m_myObject->setVariantProperty(42); - QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue); - m_myObject->setVariantProperty(QVariant::fromValue(QBrush())); -//XFAIL -// QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant); - - m_myObject->setStringProperty(QLatin1String("baz")); - QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue); - m_myObject->setStringProperty(QLatin1String("zab")); - QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue); - - // property change in script should be reflected in C++ - QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123")); - QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue); - QCOMPARE(m_myObject->intProperty(), 123); - QCOMPARE(evalJS("myObject.intProperty = 'ciao!';" - "myObject.intProperty == 0"), sTrue); - QCOMPARE(m_myObject->intProperty(), 0); - QCOMPARE(evalJS("myObject.intProperty = '123';" - "myObject.intProperty == 123"), sTrue); - QCOMPARE(m_myObject->intProperty(), 123); - - QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao")); - QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao")); - QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao")); - QCOMPARE(evalJS("myObject.stringProperty = 123;" - "myObject.stringProperty"), QLatin1String("123")); - QCOMPARE(m_myObject->stringProperty(), QLatin1String("123")); - QCOMPARE(evalJS("myObject.stringProperty = null"), QString()); - QCOMPARE(evalJS("myObject.stringProperty"), QString()); - QCOMPARE(m_myObject->stringProperty(), QString()); - QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined); - QCOMPARE(evalJS("myObject.stringProperty"), QString()); - QCOMPARE(m_myObject->stringProperty(), QString()); - - QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);" - "myObject.variantProperty").toDouble(), 1234.0); - QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0); - - QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);" - "myObject.variantProperty"), sTrue); - QCOMPARE(m_myObject->variantProperty().toBool(), true); - - QCOMPARE(evalJS("myObject.variantProperty = null;" - "myObject.variantProperty.valueOf()"), sUndefined); - QCOMPARE(m_myObject->variantProperty(), QVariant()); - QCOMPARE(evalJS("myObject.variantProperty = undefined;" - "myObject.variantProperty.valueOf()"), sUndefined); - QCOMPARE(m_myObject->variantProperty(), QVariant()); - - QCOMPARE(evalJS("myObject.variantProperty = 'foo';" - "myObject.variantProperty.valueOf()"), QLatin1String("foo")); - QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo"))); - QCOMPARE(evalJS("myObject.variantProperty = 42;" - "myObject.variantProperty").toDouble(), 42.0); - QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0); - - QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];" - "myObject.variantListProperty.length == 3"), sTrue); - QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue); - QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two")); - QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue); - - QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];" - "myObject.stringListProperty.length == 3"), sTrue); - QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString); - QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue); - QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString); - QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two")); - QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString); - QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true")); - evalJS("myObject.webElementProperty=document.body;"); - QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY")); - - // try to delete - QCOMPARE(evalJS("delete myObject.intProperty"), sFalse); - QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue); - - QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse); - QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0); - - // custom property - QCOMPARE(evalJS("myObject.customProperty"), sUndefined); - QCOMPARE(evalJS("myObject.customProperty = 123;" - "myObject.customProperty == 123"), sTrue); - QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty"); - QCOMPARE(v.type(), QVariant::Double); - QCOMPARE(v.toInt(), 123); - - // non-scriptable property - QCOMPARE(m_myObject->hiddenProperty(), 456.0); - QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined); - QCOMPARE(evalJS("myObject.hiddenProperty = 123;" - "myObject.hiddenProperty == 123"), sTrue); - QCOMPARE(m_myObject->hiddenProperty(), 456.0); - - // write-only property - QCOMPARE(m_myObject->writeOnlyProperty(), 789); - QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined); - QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;" - "typeof myObject.writeOnlyProperty"), sUndefined); - QCOMPARE(m_myObject->writeOnlyProperty(), 123); - - // read-only property - QCOMPARE(m_myObject->readOnlyProperty(), 987); - QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue); - QCOMPARE(evalJS("myObject.readOnlyProperty = 654;" - "myObject.readOnlyProperty == 987"), sTrue); - QCOMPARE(m_myObject->readOnlyProperty(), 987); - - // QObject* property - m_myObject->setObjectStarProperty(0); - QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0); - QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue); - QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject); - QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse); - QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue); - QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"), - sUndefined); - m_myObject->setObjectStarProperty(this); - QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue); - QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject); - QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue); - QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue); -} - -void tst_QWebFrame::getSetDynamicProperty() -{ - // initially the object does not have the property - // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty - - //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse); - QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); - - // add a dynamic property in C++ - QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); - //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue); - QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue); - QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue); - - // property change in script should be reflected in C++ - QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';" - "myObject.dynamicProperty"), QLatin1String("foo")); - QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo")); - - // delete the property (XFAIL - can't delete properties) - QEXPECT_FAIL("", "can't delete properties", Continue); - QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue); - /* - QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false); - QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); - // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse); - QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined); - */ -} - -void tst_QWebFrame::getSetChildren() -{ - // initially the object does not have the child - // (again, no hasOwnProperty) - - //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse); - QCOMPARE(evalJS("typeof myObject.child"), sUndefined); - - // add a child - MyQObject* child = new MyQObject(m_myObject); - child->setObjectName("child"); -// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue); - QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue); - - // add a grandchild - MyQObject* grandChild = new MyQObject(child); - grandChild->setObjectName("grandChild"); -// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue); - QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue); - - // delete grandchild - delete grandChild; -// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse); - QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue); - - // delete child - delete child; -// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse); - QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue); -} - -Q_DECLARE_METATYPE(QVector<int>) -Q_DECLARE_METATYPE(QVector<double>) -Q_DECLARE_METATYPE(QVector<QString>) - -void tst_QWebFrame::callQtInvokable() -{ - qRegisterMetaType<QObjectList>(); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - // extra arguments should silently be ignored - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123)); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 3); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 4); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 4); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 52); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao")); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); - QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); - QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 6); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123")); - QCOMPARE(m_myObject->qtFunctionInvoked(), 7); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456")); - QCOMPARE(m_myObject->qtFunctionInvoked(), 39); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao")); - QCOMPARE(m_myObject->qtFunctionInvoked(), 8); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 9); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 44); - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)")); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type); - QCOMPARE(type, sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 47); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello")); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type); - QCOMPARE(type, sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 47); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString()); - } - - // calling function that returns (const)ref - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("typeof myObject.myInvokableReturningRef()"); - QCOMPARE(ret, sUndefined); - //QVERIFY(!m_engine->hasUncaughtException()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 48); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()"); - QCOMPARE(ret, sUndefined); - //QVERIFY(!m_engine->hasUncaughtException()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 49); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type); - QCOMPARE(m_myObject->qtFunctionInvoked(), 13); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(type, sObject); - QCOMPARE(ret.userType(), int(QMetaType::QObjectStar)); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type); - QCOMPARE(m_myObject->qtFunctionInvoked(), 14); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(type, sArray); - QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList - QVariantList vl = qvariant_cast<QVariantList>(ret); - QCOMPARE(vl.count(), 1); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - m_myObject->setVariantProperty(QVariant(123)); - QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type); - QCOMPARE(type, sNumber); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty()); - QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int - QCOMPARE(ret.toInt(),123); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type); - QCOMPARE(type, sObject); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); - QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid()); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type); - QCOMPARE(type, sObject); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); - QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid()); - } - - /* XFAIL - variant support - m_myObject->resetQtFunctionInvoked(); - { - m_myObject->setVariantProperty(QVariant::fromValue(QBrush())); - QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); - QVERIFY(ret.isVariant()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0)); - QCOMPARE(ret.toVariant(), m_myObject->variantProperty()); - } - */ - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type); - QCOMPARE(type, sNumber); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123)); - QCOMPARE(ret.userType(), int(QMetaType::Double)); - QCOMPARE(ret.toInt(),123); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type); - QCOMPARE(m_myObject->qtFunctionInvoked(), 16); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QVariantMap)); - - QVariantMap vmap = qvariant_cast<QVariantMap>(v); - QCOMPARE(vmap.keys().size(), 2); - QCOMPARE(vmap.keys().at(0), QLatin1String("a")); - QCOMPARE(vmap.value("a"), QVariant(123)); - QCOMPARE(vmap.keys().at(1), QLatin1String("b")); - QCOMPARE(vmap.value("b"), QVariant("ciao")); - - QCOMPARE(type, sObject); - - QCOMPARE(ret.userType(), int(QMetaType::QVariantMap)); - vmap = qvariant_cast<QVariantMap>(ret); - QCOMPARE(vmap.keys().size(), 2); - QCOMPARE(vmap.keys().at(0), QLatin1String("a")); - QCOMPARE(vmap.value("a"), QVariant(123)); - QCOMPARE(vmap.keys().at(1), QLatin1String("b")); - QCOMPARE(vmap.value("b"), QVariant("ciao")); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type); - QCOMPARE(m_myObject->qtFunctionInvoked(), 17); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), qMetaTypeId<QList<int> >()); - QList<int> ilst = qvariant_cast<QList<int> >(v); - QCOMPARE(ilst.size(), 2); - QCOMPARE(ilst.at(0), 1); - QCOMPARE(ilst.at(1), 5); - - QCOMPARE(type, sArray); - QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist - QVariantList vlst = qvariant_cast<QVariantList>(ret); - QCOMPARE(vlst.size(), 2); - QCOMPARE(vlst.at(0).toInt(), 1); - QCOMPARE(vlst.at(1).toInt(), 5); - } - - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type); - QCOMPARE(m_myObject->qtFunctionInvoked(), 18); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); - QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject); - - QCOMPARE(ret.userType(), int(QMetaType::QObjectStar)); - QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject); - - QCOMPARE(type, sObject); - } - - m_myObject->resetQtFunctionInvoked(); - { - // no implicit conversion from integer to QObject* - QString type; - evalJS("myObject.myInvokableWithQObjectStarArg(123)", type); - QCOMPARE(type, sError); - } - - /* - m_myObject->resetQtFunctionInvoked(); - { - QString fun = evalJS("myObject.myInvokableWithQBrushArg"); - Q_ASSERT(fun.isFunction()); - QColor color(10, 20, 30, 40); - // QColor should be converted to a QBrush - QVariant ret = fun.call(QString(), QStringList() - << qScriptValueFromValue(m_engine, color)); - QCOMPARE(m_myObject->qtFunctionInvoked(), 19); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QBrush)); - QCOMPARE(qvariant_cast<QColor>(v), color); - - QCOMPARE(qscriptvalue_cast<QColor>(ret), color); - } - */ - - // private slots should not be part of the QObject binding - QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined); - - // protected slots should be fine - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myProtectedSlot()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 36); - - // call with too few arguments - { - QString type; - QString ret = evalJS("myObject.myInvokableWithIntArg()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)")); - } - - // call function where not all types have been registered - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } - - // call function with incompatible argument type - m_myObject->resetQtFunctionInvoked(); - { - QString type; - QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } -} - -void tst_QWebFrame::connectAndDisconnect() -{ - // connect(function) - QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction); - QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction); - QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction); - - { - QString type; - evalJS("myObject.mySignal.connect(123)", type); - QCOMPARE(type, sError); - } - - evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }"); - - QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined); - - evalJS("gotSignal = false"); - evalJS("myObject.mySignal()"); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); - QCOMPARE(evalJS("signalSender"),evalJS("myObject")); - QCOMPARE(evalJS("slotThisObject == window"), sTrue); - - evalJS("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); - - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined); - - evalJS("gotSignal = false"); - m_myObject->emitMySignalWithIntArg(123); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); - QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue); - - QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined); - { - QString type; - evalJS("myObject.mySignal.disconnect(myHandler)", type); - QCOMPARE(type, sError); - } - - evalJS("gotSignal = false"); - QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined); - m_myObject->emitMySignal2(true); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); - QCOMPARE(evalJS("signalArgs[0]"), sTrue); - - QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined); - - QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction); - QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction); - QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction); - - QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined); - - evalJS("gotSignal = false"); - m_myObject->emitMySignal2(); - QCOMPARE(evalJS("gotSignal"), sTrue); - - QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined); - - // connect(object, function) - evalJS("otherObject = { name:'foo' }"); - QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined); - QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined); - evalJS("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(evalJS("gotSignal"), sFalse); - - { - QString type; - evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type); - QCOMPARE(type, sError); - } - - QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined); - evalJS("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 0"), sTrue); - QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject")); - QCOMPARE(evalJS("signalSender"),evalJS("myObject")); - QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo")); - QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined); - - evalJS("yetAnotherObject = { name:'bar', func : function() { } }"); - QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined); - evalJS("gotSignal = false"); - m_myObject->emitMySignal2(true); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); - QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue); - QCOMPARE(evalJS("signalSender == myObject"), sTrue); - QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar")); - QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined); - - QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined); - evalJS("gotSignal = false"); - m_myObject->emitMySignal2(true); - QCOMPARE(evalJS("gotSignal"), sTrue); - QCOMPARE(evalJS("signalArgs.length == 1"), sTrue); - QCOMPARE(evalJS("slotThisObject == myObject"), sTrue); - QCOMPARE(evalJS("signalSender == myObject"), sTrue); - QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined); - - // connect(obj, string) - QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined); - QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined); - QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined); - QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined); - - // check that emitting signals from script works - - // no arguments - QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignal()"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); - QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined); - - // one argument - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 21); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined); - - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 22); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0); - QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined); - - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 23); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); - QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined); - - // connecting to overloaded slot - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined); - - QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); - QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined); - - // erroneous input - { - // ### QtScript adds .connect to all functions, WebKit does only to signals/slots - QString type; - QString ret = evalJS("(function() { }).connect()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); - } - { - QString type; - QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); - } - - { - QString type; - QString ret = evalJS("(function() { }).connect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); - } - { - QString type; - QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function")); - } - - { - QString type; - QString ret = evalJS("myObject.myInvokable.connect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal")); - } - { - QString type; - QString ret = evalJS("myObject.myInvokable.connect(function() { })", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal")); - } - - { - QString type; - QString ret = evalJS("myObject.mySignal.connect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function")); - } - - { - QString type; - QString ret = evalJS("myObject.mySignal.disconnect()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given")); - } - { - QString type; - QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given")); - } - - /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots - { - QString type; - QString ret = evalJS("(function() { }).disconnect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal")); - } - */ - - { - QString type; - QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); - } - - { - QString type; - QString ret = evalJS("myObject.myInvokable.disconnect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); - } - { - QString type; - QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal")); - } - - { - QString type; - QString ret = evalJS("myObject.mySignal.disconnect(123)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function")); - } - - { - QString type; - QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()")); - } - - // when the wrapper dies, the connection stays alive - QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined); - m_myObject->resetQtFunctionInvoked(); - m_myObject->emitMySignal(); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); - evalJS("myObject = null"); - evalJS("gc()"); - m_myObject->resetQtFunctionInvoked(); - m_myObject->emitMySignal(); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); -} - -void tst_QWebFrame::classEnums() -{ - // We don't do the meta thing currently, unfortunately!!! - /* - QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue()); - m_engine->globalObject().setProperty("MyQObject", myClass); - - QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()), - MyQObject::FooPolicy); - QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()), - MyQObject::BarPolicy); - QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()), - MyQObject::BazPolicy); - - QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()), - MyQObject::FooStrategy); - QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()), - MyQObject::BarStrategy); - QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()), - MyQObject::BazStrategy); - - QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()), - MyQObject::NoAbility); - QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()), - MyQObject::FooAbility); - QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()), - MyQObject::BarAbility); - QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()), - MyQObject::BazAbility); - QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()), - MyQObject::AllAbility); - - // enums from Qt are inherited through prototype - QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()), - Qt::StrongFocus); - QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()), - Qt::Key_Left); - - QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject")); - - qRegisterMetaType<MyQObject::Policy>("Policy"); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 10); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 36); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); - - m_myObject->resetQtFunctionInvoked(); - { - QVariant ret = evalJS("myObject.myInvokableReturningEnum()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 37); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(ret.isVariant()); - } - m_myObject->resetQtFunctionInvoked(); - { - QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 38); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(ret.isNumber()); - } - */ -} - -void tst_QWebFrame::classConstructor() -{ - /* - QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine); - m_engine->globalObject().setProperty("MyQObject", myClass); - - QString myObj = evalJS("myObj = MyQObject()"); - QObject* qobj = myObj.toQObject(); - QVERIFY(qobj != 0); - QCOMPARE(qobj->metaObject()->className(), "MyQObject"); - QCOMPARE(qobj->parent(), (QObject*)0); - - QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine); - m_engine->globalObject().setProperty("QObject", qobjectClass); - - QString otherObj = evalJS("otherObj = QObject(myObj)"); - QObject* qqobj = otherObj.toQObject(); - QVERIFY(qqobj != 0); - QCOMPARE(qqobj->metaObject()->className(), "QObject"); - QCOMPARE(qqobj->parent(), qobj); - - delete qobj; - */ -} - -void tst_QWebFrame::overrideInvokable() -{ - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - - /* XFAIL - can't write to functions with RuntimeObject - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myInvokable = function() { window.a = 123; }"); - evalJS("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - QCOMPARE(evalJS("window.a").toDouble(), 123.0); - - evalJS("myObject.myInvokable = function() { window.a = 456; }"); - evalJS("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - QCOMPARE(evalJS("window.a").toDouble(), 456.0); - */ - - evalJS("delete myObject.myInvokable"); - evalJS("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - - /* XFAIL - ditto - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg"); - evalJS("myObject.myInvokable(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - */ - - evalJS("delete myObject.myInvokable"); - m_myObject->resetQtFunctionInvoked(); - // this form (with the '()') is read-only - evalJS("myObject['myInvokable()'] = function() { window.a = 123; }"); - evalJS("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); -} - -void tst_QWebFrame::transferInvokable() -{ - /* XFAIL - can't put to functions with RuntimeObject - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.foozball = myObject.myInvokable"); - evalJS("myObject.foozball()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.foozball = myObject.myInvokableWithIntArg"); - evalJS("myObject.foozball(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg"); - evalJS("myObject.myInvokable(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - - MyOtherQObject other; - m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other); - evalJS("myOtherObject.foo = myObject.foozball"); - other.resetQtFunctionInvoked(); - evalJS("myOtherObject.foo(456)"); - QCOMPARE(other.qtFunctionInvoked(), 1); - */ -} - -void tst_QWebFrame::findChild() -{ - /* - QObject* child = new QObject(m_myObject); - child->setObjectName(QLatin1String("myChildObject")); - - { - QString result = evalJS("myObject.findChild('noSuchChild')"); - QCOMPARE(result.isNull()); - } - - { - QString result = evalJS("myObject.findChild('myChildObject')"); - QCOMPARE(result.isQObject()); - QCOMPARE(result.toQObject(), child); - } - - delete child; - */ -} - -void tst_QWebFrame::findChildren() -{ - /* - QObject* child = new QObject(m_myObject); - child->setObjectName(QLatin1String("myChildObject")); - - { - QString result = evalJS("myObject.findChildren('noSuchChild')"); - QCOMPARE(result.isArray()); - QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0); - } - - { - QString result = evalJS("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray()); - QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); - } - - QObject* namelessChild = new QObject(m_myObject); - - { - QString result = evalJS("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray()); - QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); - } - - QObject* anotherChild = new QObject(m_myObject); - anotherChild->setObjectName(QLatin1String("anotherChildObject")); - - { - QString result = evalJS("myObject.findChildren('anotherChildObject')"); - QCOMPARE(result.isArray()); - QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild); - } - - anotherChild->setObjectName(QLatin1String("myChildObject")); - { - QString result = evalJS("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray()); - QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0); - QObject* o1 = result.property(QLatin1String("0")).toQObject(); - QObject* o2 = result.property(QLatin1String("1")).toQObject(); - if (o1 != child) { - QCOMPARE(o1, anotherChild); - QCOMPARE(o2, child); - } else { - QCOMPARE(o1, child); - QCOMPARE(o2, anotherChild); - } - } - - // find all - { - QString result = evalJS("myObject.findChildren()"); - QVERIFY(result.isArray()); - int count = 3; - QCOMPARE(result.property("length"), QLatin1String(count); - for (int i = 0; i < 3; ++i) { - QObject* o = result.property(i).toQObject(); - if (o == namelessChild || o == child || o == anotherChild) - --count; - } - QVERIFY(count == 0); - } - - delete anotherChild; - delete namelessChild; - delete child; - */ -} - -void tst_QWebFrame::overloadedSlots() -{ - // should pick myOverloadedSlot(double) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(10)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); - - // should pick myOverloadedSlot(double) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(10.0)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); - - // should pick myOverloadedSlot(QString) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot('10')"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 29); - - // should pick myOverloadedSlot(bool) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(true)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 25); - - // should pick myOverloadedSlot(QDateTime) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(new Date())"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 32); - - // should pick myOverloadedSlot(QRegExp) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(new RegExp())"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 34); - - // should pick myOverloadedSlot(QVariant) - /* XFAIL - m_myObject->resetQtFunctionInvoked(); - QString f = evalJS("myObject.myOverloadedSlot"); - f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao"))); - QCOMPARE(m_myObject->qtFunctionInvoked(), 35); - */ - - // Should pick myOverloadedSlot(QWebElement). - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(document.body)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 36); - - // should pick myOverloadedSlot(QObject*) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(myObject)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 41); - - // should pick myOverloadedSlot(QObject*) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(null)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 41); - - // should pick myOverloadedSlot(QStringList) - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(['hello'])"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 42); -} - -void tst_QWebFrame::enumerate_data() -{ - QTest::addColumn<QStringList>("expectedNames"); - - QTest::newRow("enumerate all") - << (QStringList() - // meta-object-defined properties: - // inherited - << "objectName" - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // inherited signals and slots - << "destroyed(QObject*)" << "destroyed()" -#if defined(HAVE_QT5) && HAVE_QT5 - << "objectNameChanged(QString)" -#endif - << "deleteLater()" - // not included because it's private: - // << "_q_reregisterTimers(void*)" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); -} - -void tst_QWebFrame::enumerate() -{ - QFETCH(QStringList, expectedNames); - - MyEnumTestQObject enumQObject; - // give it some dynamic properties - enumQObject.setProperty("dp1", "dp1"); - enumQObject.setProperty("dp2", "dp2"); - enumQObject.setProperty("dp3", "dp3"); - m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject); - - // enumerate in script - { - evalJS("var enumeratedProperties = []"); - evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }"); - QStringList result = evalJSV("enumeratedProperties").toStringList(); - QCOMPARE(result.size(), expectedNames.size()); - for (int i = 0; i < expectedNames.size(); ++i) - QCOMPARE(result.at(i), expectedNames.at(i)); - } -} - -void tst_QWebFrame::objectDeleted() -{ - MyQObject* qobj = new MyQObject(); - m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj); - evalJS("bar.objectName = 'foo';"); - QCOMPARE(qobj->objectName(), QLatin1String("foo")); - evalJS("bar.intProperty = 123;"); - QCOMPARE(qobj->intProperty(), 123); - qobj->resetQtFunctionInvoked(); - evalJS("bar.myInvokable.call(bar);"); - QCOMPARE(qobj->qtFunctionInvoked(), 0); - - // do this, to ensure that we cache that it implements call - evalJS("bar()"); - - // now delete the object - delete qobj; - - QCOMPARE(evalJS("typeof bar"), sObject); - - // any attempt to access properties of the object should result in an exception - { - QString type; - QString ret = evalJS("bar.objectName", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - { - QString type; - QString ret = evalJS("bar.objectName = 'foo'", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - - // myInvokable is stored in member table (since we've accessed it before deletion) - { - QString type; - evalJS("bar.myInvokable", type); - QCOMPARE(type, sFunction); - } - - { - QString type; - QString ret = evalJS("bar.myInvokable.call(bar);", type); - ret = evalJS("bar.myInvokable(bar)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject")); - } - // myInvokableWithIntArg is not stored in member table (since we've not accessed it) - { - QString type; - QString ret = evalJS("bar.myInvokableWithIntArg", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); - } - - // access from script - evalJS("window.o = bar;"); - { - QString type; - QString ret = evalJS("o.objectName", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - { - QString type; - QString ret = evalJS("o.myInvokable()", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject")); - } - { - QString type; - QString ret = evalJS("o.myInvokableWithIntArg(10)", type); - QCOMPARE(type, sError); - QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); - } -} - -void tst_QWebFrame::typeConversion() -{ - m_myObject->resetQtFunctionInvoked(); - - QDateTime localdt(QDate(2008,1,18), QTime(12,31,0)); - QDateTime utclocaldt = localdt.toUTC(); - QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC); - - // Dates in JS (default to local) - evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 32); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt); - - m_myObject->resetQtFunctionInvoked(); - evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 32); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt); - - // Pushing QDateTimes into JS - // Local - evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}"); - evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)"); - m_myObject->emitMySignalWithDateTimeArg(localdt); - QCOMPARE(evalJS("window.__date_equals"), sTrue); - evalJS("delete window.__date_equals"); - m_myObject->emitMySignalWithDateTimeArg(utclocaldt); - QCOMPARE(evalJS("window.__date_equals"), sTrue); - evalJS("delete window.__date_equals"); - evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;"); - - // UTC - evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }"); - evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)"); - m_myObject->emitMySignalWithDateTimeArg(utcdt); - QCOMPARE(evalJS("window.__date_equals"), sTrue); - evalJS("delete window.__date_equals"); - evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;"); - - // ### RegExps -} - -class StringListTestObject : public QObject { - Q_OBJECT -public Q_SLOTS: - QVariant stringList() - { - return QStringList() << "Q" << "t"; - }; -}; - -void tst_QWebFrame::arrayObjectEnumerable() -{ - QWebPage page; - QWebFrame* frame = page.mainFrame(); - QObject* qobject = new StringListTestObject(); - frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership); - - const QString script("var stringArray = test.stringList();" - "var result = '';" - "for (var i in stringArray) {" - " result += stringArray[i];" - "}" - "result;"); - QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt")); } void tst_QWebFrame::symmetricUrl() @@ -2285,14 +197,6 @@ void tst_QWebFrame::urlChange() QCOMPARE(urlSpy.size(), 2); } - -void tst_QWebFrame::domCycles() -{ - m_view->setHtml("<html><body>"); - QVariant v = m_page->mainFrame()->evaluateJavaScript("document"); - QVERIFY(v.type() == QVariant::Map); -} - class FakeReply : public QNetworkReply { Q_OBJECT @@ -2756,89 +660,6 @@ void tst_QWebFrame::hitTestContent() QCOMPARE(link.attribute("target"), QString("_foo")); } -void tst_QWebFrame::jsByteArray() -{ - QByteArray ba("hello world"); - m_myObject->setByteArrayProperty(ba); - - // read-only property - QCOMPARE(m_myObject->byteArrayProperty(), ba); - QString type; - QVariant v = evalJSV("myObject.byteArrayProperty"); - QCOMPARE(int(v.type()), int(QVariant::ByteArray)); - - QCOMPARE(v.toByteArray(), ba); -} - -void tst_QWebFrame::ownership() -{ - // test ownership - { - QWeakPointer<QObject> ptr = new QObject(); - QVERIFY(ptr != 0); - { - QWebPage page; - QWebFrame* frame = page.mainFrame(); - frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::ScriptOwnership); - } - QVERIFY(ptr == 0); - } - { - QWeakPointer<QObject> ptr = new QObject(); - QVERIFY(ptr != 0); - QObject* before = ptr.data(); - { - QWebPage page; - QWebFrame* frame = page.mainFrame(); - frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::QtOwnership); - } - QVERIFY(ptr.data() == before); - delete ptr.data(); - } - { - QObject* parent = new QObject(); - QObject* child = new QObject(parent); - QWebPage page; - QWebFrame* frame = page.mainFrame(); - frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership); - QVariant v = frame->evaluateJavaScript("test"); - QCOMPARE(qvariant_cast<QObject*>(v), child); - delete parent; - v = frame->evaluateJavaScript("test"); - QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0); - } - { - QWeakPointer<QObject> ptr = new QObject(); - QVERIFY(ptr != 0); - { - QWebPage page; - QWebFrame* frame = page.mainFrame(); - frame->addToJavaScriptWindowObject("test", ptr.data(), QScriptEngine::AutoOwnership); - } - // no parent, so it should be like ScriptOwnership - QVERIFY(ptr == 0); - } - { - QObject* parent = new QObject(); - QWeakPointer<QObject> child = new QObject(parent); - QVERIFY(child != 0); - { - QWebPage page; - QWebFrame* frame = page.mainFrame(); - frame->addToJavaScriptWindowObject("test", child.data(), QScriptEngine::AutoOwnership); - } - // has parent, so it should be like QtOwnership - QVERIFY(child != 0); - delete parent; - } -} - -void tst_QWebFrame::nullValue() -{ - QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null"); - QVERIFY(v.isNull()); -} - void tst_QWebFrame::baseUrl_data() { QTest::addColumn<QString>("html"); @@ -3212,86 +1033,6 @@ void tst_QWebFrame::evaluateWillCauseRepaint() ::waitForSignal(view.page(), SIGNAL(repaintRequested(QRect))); } -class TestFactory : public QObject -{ - Q_OBJECT -public: - TestFactory() - : obj(0), counter(0) - {} - - Q_INVOKABLE QObject* getNewObject() - { - delete obj; - obj = new QObject(this); - obj->setObjectName(QLatin1String("test") + QString::number(++counter)); - return obj; - - } - - QObject* obj; - int counter; -}; - -void tst_QWebFrame::qObjectWrapperWithSameIdentity() -{ - m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>" - "<body><span id='span1'>test</span></body>"); - - QWebFrame* mainFrame = m_view->page()->mainFrame(); - QCOMPARE(mainFrame->toPlainText(), QString("test")); - - mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership); - - mainFrame->evaluateJavaScript("triggerBug();"); - QCOMPARE(mainFrame->toPlainText(), QString("test1")); - - mainFrame->evaluateJavaScript("triggerBug();"); - QCOMPARE(mainFrame->toPlainText(), QString("test2")); -} - -void tst_QWebFrame::introspectQtMethods_data() -{ - QTest::addColumn<QString>("objectExpression"); - QTest::addColumn<QString>("methodName"); - QTest::addColumn<QStringList>("expectedPropertyNames"); - - QTest::newRow("myObject.mySignal") - << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name"); - QTest::newRow("myObject.mySlot") - << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name"); - QTest::newRow("myObject.myInvokable") - << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name"); - QTest::newRow("myObject.mySignal.connect") - << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name"); - QTest::newRow("myObject.mySignal.disconnect") - << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name"); -} - -void tst_QWebFrame::introspectQtMethods() -{ - QFETCH(QString, objectExpression); - QFETCH(QString, methodName); - QFETCH(QStringList, expectedPropertyNames); - - QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName); - QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames); - - for (int i = 0; i < expectedPropertyNames.size(); ++i) { - QString name = expectedPropertyNames.at(i); - QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue); - evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name)); - QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object")); - QCOMPARE(evalJS("descriptor.get"), sUndefined); - QCOMPARE(evalJS("descriptor.set"), sUndefined); - QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue); - QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse); - QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse); - } - - QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty()); -} - void tst_QWebFrame::setContent_data() { QTest::addColumn<QString>("mimeType"); @@ -3374,15 +1115,6 @@ void tst_QWebFrame::setCacheLoadControlAttribute() QCOMPARE(manager->lastCacheLoad(), QNetworkRequest::PreferNetwork); } -void tst_QWebFrame::webElementSlotOnly() -{ - MyWebElementSlotOnlyObject object; - m_page->mainFrame()->setHtml("<html><head><body></body></html>"); - m_page->mainFrame()->addToJavaScriptWindowObject("myWebElementSlotObject", &object); - evalJS("myWebElementSlotObject.doSomethingWithWebElement(document.body)"); - QCOMPARE(evalJS("myWebElementSlotObject.tagName"), QString("BODY")); -} - // [Qt] Fix tst_QWebFrame::setUrlWithPendingLoads() API test // https://bugs.webkit.org/show_bug.cgi?id=63237 /* |