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