2 Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include <QtTest/QtTest>
23 #include <qwebelement.h>
24 #include <qwebframe.h>
31 Q_DECLARE_METATYPE(CustomType)
33 Q_DECLARE_METATYPE(QBrush*)
34 Q_DECLARE_METATYPE(QObjectList)
35 Q_DECLARE_METATYPE(QList<int>)
36 Q_DECLARE_METATYPE(Qt::BrushStyle)
37 Q_DECLARE_METATYPE(QVariantList)
38 Q_DECLARE_METATYPE(QVariantMap)
40 class MyQObject : public QObject {
43 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
44 Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
45 Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
46 Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty)
47 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
48 Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
49 Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
50 Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
51 Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
52 Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
53 Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
54 Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
55 Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
56 Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty)
57 Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty)
58 Q_ENUMS(Policy Strategy)
79 AllAbility = FooAbility | BarAbility | BazAbility
82 Q_DECLARE_FLAGS(Ability, AbilityFlag)
84 MyQObject(QObject* parent = 0)
87 m_variantValue(QLatin1String("foo")),
88 m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
89 m_stringValue(QLatin1String("bar")),
90 m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
91 m_brushValue(QColor(10, 20, 30, 40)),
93 m_writeOnlyValue(789),
96 m_qtFunctionInvoked(-1)
98 m_variantMapValue.insert("a", QVariant(123));
99 m_variantMapValue.insert("b", QVariant(QLatin1String("foo")));
100 m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this));
105 int intProperty() const
109 void setIntProperty(int value)
114 QVariant variantProperty() const
116 return m_variantValue;
118 void setVariantProperty(const QVariant& value)
120 m_variantValue = value;
123 QVariantList variantListProperty() const
125 return m_variantListValue;
127 void setVariantListProperty(const QVariantList& value)
129 m_variantListValue = value;
132 QVariantMap variantMapProperty() const
134 return m_variantMapValue;
136 void setVariantMapProperty(const QVariantMap& value)
138 m_variantMapValue = value;
141 QString stringProperty() const
143 return m_stringValue;
145 void setStringProperty(const QString& value)
147 m_stringValue = value;
150 QStringList stringListProperty() const
152 return m_stringListValue;
154 void setStringListProperty(const QStringList& value)
156 m_stringListValue = value;
159 QByteArray byteArrayProperty() const
161 return m_byteArrayValue;
163 void setByteArrayProperty(const QByteArray& value)
165 m_byteArrayValue = value;
168 QBrush brushProperty() const
172 void setBrushProperty(const QBrush& value)
174 m_brushValue = value;
177 double hiddenProperty() const
179 return m_hiddenValue;
181 void setHiddenProperty(double value)
183 m_hiddenValue = value;
186 int writeOnlyProperty() const
188 return m_writeOnlyValue;
190 void setWriteOnlyProperty(int value)
192 m_writeOnlyValue = value;
195 int readOnlyProperty() const
197 return m_readOnlyValue;
200 QKeySequence shortcut() const
204 void setShortcut(const QKeySequence& seq)
209 QWebElement webElementProperty() const
213 void setWebElementProperty(const QWebElement& element)
215 m_webElement = element;
218 CustomType propWithCustomType() const
222 void setPropWithCustomType(const CustomType& c)
227 QObject* objectStarProperty() const
231 void setObjectStarProperty(QObject* object)
233 m_objectStar = object;
237 int qtFunctionInvoked() const
239 return m_qtFunctionInvoked;
242 QVariantList qtFunctionActuals() const
247 void resetQtFunctionInvoked()
249 m_qtFunctionInvoked = -1;
253 Q_INVOKABLE void myInvokable()
255 m_qtFunctionInvoked = 0;
257 Q_INVOKABLE void myInvokableWithIntArg(int arg)
259 m_qtFunctionInvoked = 1;
262 Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg)
264 m_qtFunctionInvoked = 2;
267 Q_INVOKABLE void myInvokableWithFloatArg(float arg)
269 m_qtFunctionInvoked = 3;
272 Q_INVOKABLE void myInvokableWithDoubleArg(double arg)
274 m_qtFunctionInvoked = 4;
277 Q_INVOKABLE void myInvokableWithStringArg(const QString& arg)
279 m_qtFunctionInvoked = 5;
282 Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2)
284 m_qtFunctionInvoked = 6;
285 m_actuals << arg1 << arg2;
287 Q_INVOKABLE int myInvokableReturningInt()
289 m_qtFunctionInvoked = 7;
292 Q_INVOKABLE qlonglong myInvokableReturningLongLong()
294 m_qtFunctionInvoked = 39;
297 Q_INVOKABLE QString myInvokableReturningString()
299 m_qtFunctionInvoked = 8;
300 return QLatin1String("ciao");
302 Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // Overload.
304 m_qtFunctionInvoked = 9;
305 m_actuals << arg1 << arg2;
307 Q_INVOKABLE void myInvokableWithEnumArg(Policy policy)
309 m_qtFunctionInvoked = 10;
312 Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy)
314 m_qtFunctionInvoked = 36;
317 Q_INVOKABLE Policy myInvokableReturningEnum()
319 m_qtFunctionInvoked = 37;
322 Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum()
324 m_qtFunctionInvoked = 38;
327 Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt()
329 m_qtFunctionInvoked = 11;
330 return QVector<int>();
332 Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int>&)
334 m_qtFunctionInvoked = 12;
336 Q_INVOKABLE QObject* myInvokableReturningQObjectStar()
338 m_qtFunctionInvoked = 13;
341 Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList& lst)
343 m_qtFunctionInvoked = 14;
344 m_actuals << QVariant::fromValue(lst);
347 Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant& v)
349 m_qtFunctionInvoked = 15;
353 Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap& vm)
355 m_qtFunctionInvoked = 16;
359 Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int>& lst)
361 m_qtFunctionInvoked = 17;
362 m_actuals << QVariant::fromValue(lst);
365 Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj)
367 m_qtFunctionInvoked = 18;
368 m_actuals << QVariant::fromValue(obj);
371 Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush& brush)
373 m_qtFunctionInvoked = 19;
374 m_actuals << QVariant::fromValue(brush);
377 Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style)
379 m_qtFunctionInvoked = 43;
380 m_actuals << QVariant::fromValue(style);
382 Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg)
384 m_qtFunctionInvoked = 44;
385 m_actuals << QVariant::fromValue(arg);
387 Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg)
389 m_qtFunctionInvoked = 45;
390 m_actuals << QVariant::fromValue(arg);
392 Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg)
394 m_qtFunctionInvoked = 46;
395 m_actuals << QVariant::fromValue(arg);
397 Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString& arg2 = QString())
399 m_qtFunctionInvoked = 47;
400 m_actuals << QVariant::fromValue(arg1) << qVariantFromValue(arg2);
402 Q_INVOKABLE QObject& myInvokableReturningRef()
404 m_qtFunctionInvoked = 48;
407 Q_INVOKABLE const QObject& myInvokableReturningConstRef() const
409 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
412 Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
413 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
414 m_actuals << QVariant::fromValue(arg);
416 Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
417 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
418 m_actuals << QVariant::fromValue(arg);
420 Q_INVOKABLE void myInvokableWithBoolArg(bool arg) {
421 m_qtFunctionInvoked = 52;
429 void emitMySignalWithIntArg(int arg)
431 emit mySignalWithIntArg(arg);
433 void emitMySignal2(bool arg)
441 void emitMySignalWithDateTimeArg(QDateTime dt)
443 emit mySignalWithDateTimeArg(dt);
449 m_qtFunctionInvoked = 20;
452 void mySlotWithIntArg(int arg)
454 m_qtFunctionInvoked = 21;
458 void mySlotWithDoubleArg(double arg)
460 m_qtFunctionInvoked = 22;
464 void mySlotWithStringArg(const QString &arg)
466 m_qtFunctionInvoked = 23;
470 void myOverloadedSlot()
472 m_qtFunctionInvoked = 24;
475 void myOverloadedSlot(QObject* arg)
477 m_qtFunctionInvoked = 41;
478 m_actuals << QVariant::fromValue(arg);
481 void myOverloadedSlot(bool arg)
483 m_qtFunctionInvoked = 25;
487 void myOverloadedSlot(const QStringList &arg)
489 m_qtFunctionInvoked = 42;
493 void myOverloadedSlot(double arg)
495 m_qtFunctionInvoked = 26;
499 void myOverloadedSlot(float arg)
501 m_qtFunctionInvoked = 27;
505 void myOverloadedSlot(int arg)
507 m_qtFunctionInvoked = 28;
511 void myOverloadedSlot(const QString &arg)
513 m_qtFunctionInvoked = 29;
517 void myOverloadedSlot(const QColor &arg)
519 m_qtFunctionInvoked = 30;
523 void myOverloadedSlot(const QBrush &arg)
525 m_qtFunctionInvoked = 31;
529 void myOverloadedSlot(const QDateTime &arg)
531 m_qtFunctionInvoked = 32;
535 void myOverloadedSlot(const QDate &arg)
537 m_qtFunctionInvoked = 33;
541 void myOverloadedSlot(const QVariant &arg)
543 m_qtFunctionInvoked = 35;
547 void myOverloadedSlot(const QWebElement &arg)
549 m_qtFunctionInvoked = 36;
550 m_actuals << QVariant::fromValue<QWebElement>(arg);
554 void myProtectedSlot()
556 m_qtFunctionInvoked = 36;
560 void myPrivateSlot() { }
564 void mySignalWithIntArg(int);
565 void mySignalWithDoubleArg(double);
566 void mySignal2(bool arg = false);
567 void mySignalWithDateTimeArg(QDateTime);
571 QVariant m_variantValue;
572 QVariantList m_variantListValue;
573 QVariantMap m_variantMapValue;
574 QString m_stringValue;
575 QStringList m_stringListValue;
576 QByteArray m_byteArrayValue;
578 double m_hiddenValue;
579 int m_writeOnlyValue;
581 QKeySequence m_shortcut;
582 QWebElement m_webElement;
583 CustomType m_customType;
584 QObject* m_objectStar;
585 int m_qtFunctionInvoked;
586 QVariantList m_actuals;
589 class MyWebElementSlotOnlyObject : public QObject {
591 Q_PROPERTY(QString tagName READ tagName)
593 void doSomethingWithWebElement(const QWebElement& element)
595 m_tagName = element.tagName();
599 QString tagName() const
607 class MyOtherQObject : public MyQObject {
609 MyOtherQObject(QObject* parent = 0)
610 : MyQObject(parent) { }
613 class tst_QObjectBridge : public QObject {
624 void getSetStaticProperty();
625 void getSetDynamicProperty();
626 void getSetChildren();
627 void callQtInvokable();
628 void connectAndDisconnect();
629 void overrideInvokable();
630 void overloadedSlots();
631 void webElementSlotOnly();
632 void enumerate_data();
634 void objectDeleted();
635 void typeConversion();
636 void arrayObjectEnumerable();
641 void qObjectWrapperWithSameIdentity();
642 void introspectQtMethods_data();
643 void introspectQtMethods();
644 void scriptablePlugin();
647 QString evalJS(const QString& s)
649 QVariant ret = evalJSV(s);
652 return ret.toString();
655 QVariant evalJSV(const QString& s)
657 return m_page->mainFrame()->evaluateJavaScript(s);
660 QString evalJS(const QString& s, QString& type)
662 return evalJSV(s, type).toString();
665 QVariant evalJSV(const QString& s, QString& type)
667 // As a special measure, if we get an exception we set the type to 'error'
668 // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
669 // Similarly, an array is an object, but we'd prefer to have a type of 'array'
671 escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
672 QString code("var retvalue; "
675 " retvalue = eval('%1'); "
676 " typevalue = typeof retvalue; "
677 " if (retvalue instanceof Array) "
678 " typevalue = 'array'; "
680 " retvalue = e.name + ': ' + e.message; "
681 " typevalue = 'error'; "
683 evalJS(code.arg(escaped));
685 QVariant ret = evalJSV("retvalue");
687 type = evalJS("typevalue");
689 ret = QString("undefined");
692 evalJS("delete retvalue; delete typevalue");
697 const QString sFalse;
698 const QString sUndefined;
699 const QString sArray;
700 const QString sFunction;
701 const QString sError;
702 const QString sString;
703 const QString sObject;
704 const QString sNumber;
709 MyQObject* m_myObject;
712 tst_QObjectBridge::tst_QObjectBridge()
715 , sUndefined("undefined")
717 , sFunction("function")
725 void tst_QObjectBridge::init()
727 m_view = new QWebView();
728 m_page = m_view->page();
729 m_myObject = new MyQObject();
730 m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
733 void tst_QObjectBridge::cleanup()
739 void tst_QObjectBridge::getSetStaticProperty()
741 m_page->mainFrame()->setHtml("<html><head><body></body></html>");
742 QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
744 // initial value (set in MyQObject constructor)
747 QVariant ret = evalJSV("myObject.intProperty", type);
748 QCOMPARE(type, sNumber);
749 QCOMPARE(ret.type(), QVariant::Double);
750 QCOMPARE(ret.toInt(), 123);
752 QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
756 QVariant ret = evalJSV("myObject.variantProperty", type);
757 QCOMPARE(type, sString);
758 QCOMPARE(ret.type(), QVariant::String);
759 QCOMPARE(ret.toString(), QLatin1String("foo"));
761 QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
765 QVariant ret = evalJSV("myObject.stringProperty", type);
766 QCOMPARE(type, sString);
767 QCOMPARE(ret.type(), QVariant::String);
768 QCOMPARE(ret.toString(), QLatin1String("bar"));
770 QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
774 QVariant ret = evalJSV("myObject.variantListProperty", type);
775 QCOMPARE(type, sArray);
776 QCOMPARE(ret.type(), QVariant::List);
777 QVariantList vl = ret.value<QVariantList>();
778 QCOMPARE(vl.size(), 2);
779 QCOMPARE(vl.at(0).toInt(), 123);
780 QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
782 QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
783 QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
784 QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
788 QVariant ret = evalJSV("myObject.variantMapProperty", type);
789 QCOMPARE(type, sObject);
790 QCOMPARE(ret.type(), QVariant::Map);
791 QVariantMap vm = ret.value<QVariantMap>();
792 QCOMPARE(vm.size(), 3);
793 QCOMPARE(vm.value("a").toInt(), 123);
794 QCOMPARE(vm.value("b").toString(), QLatin1String("foo"));
795 QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject));
797 QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue);
798 QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue);
799 QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue);
803 QVariant ret = evalJSV("myObject.stringListProperty", type);
804 QCOMPARE(type, sArray);
805 QCOMPARE(ret.type(), QVariant::List);
806 QVariantList vl = ret.value<QVariantList>();
807 QCOMPARE(vl.size(), 2);
808 QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
809 QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
811 QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
812 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
813 QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
814 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
815 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
817 // property change in C++ should be reflected in script
818 m_myObject->setIntProperty(456);
819 QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
820 m_myObject->setIntProperty(789);
821 QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
823 m_myObject->setVariantProperty(QLatin1String("bar"));
824 QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
825 m_myObject->setVariantProperty(42);
826 QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
827 m_myObject->setVariantProperty(QVariant::fromValue(QBrush()));
829 m_myObject->setStringProperty(QLatin1String("baz"));
830 QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
831 m_myObject->setStringProperty(QLatin1String("zab"));
832 QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
834 // property change in script should be reflected in C++
835 QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
836 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
837 QCOMPARE(m_myObject->intProperty(), 123);
838 QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
839 "myObject.intProperty == 0"), sTrue);
840 QCOMPARE(m_myObject->intProperty(), 0);
841 QCOMPARE(evalJS("myObject.intProperty = '123';"
842 "myObject.intProperty == 123"), sTrue);
843 QCOMPARE(m_myObject->intProperty(), 123);
845 QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
846 QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
847 QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
848 QCOMPARE(evalJS("myObject.stringProperty = 123;"
849 "myObject.stringProperty"), QLatin1String("123"));
850 QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
851 QCOMPARE(evalJS("myObject.stringProperty = null"), QString());
852 QCOMPARE(evalJS("myObject.stringProperty"), QString());
853 QCOMPARE(m_myObject->stringProperty(), QString());
854 QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined);
855 QCOMPARE(evalJS("myObject.stringProperty"), QString());
856 QCOMPARE(m_myObject->stringProperty(), QString());
858 QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);"
859 "myObject.variantProperty").toDouble(), 1234.0);
860 QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0);
862 QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);"
863 "myObject.variantProperty"), sTrue);
864 QCOMPARE(m_myObject->variantProperty().toBool(), true);
866 QCOMPARE(evalJS("myObject.variantProperty = null;"
867 "myObject.variantProperty.valueOf()"), sUndefined);
868 QCOMPARE(m_myObject->variantProperty(), QVariant());
869 QCOMPARE(evalJS("myObject.variantProperty = undefined;"
870 "myObject.variantProperty.valueOf()"), sUndefined);
871 QCOMPARE(m_myObject->variantProperty(), QVariant());
873 QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
874 "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
875 QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
876 QCOMPARE(evalJS("myObject.variantProperty = 42;"
877 "myObject.variantProperty").toDouble(), 42.0);
878 QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
880 QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
881 "myObject.variantListProperty.length == 3"), sTrue);
882 QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
883 QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
884 QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
886 QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
887 "myObject.stringListProperty.length == 3"), sTrue);
888 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
889 QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
890 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
891 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
892 QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
893 QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
894 evalJS("myObject.webElementProperty=document.body;");
895 QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY"));
898 QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
899 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
901 QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
902 QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
905 QCOMPARE(evalJS("myObject.customProperty"), sUndefined);
906 QCOMPARE(evalJS("myObject.customProperty = 123;"
907 "myObject.customProperty == 123"), sTrue);
908 QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty");
909 QCOMPARE(v.type(), QVariant::Double);
910 QCOMPARE(v.toInt(), 123);
912 // non-scriptable property
913 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
914 QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
915 QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
916 "myObject.hiddenProperty == 123"), sTrue);
917 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
919 // write-only property
920 QCOMPARE(m_myObject->writeOnlyProperty(), 789);
921 QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
922 QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
923 "typeof myObject.writeOnlyProperty"), sUndefined);
924 QCOMPARE(m_myObject->writeOnlyProperty(), 123);
926 // read-only property
927 QCOMPARE(m_myObject->readOnlyProperty(), 987);
928 QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
929 QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
930 "myObject.readOnlyProperty == 987"), sTrue);
931 QCOMPARE(m_myObject->readOnlyProperty(), 987);
934 m_myObject->setObjectStarProperty(0);
935 QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0);
936 QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue);
937 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
938 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse);
939 QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue);
940 QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"),
942 m_myObject->setObjectStarProperty(this);
943 QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue);
944 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
945 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue);
946 QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue);
949 void tst_QObjectBridge::getSetDynamicProperty()
951 // initially the object does not have the property
952 // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
954 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
955 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
957 // add a dynamic property in C++
958 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
959 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
960 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
961 QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
963 // property change in script should be reflected in C++
964 QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
965 "myObject.dynamicProperty"), QLatin1String("foo"));
966 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
968 // delete the property (XFAIL - can't delete properties)
969 QEXPECT_FAIL("", "can't delete properties", Continue);
970 QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
972 QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
973 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
974 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
975 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
979 void tst_QObjectBridge::getSetChildren()
981 // initially the object does not have the child
982 // (again, no hasOwnProperty)
984 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
985 QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
988 MyQObject* child = new MyQObject(m_myObject);
989 child->setObjectName("child");
990 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
991 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
994 MyQObject* grandChild = new MyQObject(child);
995 grandChild->setObjectName("grandChild");
996 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
997 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
1001 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
1002 QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
1006 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
1007 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
1010 Q_DECLARE_METATYPE(QVector<int>)
1011 Q_DECLARE_METATYPE(QVector<double>)
1012 Q_DECLARE_METATYPE(QVector<QString>)
1014 void tst_QObjectBridge::callQtInvokable()
1016 qRegisterMetaType<QObjectList>();
1018 m_myObject->resetQtFunctionInvoked();
1019 QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
1020 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1021 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1023 // extra arguments should silently be ignored
1024 m_myObject->resetQtFunctionInvoked();
1025 QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
1026 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1027 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1029 m_myObject->resetQtFunctionInvoked();
1030 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
1031 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1032 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1033 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1035 m_myObject->resetQtFunctionInvoked();
1036 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
1037 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1038 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1039 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1041 m_myObject->resetQtFunctionInvoked();
1042 QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
1043 QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
1044 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1045 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
1047 m_myObject->resetQtFunctionInvoked();
1048 QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
1049 QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
1050 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1051 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1053 m_myObject->resetQtFunctionInvoked();
1054 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
1055 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1056 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1057 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1059 m_myObject->resetQtFunctionInvoked();
1060 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined);
1061 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1062 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1063 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5);
1065 m_myObject->resetQtFunctionInvoked();
1066 QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined);
1067 QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
1068 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1069 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true);
1071 m_myObject->resetQtFunctionInvoked();
1072 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
1073 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1074 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1075 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
1077 m_myObject->resetQtFunctionInvoked();
1078 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
1079 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1080 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1081 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1083 m_myObject->resetQtFunctionInvoked();
1084 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined);
1085 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1086 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1087 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1088 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1090 m_myObject->resetQtFunctionInvoked();
1091 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined);
1092 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1093 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1094 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1095 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1097 m_myObject->resetQtFunctionInvoked();
1098 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
1099 QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
1100 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1101 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1102 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1104 m_myObject->resetQtFunctionInvoked();
1105 QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
1106 QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
1107 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1109 m_myObject->resetQtFunctionInvoked();
1110 QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
1111 QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
1112 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1114 m_myObject->resetQtFunctionInvoked();
1115 QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
1116 QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
1117 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1119 m_myObject->resetQtFunctionInvoked();
1120 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
1121 QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
1122 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1123 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1124 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1126 m_myObject->resetQtFunctionInvoked();
1127 QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
1128 QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
1129 m_myObject->resetQtFunctionInvoked();
1132 QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
1133 QCOMPARE(type, sError);
1134 QCOMPARE(ret, QLatin1String("Error: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)"));
1135 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1138 m_myObject->resetQtFunctionInvoked();
1141 QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
1142 QCOMPARE(type, sError);
1143 QCOMPARE(ret, QLatin1String("Error: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
1146 m_myObject->resetQtFunctionInvoked();
1149 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
1150 QCOMPARE(type, sUndefined);
1151 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1152 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1153 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1154 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
1157 m_myObject->resetQtFunctionInvoked();
1160 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
1161 QCOMPARE(type, sUndefined);
1162 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1163 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1164 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1165 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
1168 // calling function that returns (const)ref
1169 m_myObject->resetQtFunctionInvoked();
1172 QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
1173 QCOMPARE(ret, sUndefined);
1174 QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1177 m_myObject->resetQtFunctionInvoked();
1180 QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
1181 QCOMPARE(ret, sUndefined);
1182 QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1185 m_myObject->resetQtFunctionInvoked();
1188 QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
1189 QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1190 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1191 QCOMPARE(type, sObject);
1192 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1195 m_myObject->resetQtFunctionInvoked();
1198 QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
1199 QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1200 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1201 QCOMPARE(type, sArray);
1202 QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
1203 QVariantList vl = qvariant_cast<QVariantList>(ret);
1204 QCOMPARE(vl.count(), 1);
1207 m_myObject->resetQtFunctionInvoked();
1210 m_myObject->setVariantProperty(QVariant(123));
1211 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
1212 QCOMPARE(type, sNumber);
1213 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1214 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1215 QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1216 QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
1217 QCOMPARE(ret.toInt(), 123);
1220 m_myObject->resetQtFunctionInvoked();
1223 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type);
1224 QCOMPARE(type, sObject);
1225 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1226 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1227 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1228 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1231 m_myObject->resetQtFunctionInvoked();
1234 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type);
1235 QCOMPARE(type, sObject);
1236 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1237 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1238 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1239 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1242 /* XFAIL - variant support
1243 m_myObject->resetQtFunctionInvoked();
1245 m_myObject->setVariantProperty(QVariant::fromValue(QBrush()));
1246 QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1247 QVERIFY(ret.isVariant());
1248 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1249 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1250 QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1251 QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1255 m_myObject->resetQtFunctionInvoked();
1258 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
1259 QCOMPARE(type, sNumber);
1260 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1261 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1262 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1263 QCOMPARE(ret.userType(), int(QMetaType::Double));
1264 QCOMPARE(ret.toInt(), 123);
1267 m_myObject->resetQtFunctionInvoked();
1270 QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
1271 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1272 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1274 QVariant v = m_myObject->qtFunctionActuals().at(0);
1275 QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1277 QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1278 QCOMPARE(vmap.keys().size(), 2);
1279 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1280 QCOMPARE(vmap.value("a"), QVariant(123));
1281 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1282 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1284 QCOMPARE(type, sObject);
1286 QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
1287 vmap = qvariant_cast<QVariantMap>(ret);
1288 QCOMPARE(vmap.keys().size(), 2);
1289 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1290 QCOMPARE(vmap.value("a"), QVariant(123));
1291 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1292 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1295 m_myObject->resetQtFunctionInvoked();
1298 QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
1299 QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1300 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1301 QVariant v = m_myObject->qtFunctionActuals().at(0);
1302 QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1303 QList<int> ilst = qvariant_cast<QList<int> >(v);
1304 QCOMPARE(ilst.size(), 2);
1305 QCOMPARE(ilst.at(0), 1);
1306 QCOMPARE(ilst.at(1), 5);
1308 QCOMPARE(type, sArray);
1309 QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
1310 QVariantList vlst = qvariant_cast<QVariantList>(ret);
1311 QCOMPARE(vlst.size(), 2);
1312 QCOMPARE(vlst.at(0).toInt(), 1);
1313 QCOMPARE(vlst.at(1).toInt(), 5);
1316 m_myObject->resetQtFunctionInvoked();
1319 QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
1320 QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1321 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1322 QVariant v = m_myObject->qtFunctionActuals().at(0);
1323 QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1324 QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
1326 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1327 QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
1329 QCOMPARE(type, sObject);
1332 m_myObject->resetQtFunctionInvoked();
1334 // no implicit conversion from integer to QObject*
1336 evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
1337 QCOMPARE(type, sError);
1341 m_myObject->resetQtFunctionInvoked();
1343 QString fun = evalJS("myObject.myInvokableWithQBrushArg");
1344 Q_ASSERT(fun.isFunction());
1345 QColor color(10, 20, 30, 40);
1346 // QColor should be converted to a QBrush
1347 QVariant ret = fun.call(QString(), QStringList()
1348 << qScriptValueFromValue(m_engine, color));
1349 QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1350 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1351 QVariant v = m_myObject->qtFunctionActuals().at(0);
1352 QCOMPARE(v.userType(), int(QMetaType::QBrush));
1353 QCOMPARE(qvariant_cast<QColor>(v), color);
1355 QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1359 // private slots should not be part of the QObject binding
1360 QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
1362 // protected slots should be fine
1363 m_myObject->resetQtFunctionInvoked();
1364 evalJS("myObject.myProtectedSlot()");
1365 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1367 // call with too few arguments
1370 QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
1371 QCOMPARE(type, sError);
1372 QCOMPARE(ret, QLatin1String("Error: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
1375 // call function where not all types have been registered
1376 m_myObject->resetQtFunctionInvoked();
1379 QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
1380 QCOMPARE(type, sError);
1381 QCOMPARE(ret, QLatin1String("Error: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
1382 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1385 // call function with incompatible argument type
1386 m_myObject->resetQtFunctionInvoked();
1389 QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
1390 QCOMPARE(type, sError);
1391 QCOMPARE(ret, QLatin1String("Error: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
1392 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1396 void tst_QObjectBridge::connectAndDisconnect()
1398 // connect(function)
1399 QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
1400 QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
1401 QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
1405 evalJS("myObject.mySignal.connect(123)", type);
1406 QCOMPARE(type, sError);
1409 evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; }");
1411 QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
1413 evalJS("gotSignal = false");
1414 evalJS("myObject.mySignal()");
1415 QCOMPARE(evalJS("gotSignal"), sTrue);
1416 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1417 QCOMPARE(evalJS("slotThisObject == window"), sTrue);
1419 evalJS("gotSignal = false");
1420 m_myObject->emitMySignal();
1421 QCOMPARE(evalJS("gotSignal"), sTrue);
1422 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1424 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
1426 evalJS("gotSignal = false");
1427 m_myObject->emitMySignalWithIntArg(123);
1428 QCOMPARE(evalJS("gotSignal"), sTrue);
1429 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1430 QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
1432 QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
1435 evalJS("myObject.mySignal.disconnect(myHandler)", type);
1436 QCOMPARE(type, sError);
1439 evalJS("gotSignal = false");
1440 QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
1441 m_myObject->emitMySignal2(true);
1442 QCOMPARE(evalJS("gotSignal"), sTrue);
1443 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1444 QCOMPARE(evalJS("signalArgs[0]"), sTrue);
1446 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
1448 QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
1449 QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
1450 QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
1452 QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
1454 evalJS("gotSignal = false");
1455 m_myObject->emitMySignal2();
1456 QCOMPARE(evalJS("gotSignal"), sTrue);
1458 QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
1460 // connect(object, function)
1461 evalJS("otherObject = { name:'foo' }");
1462 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1463 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1464 evalJS("gotSignal = false");
1465 m_myObject->emitMySignal();
1466 QCOMPARE(evalJS("gotSignal"), sFalse);
1470 evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
1471 QCOMPARE(type, sError);
1474 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1475 evalJS("gotSignal = false");
1476 m_myObject->emitMySignal();
1477 QCOMPARE(evalJS("gotSignal"), sTrue);
1478 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1479 QCOMPARE(evalJS("slotThisObject"), evalJS("otherObject"));
1480 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
1481 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1483 evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
1484 QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
1485 evalJS("gotSignal = false");
1486 m_myObject->emitMySignal2(true);
1487 QCOMPARE(evalJS("gotSignal"), sTrue);
1488 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1489 QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
1490 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
1491 QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
1493 QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
1494 evalJS("gotSignal = false");
1495 m_myObject->emitMySignal2(true);
1496 QCOMPARE(evalJS("gotSignal"), sTrue);
1497 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1498 QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
1499 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
1501 // connect(obj, string)
1504 QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')", type), sUndefined);
1505 QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')", type), sUndefined);
1506 QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')", type), sUndefined);
1507 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')", type), sUndefined);
1510 // check that emitting signals from script works
1513 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1514 m_myObject->resetQtFunctionInvoked();
1515 QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
1516 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1517 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
1520 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
1521 m_myObject->resetQtFunctionInvoked();
1522 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1523 QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
1524 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1525 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1526 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
1528 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
1529 m_myObject->resetQtFunctionInvoked();
1530 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1531 QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
1532 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1533 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
1534 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
1536 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
1537 m_myObject->resetQtFunctionInvoked();
1538 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1539 QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
1540 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1541 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1542 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
1544 // connecting to overloaded slot
1545 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
1546 m_myObject->resetQtFunctionInvoked();
1547 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1548 QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
1549 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1550 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1551 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
1553 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1554 m_myObject->resetQtFunctionInvoked();
1555 QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1556 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1557 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1558 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1559 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1561 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject, 'myOverloadedSlot(int)')"), sUndefined);
1562 m_myObject->resetQtFunctionInvoked();
1563 QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1564 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1565 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1566 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1567 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject, 'myOverloadedSlot(int)')"), sUndefined);
1571 // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
1573 QString ret = evalJS("(function() { }).connect()", type);
1574 QCOMPARE(type, sError);
1575 QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
1579 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type);
1580 QCOMPARE(type, sError);
1581 QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
1586 QString ret = evalJS("(function() { }).connect(123)", type);
1587 QCOMPARE(type, sError);
1588 QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
1592 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type);
1593 QCOMPARE(type, sError);
1594 QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
1599 QString ret = evalJS("myObject.myInvokable.connect(123)", type);
1600 QCOMPARE(type, sError);
1601 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1605 QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
1606 QCOMPARE(type, sError);
1607 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1612 QString ret = evalJS("myObject.mySignal.connect(123)", type);
1613 QCOMPARE(type, sError);
1614 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
1619 QString ret = evalJS("var randomObject = new Object; myObject.mySignal.connect(myObject, randomObject)", type);
1620 QCOMPARE(type, sError);
1621 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
1626 QString ret = evalJS("myObject.mySignal.connect(myObject, 'nonExistantSlot')", type);
1627 QCOMPARE(type, sError);
1628 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
1633 QString ret = evalJS("myObject.mySignal.disconnect()", type);
1634 QCOMPARE(type, sError);
1635 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1639 QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type);
1640 QCOMPARE(type, sError);
1641 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1646 QString ret = evalJS("myObject.mySignal.disconnect(myObject, 'nonExistantSlot')", type);
1647 QCOMPARE(type, sError);
1648 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: target is not a function"));
1651 /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
1654 QString ret = evalJS("(function() { }).disconnect(123)", type);
1655 QCOMPARE(type, sError);
1656 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
1662 QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
1663 QCOMPARE(type, sError);
1664 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1669 QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
1670 QCOMPARE(type, sError);
1671 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1675 QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
1676 QCOMPARE(type, sError);
1677 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1682 QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
1683 QCOMPARE(type, sError);
1684 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: target is not a function"));
1689 QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
1690 QCOMPARE(type, sError);
1691 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
1694 // when the wrapper dies, the connection stays alive
1695 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1696 m_myObject->resetQtFunctionInvoked();
1697 m_myObject->emitMySignal();
1698 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1699 evalJS("myObject = null");
1701 m_myObject->resetQtFunctionInvoked();
1702 m_myObject->emitMySignal();
1703 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1706 void tst_QObjectBridge::overrideInvokable()
1708 m_myObject->resetQtFunctionInvoked();
1709 QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
1710 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1712 /* XFAIL - can't write to functions with RuntimeObject
1713 m_myObject->resetQtFunctionInvoked();
1714 evalJS("myObject.myInvokable = function() { window.a = 123; }");
1715 evalJS("myObject.myInvokable()");
1716 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1717 QCOMPARE(evalJS("window.a").toDouble(), 123.0);
1719 evalJS("myObject.myInvokable = function() { window.a = 456; }");
1720 evalJS("myObject.myInvokable()");
1721 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1722 QCOMPARE(evalJS("window.a").toDouble(), 456.0);
1725 evalJS("delete myObject.myInvokable");
1726 evalJS("myObject.myInvokable()");
1727 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1730 m_myObject->resetQtFunctionInvoked();
1731 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1732 evalJS("myObject.myInvokable(123)");
1733 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1736 evalJS("delete myObject.myInvokable");
1737 m_myObject->resetQtFunctionInvoked();
1738 // this form (with the '()') is read-only
1739 evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
1740 evalJS("myObject.myInvokable()");
1741 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1744 void tst_QObjectBridge::overloadedSlots()
1746 // should pick myOverloadedSlot(double)
1747 m_myObject->resetQtFunctionInvoked();
1748 evalJS("myObject.myOverloadedSlot(10)");
1749 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1751 // should pick myOverloadedSlot(double)
1752 m_myObject->resetQtFunctionInvoked();
1753 evalJS("myObject.myOverloadedSlot(10.0)");
1754 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1756 // should pick myOverloadedSlot(QString)
1757 m_myObject->resetQtFunctionInvoked();
1758 evalJS("myObject.myOverloadedSlot('10')");
1759 QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
1761 // should pick myOverloadedSlot(bool)
1762 m_myObject->resetQtFunctionInvoked();
1763 evalJS("myObject.myOverloadedSlot(true)");
1764 QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
1766 // should pick myOverloadedSlot(QDateTime)
1767 m_myObject->resetQtFunctionInvoked();
1768 evalJS("myObject.myOverloadedSlot(new Date())");
1769 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1771 // should pick myOverloadedSlot(QVariant)
1773 m_myObject->resetQtFunctionInvoked();
1774 QString f = evalJS("myObject.myOverloadedSlot");
1775 f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
1776 QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
1779 // Should pick myOverloadedSlot(QWebElement).
1780 m_myObject->resetQtFunctionInvoked();
1781 evalJS("myObject.myOverloadedSlot(document.body)");
1782 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1784 // should pick myOverloadedSlot(QObject*)
1785 m_myObject->resetQtFunctionInvoked();
1786 evalJS("myObject.myOverloadedSlot(myObject)");
1787 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1789 // should pick myOverloadedSlot(QObject*)
1790 m_myObject->resetQtFunctionInvoked();
1791 evalJS("myObject.myOverloadedSlot(null)");
1792 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1794 // should pick myOverloadedSlot(QStringList)
1795 m_myObject->resetQtFunctionInvoked();
1796 evalJS("myObject.myOverloadedSlot(['hello'])");
1797 QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
1800 class MyEnumTestQObject : public QObject {
1802 Q_PROPERTY(QString p1 READ p1)
1803 Q_PROPERTY(QString p2 READ p2)
1804 Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
1805 Q_PROPERTY(QString p4 READ p4)
1806 Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
1807 Q_PROPERTY(QString p6 READ p6)
1809 MyEnumTestQObject(QObject* parent = 0)
1810 : QObject(parent) { }
1812 QString p1() const { return QLatin1String("p1"); }
1813 QString p2() const { return QLatin1String("p2"); }
1814 QString p3() const { return QLatin1String("p3"); }
1815 QString p4() const { return QLatin1String("p4"); }
1816 QString p5() const { return QLatin1String("p5"); }
1817 QString p6() const { return QLatin1String("p6"); }
1821 void myOtherSlot() { }
1826 void tst_QObjectBridge::enumerate_data()
1828 QTest::addColumn<QStringList>("expectedNames");
1830 QTest::newRow("enumerate all")
1832 // meta-object-defined properties:
1836 << "p1" << "p2" << "p4" << "p6"
1837 // dynamic properties
1838 << "dp1" << "dp2" << "dp3"
1839 // inherited signals and slots
1840 << "destroyed(QObject*)" << "destroyed()"
1841 << "objectNameChanged(QString)"
1843 // not included because it's private:
1844 // << "_q_reregisterTimers(void*)"
1848 << "mySlot()" << "myOtherSlot()");
1851 void tst_QObjectBridge::enumerate()
1853 QFETCH(QStringList, expectedNames);
1855 MyEnumTestQObject enumQObject;
1856 // give it some dynamic properties
1857 enumQObject.setProperty("dp1", "dp1");
1858 enumQObject.setProperty("dp2", "dp2");
1859 enumQObject.setProperty("dp3", "dp3");
1860 m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
1862 // enumerate in script
1864 evalJS("var enumeratedProperties = []");
1865 evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
1866 QStringList result = evalJSV("enumeratedProperties").toStringList();
1867 QCOMPARE(result.size(), expectedNames.size());
1868 for (int i = 0; i < expectedNames.size(); ++i)
1869 QCOMPARE(result.at(i), expectedNames.at(i));
1873 void tst_QObjectBridge::objectDeleted()
1875 MyQObject* qobj = new MyQObject();
1876 m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
1877 evalJS("bar.objectName = 'foo';");
1878 QCOMPARE(qobj->objectName(), QLatin1String("foo"));
1879 evalJS("bar.intProperty = 123;");
1880 QCOMPARE(qobj->intProperty(), 123);
1881 qobj->resetQtFunctionInvoked();
1882 evalJS("bar.myInvokable(bar);");
1883 QCOMPARE(qobj->qtFunctionInvoked(), 0);
1885 // do this, to ensure that we cache that it implements call
1888 // now delete the object
1891 QCOMPARE(evalJS("typeof bar"), sObject);
1893 // any attempt to access properties of the object should result in an exception
1896 QString ret = evalJS("bar.objectName", type);
1897 QCOMPARE(type, sError);
1898 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1902 QString ret = evalJS("bar.objectName = 'foo'", type);
1903 QCOMPARE(type, sError);
1904 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1907 // myInvokable is stored in member table (since we've accessed it before deletion)
1910 evalJS("bar.myInvokable", type);
1911 QCOMPARE(type, sFunction);
1916 QString ret = evalJS("bar.myInvokable.call(bar);", type);
1917 ret = evalJS("bar.myInvokable(bar)", type);
1918 QCOMPARE(type, sError);
1919 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1921 // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
1924 QString ret = evalJS("bar.myInvokableWithIntArg", type);
1925 QCOMPARE(type, sError);
1926 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1929 // access from script
1930 evalJS("window.o = bar;");
1933 QString ret = evalJS("o.objectName", type);
1934 QCOMPARE(type, sError);
1935 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1939 QString ret = evalJS("o.myInvokable()", type);
1940 QCOMPARE(type, sError);
1941 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1945 QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
1946 QCOMPARE(type, sError);
1947 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1951 void tst_QObjectBridge::typeConversion()
1953 m_myObject->resetQtFunctionInvoked();
1955 QDateTime localdt(QDate(2008, 1, 18), QTime(12, 31, 0));
1956 QDateTime utclocaldt = localdt.toUTC();
1957 QDateTime utcdt(QDate(2008, 1, 18), QTime(12, 31, 0), Qt::UTC);
1959 // Dates in JS (default to local)
1960 evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
1961 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1962 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1963 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
1965 m_myObject->resetQtFunctionInvoked();
1966 evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
1967 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1968 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1969 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
1971 // Pushing QDateTimes into JS
1973 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
1974 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1975 m_myObject->emitMySignalWithDateTimeArg(localdt);
1976 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1977 evalJS("delete window.__date_equals");
1978 m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
1979 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1980 evalJS("delete window.__date_equals");
1981 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1984 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
1985 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1986 m_myObject->emitMySignalWithDateTimeArg(utcdt);
1987 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1988 evalJS("delete window.__date_equals");
1989 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1992 class StringListTestObject : public QObject {
1995 QVariant stringList()
1997 return QStringList() << "Q" << "t";
2001 void tst_QObjectBridge::arrayObjectEnumerable()
2004 QWebFrame* frame = page.mainFrame();
2005 QObject* qobject = new StringListTestObject();
2006 frame->addToJavaScriptWindowObject("test", qobject, QWebFrame::ScriptOwnership);
2008 const QString script("var stringArray = test.stringList();"
2010 "for (var i in stringArray) {"
2011 " result += stringArray[i];"
2014 QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt"));
2017 void tst_QObjectBridge::domCycles()
2019 m_view->setHtml("<html><body>");
2020 QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
2021 QVERIFY(v.type() == QVariant::Map);
2024 void tst_QObjectBridge::jsByteArray()
2026 QByteArray ba("hello world");
2027 m_myObject->setByteArrayProperty(ba);
2029 // read-only property
2030 QCOMPARE(m_myObject->byteArrayProperty(), ba);
2032 QVariant v = evalJSV("myObject.byteArrayProperty");
2033 QCOMPARE(int(v.type()), int(QVariant::ByteArray));
2035 QCOMPARE(v.toByteArray(), ba);
2038 void tst_QObjectBridge::ownership()
2042 QWeakPointer<QObject> ptr = new QObject();
2046 QWebFrame* frame = page.mainFrame();
2047 frame->addToJavaScriptWindowObject("test", ptr.data(), QWebFrame::ScriptOwnership);
2052 QWeakPointer<QObject> ptr = new QObject();
2054 QObject* before = ptr.data();
2057 QWebFrame* frame = page.mainFrame();
2058 frame->addToJavaScriptWindowObject("test", ptr.data(), QWebFrame::QtOwnership);
2060 QVERIFY(ptr.data() == before);
2064 QObject* parent = new QObject();
2065 QObject* child = new QObject(parent);
2067 QWebFrame* frame = page.mainFrame();
2068 frame->addToJavaScriptWindowObject("test", child, QWebFrame::QtOwnership);
2069 QVariant v = frame->evaluateJavaScript("test");
2070 QCOMPARE(qvariant_cast<QObject*>(v), child);
2072 v = frame->evaluateJavaScript("test");
2073 QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0);
2076 QWeakPointer<QObject> ptr = new QObject();
2080 QWebFrame* frame = page.mainFrame();
2081 frame->addToJavaScriptWindowObject("test", ptr.data(), QWebFrame::AutoOwnership);
2083 // no parent, so it should be like ScriptOwnership
2087 QObject* parent = new QObject();
2088 QWeakPointer<QObject> child = new QObject(parent);
2092 QWebFrame* frame = page.mainFrame();
2093 frame->addToJavaScriptWindowObject("test", child.data(), QWebFrame::AutoOwnership);
2095 // has parent, so it should be like QtOwnership
2101 void tst_QObjectBridge::nullValue()
2103 QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null");
2104 QVERIFY(v.isNull());
2107 class TestFactory : public QObject {
2111 : obj(0), counter(0)
2114 Q_INVOKABLE QObject* getNewObject()
2117 obj = new QObject(this);
2118 obj->setObjectName(QLatin1String("test") + QString::number(++counter));
2127 void tst_QObjectBridge::qObjectWrapperWithSameIdentity()
2129 m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>"
2130 "<body><span id='span1'>test</span></body>");
2132 QWebFrame* mainFrame = m_view->page()->mainFrame();
2133 QCOMPARE(mainFrame->toPlainText(), QString("test"));
2135 mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QWebFrame::ScriptOwnership);
2137 mainFrame->evaluateJavaScript("triggerBug();");
2138 QCOMPARE(mainFrame->toPlainText(), QString("test1"));
2140 mainFrame->evaluateJavaScript("triggerBug();");
2141 QCOMPARE(mainFrame->toPlainText(), QString("test2"));
2144 void tst_QObjectBridge::introspectQtMethods_data()
2146 QTest::addColumn<QString>("objectExpression");
2147 QTest::addColumn<QString>("methodName");
2148 QTest::addColumn<QStringList>("expectedPropertyNames");
2150 QTest::newRow("myObject.mySignal")
2151 << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name");
2152 QTest::newRow("myObject.mySlot")
2153 << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name");
2154 QTest::newRow("myObject.myInvokable")
2155 << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name");
2156 QTest::newRow("myObject.mySignal.connect")
2157 << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name");
2158 QTest::newRow("myObject.mySignal.disconnect")
2159 << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name");
2162 void tst_QObjectBridge::introspectQtMethods()
2164 QFETCH(QString, objectExpression);
2165 QFETCH(QString, methodName);
2166 QFETCH(QStringList, expectedPropertyNames);
2168 QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName);
2169 QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames);
2171 for (int i = 0; i < expectedPropertyNames.size(); ++i) {
2172 QString name = expectedPropertyNames.at(i);
2173 QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue);
2174 evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name));
2175 QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object"));
2176 QCOMPARE(evalJS("descriptor.get"), sUndefined);
2177 QCOMPARE(evalJS("descriptor.set"), sUndefined);
2178 QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
2179 QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
2180 QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sTrue);
2183 QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty());
2186 void tst_QObjectBridge::webElementSlotOnly()
2188 MyWebElementSlotOnlyObject object;
2189 m_page->mainFrame()->setHtml("<html><head><body></body></html>");
2190 m_page->mainFrame()->addToJavaScriptWindowObject("myWebElementSlotObject", &object);
2191 evalJS("myWebElementSlotObject.doSomethingWithWebElement(document.body)");
2192 QCOMPARE(evalJS("myWebElementSlotObject.tagName"), QString("BODY"));
2195 class TestPluginWidget : public QWidget {
2198 TestPluginWidget() { }
2201 int slotWithReturnValue() { return 42; }
2204 class TestWebPage : public QWebPage {
2207 TestWebPage(QObject* parent = 0)
2215 virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&)
2218 return new TestPluginWidget;
2222 void tst_QObjectBridge::scriptablePlugin()
2225 TestWebPage* page = new TestWebPage;
2227 page->setParent(&view);
2228 view.settings()->setAttribute(QWebSettings::PluginsEnabled, true);
2230 page->mainFrame()->setHtml("<object width=100 height=100 type=\"application/x-qt-plugin\"></object>");
2231 QCOMPARE(page->creationCount, 1);
2233 QVariant result = page->mainFrame()->evaluateJavaScript("document.querySelector(\"object\").slotWithReturnValue()");
2234 QCOMPARE(result.toString(), QLatin1String("42"));
2237 QTEST_MAIN(tst_QObjectBridge)
2238 #include "tst_qobjectbridge.moc"