Merge branch 'qtquick2' of scm.dev.nokia.troll.no:qt/qtdeclarative-staging into v8
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativexmlhttprequest / tst_qdeclarativexmlhttprequest.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QDeclarativeEngine>
44 #include <QDeclarativeComponent>
45 #include <QDebug>
46 #include <QNetworkCookieJar>
47 #include "testhttpserver.h"
48 #include "../../../shared/util.h"
49
50 #define SERVER_PORT 14445
51
52 #ifdef Q_OS_SYMBIAN
53 // In Symbian OS test data is located in applications private dir
54 #define SRCDIR "."
55 #endif
56
57 class tst_qdeclarativexmlhttprequest : public QObject
58 {
59     Q_OBJECT
60 public:
61     tst_qdeclarativexmlhttprequest() {}
62
63 private slots:
64     void domExceptionCodes();
65     void callbackException();
66     void callbackException_data();
67     void staticStateValues();
68     void instanceStateValues();
69     void constructor();
70     void defaultState();
71     void open();
72     void open_data();
73     void open_invalid_method();
74     void open_sync();
75     void open_arg_count();
76     void setRequestHeader();
77     void setRequestHeader_unsent();
78     void setRequestHeader_illegalName_data();
79     void setRequestHeader_illegalName();
80     void setRequestHeader_sent();
81     void setRequestHeader_args();
82     void send_unsent();
83     void send_alreadySent();
84     void send_ignoreData();
85     void send_withdata();
86     void send_withdata_data();
87     void abort();
88     void abort_unsent();
89     void abort_opened();
90     void getResponseHeader();
91     void getResponseHeader_unsent();
92     void getResponseHeader_sent();
93     void getResponseHeader_args();
94     void getAllResponseHeaders();
95     void getAllResponseHeaders_unsent();
96     void getAllResponseHeaders_sent();
97     void getAllResponseHeaders_args();
98     void status();
99     void status_data();
100     void statusText();
101     void statusText_data();
102     void responseText();
103     void responseText_data();
104     void responseXML_invalid();
105     void invalidMethodUsage();
106     void redirects();
107     void nonUtf8();
108     void nonUtf8_data();
109
110     // Attributes
111     void document();
112     void element();
113     void attr();
114     void text();
115     void cdata();
116
117     // Crashes
118     // void outstanding_request_at_shutdown();
119
120     // void network_errors()
121     // void readyState()
122
123 private:
124     QDeclarativeEngine engine;
125 };
126
127 inline QUrl TEST_FILE(const QString &filename)
128 {
129     return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename);
130 }
131
132 // Test that the dom exception codes are correct
133 void tst_qdeclarativexmlhttprequest::domExceptionCodes()
134 {
135     QDeclarativeComponent component(&engine, TEST_FILE("domExceptionCodes.qml"));
136     QObject *object = component.create();
137     QVERIFY(object != 0);
138
139     QCOMPARE(object->property("index_size_err").toInt(), 1);
140     QCOMPARE(object->property("domstring_size_err").toInt(), 2);
141     QCOMPARE(object->property("hierarchy_request_err").toInt(), 3);
142     QCOMPARE(object->property("wrong_document_err").toInt(), 4);
143     QCOMPARE(object->property("invalid_character_err").toInt(), 5);
144     QCOMPARE(object->property("no_data_allowed_err").toInt(), 6);
145     QCOMPARE(object->property("no_modification_allowed_err").toInt(), 7);
146     QCOMPARE(object->property("not_found_err").toInt(), 8);
147     QCOMPARE(object->property("not_supported_err").toInt(), 9);
148     QCOMPARE(object->property("inuse_attribute_err").toInt(), 10);
149     QCOMPARE(object->property("invalid_state_err").toInt(), 11);
150     QCOMPARE(object->property("syntax_err").toInt(), 12);
151     QCOMPARE(object->property("invalid_modification_err").toInt(), 13);
152     QCOMPARE(object->property("namespace_err").toInt(), 14);
153     QCOMPARE(object->property("invalid_access_err").toInt(), 15);
154     QCOMPARE(object->property("validation_err").toInt(), 16);
155     QCOMPARE(object->property("type_mismatch_err").toInt(), 17);
156
157     delete object;
158 }
159
160 void tst_qdeclarativexmlhttprequest::callbackException_data()
161 {
162     QTest::addColumn<QString>("which");
163     QTest::addColumn<int>("line");
164
165     QTest::newRow("on-opened") << "1" << 15;
166     QTest::newRow("on-loading") << "3" << 15;
167     QTest::newRow("on-done") << "4" << 15;
168 }
169
170 void tst_qdeclarativexmlhttprequest::callbackException()
171 {
172     // Test exception reporting for exceptions thrown at various points.
173
174     QFETCH(QString, which);
175     QFETCH(int, line);
176     
177     QString expect = TEST_FILE("callbackException.qml").toString() + ":"+QString::number(line)+": Error: Exception from Callback";
178     QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
179
180     QDeclarativeComponent component(&engine, TEST_FILE("callbackException.qml"));
181     QObject *object = component.beginCreate(engine.rootContext());
182     QVERIFY(object != 0);
183     object->setProperty("url", "testdocument.html");
184     object->setProperty("which", which);
185     component.completeCreate();
186
187     QTRY_VERIFY(object->property("threw").toBool() == true);
188
189     delete object;
190 }
191
192 // Test that the state value properties on the XMLHttpRequest constructor have the correct values.
193 // ### WebKit does not do this, but it seems to fit the standard and QML better
194 void tst_qdeclarativexmlhttprequest::staticStateValues()
195 {
196     QDeclarativeComponent component(&engine, TEST_FILE("staticStateValues.qml"));
197     QObject *object = component.create();
198     QVERIFY(object != 0);
199
200     QCOMPARE(object->property("unsent").toInt(), 0);
201     QCOMPARE(object->property("opened").toInt(), 1);
202     QCOMPARE(object->property("headers_received").toInt(), 2);
203     QCOMPARE(object->property("loading").toInt(), 3);
204     QCOMPARE(object->property("done").toInt(), 4);
205
206     delete object;
207 }
208
209 // Test that the state value properties on instances have the correct values.
210 void tst_qdeclarativexmlhttprequest::instanceStateValues()
211 {
212     QDeclarativeComponent component(&engine, TEST_FILE("instanceStateValues.qml"));
213     QObject *object = component.create();
214     QVERIFY(object != 0);
215
216     QCOMPARE(object->property("unsent").toInt(), 0);
217     QCOMPARE(object->property("opened").toInt(), 1);
218     QCOMPARE(object->property("headers_received").toInt(), 2);
219     QCOMPARE(object->property("loading").toInt(), 3);
220     QCOMPARE(object->property("done").toInt(), 4);
221
222     delete object;
223 }
224
225 // Test calling constructor 
226 void tst_qdeclarativexmlhttprequest::constructor()
227 {
228     QDeclarativeComponent component(&engine, TEST_FILE("constructor.qml"));
229     QObject *object = component.create();
230     QVERIFY(object != 0);
231
232     QCOMPARE(object->property("calledAsConstructor").toBool(), true);
233     QCOMPARE(object->property("calledAsFunction").toBool(), true);
234
235     delete object;
236 }
237
238 // Test that all the properties are set correctly before any request is sent
239 void tst_qdeclarativexmlhttprequest::defaultState()
240 {
241     QDeclarativeComponent component(&engine, TEST_FILE("defaultState.qml"));
242     QObject *object = component.create();
243     QVERIFY(object != 0);
244
245     QCOMPARE(object->property("readState").toInt(), 0);
246     QCOMPARE(object->property("statusIsException").toBool(), true);
247     QCOMPARE(object->property("statusTextIsException").toBool(), true);
248     QCOMPARE(object->property("responseText").toString(), QString());
249     QCOMPARE(object->property("responseXMLIsNull").toBool(), true);
250
251     delete object;
252 }
253
254 // Test valid XMLHttpRequest.open() calls
255 void tst_qdeclarativexmlhttprequest::open()
256 {
257     QFETCH(QUrl, qmlFile);
258     QFETCH(QString, url);
259     QFETCH(bool, remote);
260
261     TestHTTPServer *server = 0;
262     if (remote) {
263         server = new TestHTTPServer(SERVER_PORT);
264         QVERIFY(server->isValid());
265         QVERIFY(server->wait(TEST_FILE("open_network.expect"), 
266                              TEST_FILE("open_network.reply"), 
267                              TEST_FILE("testdocument.html")));
268     }
269
270     QDeclarativeComponent component(&engine, qmlFile);
271     QObject *object = component.beginCreate(engine.rootContext());
272     QVERIFY(object != 0);
273     object->setProperty("url", url);
274     component.completeCreate();
275
276     QCOMPARE(object->property("readyState").toBool(), true);
277     QCOMPARE(object->property("openedState").toBool(), true);
278     QCOMPARE(object->property("status").toBool(), true);
279     QCOMPARE(object->property("statusText").toBool(), true);
280     QCOMPARE(object->property("responseText").toBool(), true);
281     QCOMPARE(object->property("responseXML").toBool(), true);
282
283     QTRY_VERIFY(object->property("dataOK").toBool() == true);
284
285     delete server;
286     delete object;
287 }
288
289 void tst_qdeclarativexmlhttprequest::open_data()
290 {
291     QTest::addColumn<QUrl>("qmlFile");
292     QTest::addColumn<QString>("url");
293     QTest::addColumn<bool>("remote");
294
295     QTest::newRow("Relative url)") << TEST_FILE("open.qml") << "testdocument.html" << false;
296     QTest::newRow("Absolute url)") << TEST_FILE("open.qml") << TEST_FILE("testdocument.html").toString() << false;
297     QTest::newRow("Absolute network url)") << TEST_FILE("open.qml") << "http://127.0.0.1:14445/testdocument.html" << true;
298
299     // ### Check that the username/password were sent to the server
300     QTest::newRow("User/pass") << TEST_FILE("open_user.qml") << "http://127.0.0.1:14445/testdocument.html" << true;
301 }
302
303 // Test that calling XMLHttpRequest.open() with an invalid method raises an exception
304 void tst_qdeclarativexmlhttprequest::open_invalid_method()
305 {
306     QDeclarativeComponent component(&engine, TEST_FILE("open_invalid_method.qml"));
307     QObject *object = component.create();
308     QVERIFY(object != 0);
309
310     QCOMPARE(object->property("exceptionThrown").toBool(), true);
311
312     delete object;
313 }
314
315 // Test that calling XMLHttpRequest.open() with sync raises an exception
316 void tst_qdeclarativexmlhttprequest::open_sync()
317 {
318     QDeclarativeComponent component(&engine, TEST_FILE("open_sync.qml"));
319     QObject *object = component.create();
320     QVERIFY(object != 0);
321
322     QCOMPARE(object->property("exceptionThrown").toBool(), true);
323
324     delete object;
325 }
326
327 // Calling with incorrect arg count raises an exception
328 void tst_qdeclarativexmlhttprequest::open_arg_count()
329 {
330     {
331         QDeclarativeComponent component(&engine, TEST_FILE("open_arg_count.1.qml"));
332         QObject *object = component.create();
333         QVERIFY(object != 0);
334
335         QCOMPARE(object->property("exceptionThrown").toBool(), true);
336
337         delete object;
338     }
339
340     {
341         QDeclarativeComponent component(&engine, TEST_FILE("open_arg_count.2.qml"));
342         QObject *object = component.create();
343         QVERIFY(object != 0);
344
345         QCOMPARE(object->property("exceptionThrown").toBool(), true);
346
347         delete object;
348     }
349 }
350
351 // Test valid setRequestHeader() calls
352 void tst_qdeclarativexmlhttprequest::setRequestHeader()
353 {
354     TestHTTPServer server(SERVER_PORT);
355     QVERIFY(server.isValid());
356     QVERIFY(server.wait(TEST_FILE("setRequestHeader.expect"), 
357                         TEST_FILE("setRequestHeader.reply"), 
358                         TEST_FILE("testdocument.html")));
359
360     QDeclarativeComponent component(&engine, TEST_FILE("setRequestHeader.qml"));
361     QObject *object = component.beginCreate(engine.rootContext());
362     QVERIFY(object != 0);
363     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
364     component.completeCreate();
365
366     QTRY_VERIFY(object->property("dataOK").toBool() == true);
367
368     delete object;
369 }
370
371 // Test setting headers before open() throws exception
372 void tst_qdeclarativexmlhttprequest::setRequestHeader_unsent()
373 {
374     QDeclarativeComponent component(&engine, TEST_FILE("setRequestHeader_unsent.qml"));
375     QObject *object = component.create();
376     QVERIFY(object != 0);
377
378     QCOMPARE(object->property("test").toBool(), true);
379
380     delete object;
381 }
382
383 void tst_qdeclarativexmlhttprequest::setRequestHeader_illegalName_data()
384 {
385     QTest::addColumn<QString>("name");
386
387     QTest::newRow("Accept-Charset") << "AccePT-CHArset";
388     QTest::newRow("Accept-Encoding") << "AccEpt-EnCOding";
389     QTest::newRow("Connection") << "ConnECtion";
390     QTest::newRow("Content-Length") << "ContEnt-LenGth";
391     QTest::newRow("Cookie") << "CookIe";
392     QTest::newRow("Cookie2") << "CoOkie2";
393     QTest::newRow("Content-Transfer-Encoding") << "ConteNT-tRANSFER-eNCOding";
394     QTest::newRow("Date") << "DaTE";
395     QTest::newRow("Expect") << "ExPect";
396     QTest::newRow("Host") << "HoST";
397     QTest::newRow("Keep-Alive") << "KEEP-aLive";
398     QTest::newRow("Referer") << "ReferEr";
399     QTest::newRow("TE") << "Te";
400     QTest::newRow("Trailer") << "TraILEr";
401     QTest::newRow("Transfer-Encoding") << "tRANsfer-Encoding";
402     QTest::newRow("Upgrade") << "UpgrADe";
403     QTest::newRow("User-Agent") << "uSEr-Agent";
404     QTest::newRow("Via") << "vIa";
405     QTest::newRow("Proxy-") << "ProXy-";
406     QTest::newRow("Sec-") << "SeC-";
407     QTest::newRow("Proxy-*") << "Proxy-BLAH";
408     QTest::newRow("Sec-*") << "Sec-F";
409 }
410
411 // Tests that using illegal header names has no effect
412 void tst_qdeclarativexmlhttprequest::setRequestHeader_illegalName()
413 {
414     QFETCH(QString, name);
415
416     TestHTTPServer server(SERVER_PORT);
417     QVERIFY(server.isValid());
418     QVERIFY(server.wait(TEST_FILE("open_network.expect"), 
419                         TEST_FILE("open_network.reply"), 
420                         TEST_FILE("testdocument.html")));
421
422     QDeclarativeComponent component(&engine, TEST_FILE("setRequestHeader_illegalName.qml"));
423     QObject *object = component.beginCreate(engine.rootContext());
424     QVERIFY(object != 0);
425     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
426     object->setProperty("header", name);
427     component.completeCreate();
428
429     QCOMPARE(object->property("readyState").toBool(), true);
430     QCOMPARE(object->property("openedState").toBool(), true);
431     QCOMPARE(object->property("status").toBool(), true);
432     QCOMPARE(object->property("statusText").toBool(), true);
433     QCOMPARE(object->property("responseText").toBool(), true);
434     QCOMPARE(object->property("responseXML").toBool(), true);
435
436     QTRY_VERIFY(object->property("dataOK").toBool() == true);
437
438     delete object;
439 }
440
441 // Test that attempting to set a header after a request is sent throws an exception
442 void tst_qdeclarativexmlhttprequest::setRequestHeader_sent()
443 {
444     TestHTTPServer server(SERVER_PORT);
445     QVERIFY(server.isValid());
446     QVERIFY(server.wait(TEST_FILE("open_network.expect"), 
447                         TEST_FILE("open_network.reply"), 
448                         TEST_FILE("testdocument.html")));
449
450     QDeclarativeComponent component(&engine, TEST_FILE("setRequestHeader_sent.qml"));
451     QObject *object = component.beginCreate(engine.rootContext());
452     QVERIFY(object != 0);
453     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
454     component.completeCreate();
455
456     QCOMPARE(object->property("test").toBool(), true);
457     
458     QTRY_VERIFY(object->property("dataOK").toBool() == true);
459
460     delete object;
461 }
462
463 // Invalid arg count throws exception
464 void tst_qdeclarativexmlhttprequest::setRequestHeader_args()
465 {
466     QDeclarativeComponent component(&engine, TEST_FILE("setRequestHeader_args.qml"));
467     QObject *object = component.create();
468     QVERIFY(object != 0);
469
470     QCOMPARE(object->property("exceptionThrown").toBool(), true);
471
472     delete object;
473 }
474
475 // Test that calling send() in UNSENT state throws an exception
476 void tst_qdeclarativexmlhttprequest::send_unsent()
477 {
478     QDeclarativeComponent component(&engine, TEST_FILE("send_unsent.qml"));
479     QObject *object = component.create();
480     QVERIFY(object != 0);
481
482     QCOMPARE(object->property("test").toBool(), true);
483
484     delete object;
485 }
486
487 // Test attempting to resend a sent request throws an exception
488 void tst_qdeclarativexmlhttprequest::send_alreadySent()
489 {
490     QDeclarativeComponent component(&engine, TEST_FILE("send_alreadySent.qml"));
491     QObject *object = component.create();
492     QVERIFY(object != 0);
493
494     QCOMPARE(object->property("test").toBool(), true);
495     QTRY_VERIFY(object->property("dataOK").toBool() == true);
496
497     delete object;
498 }
499
500 // Test that sends for GET, HEAD and DELETE ignore data
501 void tst_qdeclarativexmlhttprequest::send_ignoreData()
502 {
503     {
504         TestHTTPServer server(SERVER_PORT);
505         QVERIFY(server.isValid());
506         QVERIFY(server.wait(TEST_FILE("send_ignoreData_GET.expect"), 
507                             TEST_FILE("send_ignoreData.reply"), 
508                             TEST_FILE("testdocument.html")));
509
510         QDeclarativeComponent component(&engine, TEST_FILE("send_ignoreData.qml"));
511         QObject *object = component.beginCreate(engine.rootContext());
512         QVERIFY(object != 0);
513         object->setProperty("reqType", "GET");
514         object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
515         component.completeCreate();
516
517         QTRY_VERIFY(object->property("dataOK").toBool() == true);
518
519         delete object;
520     }
521
522     {
523         TestHTTPServer server(SERVER_PORT);
524         QVERIFY(server.isValid());
525         QVERIFY(server.wait(TEST_FILE("send_ignoreData_HEAD.expect"), 
526                             TEST_FILE("send_ignoreData.reply"), 
527                             QUrl()));
528
529         QDeclarativeComponent component(&engine, TEST_FILE("send_ignoreData.qml"));
530         QObject *object = component.beginCreate(engine.rootContext());
531         QVERIFY(object != 0);
532         object->setProperty("reqType", "HEAD");
533         object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
534         component.completeCreate();
535
536         QTRY_VERIFY(object->property("dataOK").toBool() == true);
537
538         delete object;
539     }
540
541     {
542         TestHTTPServer server(SERVER_PORT);
543         QVERIFY(server.isValid());
544         QVERIFY(server.wait(TEST_FILE("send_ignoreData_DELETE.expect"), 
545                             TEST_FILE("send_ignoreData.reply"), 
546                             QUrl()));
547
548         QDeclarativeComponent component(&engine, TEST_FILE("send_ignoreData.qml"));
549         QObject *object = component.beginCreate(engine.rootContext());
550         QVERIFY(object != 0);
551         object->setProperty("reqType", "DELETE");
552         object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
553         component.completeCreate();
554
555         QTRY_VERIFY(object->property("dataOK").toBool() == true);
556
557         delete object;
558     }
559 }
560
561 // Test that send()'ing data works
562 void tst_qdeclarativexmlhttprequest::send_withdata()
563 {
564     QFETCH(QString, file_expected);
565     QFETCH(QString, file_qml);
566
567     TestHTTPServer server(SERVER_PORT);
568     QVERIFY(server.isValid());
569     QVERIFY(server.wait(TEST_FILE(file_expected), 
570                         TEST_FILE("send_data.reply"), 
571                         TEST_FILE("testdocument.html")));
572
573     QDeclarativeComponent component(&engine, TEST_FILE(file_qml));
574     QObject *object = component.beginCreate(engine.rootContext());
575     QVERIFY(object != 0);
576     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
577     component.completeCreate();
578
579     QTRY_VERIFY(object->property("dataOK").toBool() == true);
580
581     delete object;
582 }
583
584 void tst_qdeclarativexmlhttprequest::send_withdata_data()
585 {
586     QTest::addColumn<QString>("file_expected");
587     QTest::addColumn<QString>("file_qml");
588
589     QTest::newRow("No content-type") << "send_data.1.expect" << "send_data.1.qml";
590     QTest::newRow("Correct content-type") << "send_data.1.expect" << "send_data.2.qml";
591     QTest::newRow("Incorrect content-type") << "send_data.1.expect" << "send_data.3.qml";
592     QTest::newRow("Correct content-type - out of order") << "send_data.4.expect" << "send_data.4.qml";
593     QTest::newRow("Incorrect content-type - out of order") << "send_data.4.expect" << "send_data.5.qml";
594     QTest::newRow("PUT") << "send_data.6.expect" << "send_data.6.qml";
595     QTest::newRow("Correct content-type - no charset") << "send_data.1.expect" << "send_data.7.qml";
596 }
597
598 // Test abort() has no effect in unsent state
599 void tst_qdeclarativexmlhttprequest::abort_unsent()
600 {
601     QDeclarativeComponent component(&engine, TEST_FILE("abort_unsent.qml"));
602     QObject *object = component.beginCreate(engine.rootContext());
603     QVERIFY(object != 0);
604     object->setProperty("url", "testdocument.html");
605     component.completeCreate();
606
607     QCOMPARE(object->property("readyState").toBool(), true);
608     QCOMPARE(object->property("openedState").toBool(), true);
609     QCOMPARE(object->property("status").toBool(), true);
610     QCOMPARE(object->property("statusText").toBool(), true);
611     QCOMPARE(object->property("responseText").toBool(), true);
612     QCOMPARE(object->property("responseXML").toBool(), true);
613
614     QTRY_VERIFY(object->property("dataOK").toBool() == true);
615
616     delete object;
617 }
618
619 // Test abort() cancels an open (but unsent) request
620 void tst_qdeclarativexmlhttprequest::abort_opened()
621 {
622     QDeclarativeComponent component(&engine, TEST_FILE("abort_opened.qml"));
623     QObject *object = component.beginCreate(engine.rootContext());
624     QVERIFY(object != 0);
625     object->setProperty("url", "testdocument.html");
626     component.completeCreate();
627
628     QCOMPARE(object->property("readyState").toBool(), true);
629     QCOMPARE(object->property("openedState").toBool(), true);
630     QCOMPARE(object->property("status").toBool(), true);
631     QCOMPARE(object->property("statusText").toBool(), true);
632     QCOMPARE(object->property("responseText").toBool(), true);
633     QCOMPARE(object->property("responseXML").toBool(), true);
634
635     QTRY_VERIFY(object->property("dataOK").toBool() == true);
636
637     delete object;
638 }
639
640 // Test abort() aborts in progress send
641 void tst_qdeclarativexmlhttprequest::abort()
642 {
643     TestHTTPServer server(SERVER_PORT);
644     QVERIFY(server.isValid());
645     QVERIFY(server.wait(TEST_FILE("abort.expect"), 
646                         TEST_FILE("abort.reply"), 
647                         TEST_FILE("testdocument.html")));
648
649     QDeclarativeComponent component(&engine, TEST_FILE("abort.qml"));
650     QObject *object = component.beginCreate(engine.rootContext());
651     QVERIFY(object != 0);
652     object->setProperty("urlDummy", "http://127.0.0.1:14449/testdocument.html");
653     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
654     component.completeCreate();
655
656     QCOMPARE(object->property("seenDone").toBool(), true);
657     QCOMPARE(object->property("didNotSeeUnsent").toBool(), true);
658     QCOMPARE(object->property("endStateUnsent").toBool(), true);
659
660     QTRY_VERIFY(object->property("dataOK").toBool() == true);
661
662     delete object;
663 }
664
665 void tst_qdeclarativexmlhttprequest::getResponseHeader()
666 {
667     QDeclarativeEngine engine; // Avoid cookie contamination
668
669     TestHTTPServer server(SERVER_PORT);
670     QVERIFY(server.isValid());
671     QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), 
672                         TEST_FILE("getResponseHeader.reply"), 
673                         TEST_FILE("testdocument.html")));
674
675
676     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader.qml"));
677     QObject *object = component.beginCreate(engine.rootContext());
678     QVERIFY(object != 0);
679     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
680     component.completeCreate();
681
682     QCOMPARE(object->property("unsentException").toBool(), true);
683     QCOMPARE(object->property("openedException").toBool(), true);
684     QCOMPARE(object->property("readyState").toBool(), true);
685     QCOMPARE(object->property("openedState").toBool(), true);
686
687     QTRY_VERIFY(object->property("dataOK").toBool() == true);
688
689     QCOMPARE(object->property("headersReceivedState").toBool(), true);
690     QCOMPARE(object->property("headersReceivedNullHeader").toBool(), true);
691     QCOMPARE(object->property("headersReceivedValidHeader").toBool(), true);
692     QCOMPARE(object->property("headersReceivedMultiValidHeader").toBool(), true);
693     QCOMPARE(object->property("headersReceivedCookieHeader").toBool(), true);
694
695     QCOMPARE(object->property("doneState").toBool(), true);
696     QCOMPARE(object->property("doneNullHeader").toBool(), true);
697     QCOMPARE(object->property("doneValidHeader").toBool(), true);
698     QCOMPARE(object->property("doneMultiValidHeader").toBool(), true);
699     QCOMPARE(object->property("doneCookieHeader").toBool(), true);
700
701     delete object;
702 }
703
704 // Test getResponseHeader throws an exception in an invalid state
705 void tst_qdeclarativexmlhttprequest::getResponseHeader_unsent()
706 {
707     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_unsent.qml"));
708     QObject *object = component.create();
709     QVERIFY(object != 0);
710
711     QCOMPARE(object->property("test").toBool(), true);
712
713     delete object;
714 }
715
716 // Test getResponseHeader throws an exception in an invalid state
717 void tst_qdeclarativexmlhttprequest::getResponseHeader_sent()
718 {
719     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_sent.qml"));
720     QObject *object = component.create();
721     QVERIFY(object != 0);
722
723     QCOMPARE(object->property("test").toBool(), true);
724
725     delete object;
726 }
727
728 // Invalid arg count throws exception
729 void tst_qdeclarativexmlhttprequest::getResponseHeader_args()
730 {
731     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_args.qml"));
732     QObject *object = component.create();
733     QVERIFY(object != 0);
734
735     QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
736
737     delete object;
738 }
739
740 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders()
741 {
742     QDeclarativeEngine engine; // Avoid cookie contamination
743
744     TestHTTPServer server(SERVER_PORT);
745     QVERIFY(server.isValid());
746     QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), 
747                         TEST_FILE("getResponseHeader.reply"), 
748                         TEST_FILE("testdocument.html")));
749
750     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders.qml"));
751     QObject *object = component.beginCreate(engine.rootContext());
752     QVERIFY(object != 0);
753     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
754     component.completeCreate();
755
756     QCOMPARE(object->property("unsentException").toBool(), true);
757     QCOMPARE(object->property("openedException").toBool(), true);
758     QCOMPARE(object->property("readyState").toBool(), true);
759     QCOMPARE(object->property("openedState").toBool(), true);
760
761     QTRY_VERIFY(object->property("dataOK").toBool() == true);
762
763     QCOMPARE(object->property("headersReceivedState").toBool(), true);
764     QCOMPARE(object->property("headersReceivedHeader").toBool(), true);
765
766     QCOMPARE(object->property("doneState").toBool(), true);
767     QCOMPARE(object->property("doneHeader").toBool(), true);
768
769     delete object;
770 }
771
772 // Test getAllResponseHeaders throws an exception in an invalid state
773 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_unsent()
774 {
775     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_unsent.qml"));
776     QObject *object = component.create();
777     QVERIFY(object != 0);
778
779     QCOMPARE(object->property("test").toBool(), true);
780
781     delete object;
782 }
783
784 // Test getAllResponseHeaders throws an exception in an invalid state
785 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_sent()
786 {
787     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_sent.qml"));
788     QObject *object = component.create();
789     QVERIFY(object != 0);
790
791     QCOMPARE(object->property("test").toBool(), true);
792
793     delete object;
794 }
795
796 // Invalid arg count throws exception
797 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_args()
798 {
799     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_args.qml"));
800     QObject *object = component.create();
801     QVERIFY(object != 0);
802
803     QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
804
805     delete object;
806 }
807
808 void tst_qdeclarativexmlhttprequest::status()
809 {
810     QFETCH(QUrl, replyUrl);
811     QFETCH(int, status);
812
813     TestHTTPServer server(SERVER_PORT);
814     QVERIFY(server.isValid());
815     QVERIFY(server.wait(TEST_FILE("status.expect"), 
816                         replyUrl,
817                         TEST_FILE("testdocument.html")));
818
819     QDeclarativeComponent component(&engine, TEST_FILE("status.qml"));
820     QObject *object = component.beginCreate(engine.rootContext());
821     QVERIFY(object != 0);
822     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
823     object->setProperty("expectedStatus", status);
824     component.completeCreate();
825
826     QTRY_VERIFY(object->property("dataOK").toBool() == true);
827
828     QCOMPARE(object->property("unsentException").toBool(), true);
829     QCOMPARE(object->property("openedException").toBool(), true);
830     QCOMPARE(object->property("sentException").toBool(), true);
831     QCOMPARE(object->property("headersReceived").toBool(), true);
832     QCOMPARE(object->property("loading").toBool(), true);
833     QCOMPARE(object->property("done").toBool(), true);
834     QCOMPARE(object->property("resetException").toBool(), true);
835
836     delete object;
837 }
838
839 void tst_qdeclarativexmlhttprequest::status_data()
840 {
841     QTest::addColumn<QUrl>("replyUrl");
842     QTest::addColumn<int>("status");
843
844     QTest::newRow("OK") << TEST_FILE("status.200.reply") << 200;
845     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << 404;
846 }
847
848 void tst_qdeclarativexmlhttprequest::statusText()
849 {
850     QFETCH(QUrl, replyUrl);
851     QFETCH(QString, statusText);
852
853     TestHTTPServer server(SERVER_PORT);
854     QVERIFY(server.isValid());
855     QVERIFY(server.wait(TEST_FILE("status.expect"), 
856                         replyUrl, 
857                         TEST_FILE("testdocument.html")));
858
859     QDeclarativeComponent component(&engine, TEST_FILE("statusText.qml"));
860     QObject *object = component.beginCreate(engine.rootContext());
861     QVERIFY(object != 0);
862     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
863     object->setProperty("expectedStatus", statusText);
864     component.completeCreate();
865
866     QTRY_VERIFY(object->property("dataOK").toBool() == true);
867
868     QCOMPARE(object->property("unsentException").toBool(), true);
869     QCOMPARE(object->property("openedException").toBool(), true);
870     QCOMPARE(object->property("sentException").toBool(), true);
871     QCOMPARE(object->property("headersReceived").toBool(), true);
872     QCOMPARE(object->property("loading").toBool(), true);
873     QCOMPARE(object->property("done").toBool(), true);
874     QCOMPARE(object->property("resetException").toBool(), true);
875
876     delete object;
877 }
878
879 void tst_qdeclarativexmlhttprequest::statusText_data()
880 {
881     QTest::addColumn<QUrl>("replyUrl");
882     QTest::addColumn<QString>("statusText");
883
884     QTest::newRow("OK") << TEST_FILE("status.200.reply") << "OK";
885     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << "Document not found";
886 }
887
888 void tst_qdeclarativexmlhttprequest::responseText()
889 {
890     QFETCH(QUrl, replyUrl);
891     QFETCH(QUrl, bodyUrl);
892     QFETCH(QString, responseText);
893
894     TestHTTPServer server(SERVER_PORT);
895     QVERIFY(server.isValid());
896     QVERIFY(server.wait(TEST_FILE("status.expect"), 
897                         replyUrl, 
898                         bodyUrl));
899
900     QDeclarativeComponent component(&engine, TEST_FILE("responseText.qml"));
901     QObject *object = component.beginCreate(engine.rootContext());
902     QVERIFY(object != 0);
903     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
904     object->setProperty("expectedText", responseText);
905     component.completeCreate();
906
907     QTRY_VERIFY(object->property("dataOK").toBool() == true);
908
909     QCOMPARE(object->property("unsent").toBool(), true);
910     QCOMPARE(object->property("opened").toBool(), true);
911     QCOMPARE(object->property("sent").toBool(), true);
912     QCOMPARE(object->property("headersReceived").toBool(), true);
913     QCOMPARE(object->property("loading").toBool(), true);
914     QCOMPARE(object->property("done").toBool(), true);
915     QCOMPARE(object->property("reset").toBool(), true);
916
917     delete object;
918 }
919
920 void tst_qdeclarativexmlhttprequest::responseText_data()
921 {
922     QTest::addColumn<QUrl>("replyUrl");
923     QTest::addColumn<QUrl>("bodyUrl");
924     QTest::addColumn<QString>("responseText");
925
926     QTest::newRow("OK") << TEST_FILE("status.200.reply") << TEST_FILE("testdocument.html") << "QML Rocks!\n";
927     QTest::newRow("empty body") << TEST_FILE("status.200.reply") << QUrl() << "";
928     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << TEST_FILE("testdocument.html") << "";
929 }
930
931 void tst_qdeclarativexmlhttprequest::nonUtf8()
932 {
933     QFETCH(QString, fileName);
934     QFETCH(QString, responseText);
935     QFETCH(QString, xmlRootNodeValue);
936
937     QDeclarativeComponent component(&engine, TEST_FILE("utf16.qml"));
938     QObject *object = component.create();
939     QVERIFY(object != 0);
940
941     object->setProperty("fileName", fileName);
942     QMetaObject::invokeMethod(object, "startRequest");
943
944     QTRY_VERIFY(object->property("dataOK").toBool() == true);
945     
946     QCOMPARE(object->property("responseText").toString(), responseText);
947
948     if (!xmlRootNodeValue.isEmpty()) {
949         QString rootNodeValue = object->property("responseXmlRootNodeValue").toString();
950         QCOMPARE(rootNodeValue, xmlRootNodeValue);
951     }
952
953     delete object;
954 }
955
956 void tst_qdeclarativexmlhttprequest::nonUtf8_data()
957 {
958     QTest::addColumn<QString>("fileName");
959     QTest::addColumn<QString>("responseText");
960     QTest::addColumn<QString>("xmlRootNodeValue");
961
962     QString uc;
963     uc.resize(3);
964     uc[0] = QChar(0x10e3);
965     uc[1] = QChar(' ');
966     uc[2] = QChar(0x03a3);
967
968     QTest::newRow("responseText") << "utf16.html" << uc + '\n' << "";
969     QTest::newRow("responseXML") << "utf16.xml" << "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone='yes'?>\n<root>\n" + uc + "\n</root>\n" << QString('\n' + uc + '\n');
970 }
971
972 // Test that calling hte XMLHttpRequest methods on a non-XMLHttpRequest object
973 // throws an exception
974 void tst_qdeclarativexmlhttprequest::invalidMethodUsage()
975 {
976     QDeclarativeComponent component(&engine, TEST_FILE("invalidMethodUsage.qml"));
977     QObject *object = component.create();
978     QVERIFY(object != 0);
979
980     QCOMPARE(object->property("readyState").toBool(), true);
981     QCOMPARE(object->property("status").toBool(), true);
982     QCOMPARE(object->property("statusText").toBool(), true);
983     QCOMPARE(object->property("responseText").toBool(), true);
984     QCOMPARE(object->property("responseXML").toBool(), true);
985
986     QCOMPARE(object->property("open").toBool(), true);
987     QCOMPARE(object->property("setRequestHeader").toBool(), true);
988     QCOMPARE(object->property("send").toBool(), true);
989     QCOMPARE(object->property("abort").toBool(), true);
990     QCOMPARE(object->property("getResponseHeader").toBool(), true);
991     QCOMPARE(object->property("getAllResponseHeaders").toBool(), true);
992
993     delete object;
994 }
995
996 // Test that XMLHttpRequest transparently redirects
997 void tst_qdeclarativexmlhttprequest::redirects()
998 {
999     {
1000         TestHTTPServer server(SERVER_PORT);
1001         QVERIFY(server.isValid());
1002         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirecttarget.html");
1003         server.serveDirectory(SRCDIR "/data");
1004
1005         QDeclarativeComponent component(&engine, TEST_FILE("redirects.qml"));
1006         QObject *object = component.beginCreate(engine.rootContext());
1007         QVERIFY(object != 0);
1008         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
1009         object->setProperty("expectedText", "");
1010         component.completeCreate();
1011
1012         QTRY_VERIFY(object->property("done").toBool() == true);
1013         QCOMPARE(object->property("dataOK").toBool(), true);
1014
1015         delete object;
1016     }
1017
1018     {
1019         TestHTTPServer server(SERVER_PORT);
1020         QVERIFY(server.isValid());
1021         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirectmissing.html");
1022         server.serveDirectory(SRCDIR "/data");
1023
1024         QDeclarativeComponent component(&engine, TEST_FILE("redirectError.qml"));
1025         QObject *object = component.beginCreate(engine.rootContext());
1026         QVERIFY(object != 0);
1027         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
1028         object->setProperty("expectedText", "");
1029         component.completeCreate();
1030
1031         QTRY_VERIFY(object->property("done").toBool() == true);
1032         QCOMPARE(object->property("dataOK").toBool(), true);
1033
1034         delete object;
1035     }
1036
1037     {
1038         TestHTTPServer server(SERVER_PORT);
1039         QVERIFY(server.isValid());
1040         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirect.html");
1041         server.serveDirectory(SRCDIR "/data");
1042
1043         QDeclarativeComponent component(&engine, TEST_FILE("redirectRecur.qml"));
1044         QObject *object = component.beginCreate(engine.rootContext());
1045         QVERIFY(object != 0);
1046         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
1047         object->setProperty("expectedText", "");
1048         component.completeCreate();
1049
1050         for (int ii = 0; ii < 60; ++ii) { 
1051             if (object->property("done").toBool()) break; 
1052             QTest::qWait(50); 
1053         } 
1054         QVERIFY(object->property("done").toBool() == true);
1055
1056         QCOMPARE(object->property("dataOK").toBool(), true);
1057
1058         delete object;
1059     }
1060 }
1061
1062 void tst_qdeclarativexmlhttprequest::responseXML_invalid()
1063 {
1064     QDeclarativeComponent component(&engine, TEST_FILE("responseXML_invalid.qml"));
1065     QObject *object = component.create();
1066     QVERIFY(object != 0);
1067
1068     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1069
1070     QCOMPARE(object->property("xmlNull").toBool(), true);
1071
1072     delete object;
1073 }
1074
1075 // Test the Document DOM element
1076 void tst_qdeclarativexmlhttprequest::document()
1077 {
1078     QDeclarativeComponent component(&engine, TEST_FILE("document.qml"));
1079     QObject *object = component.create();
1080     QVERIFY(object != 0);
1081
1082     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1083
1084     QCOMPARE(object->property("xmlTest").toBool(), true);
1085
1086     delete object;
1087 }
1088
1089 // Test the Element DOM element
1090 void tst_qdeclarativexmlhttprequest::element()
1091 {
1092     QDeclarativeComponent component(&engine, TEST_FILE("element.qml"));
1093     QObject *object = component.create();
1094     QVERIFY(object != 0);
1095
1096     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1097
1098     QCOMPARE(object->property("xmlTest").toBool(), true);
1099
1100     delete object;
1101 }
1102
1103 // Test the Attr DOM element
1104 void tst_qdeclarativexmlhttprequest::attr()
1105 {
1106     QDeclarativeComponent component(&engine, TEST_FILE("attr.qml"));
1107     QObject *object = component.create();
1108     QVERIFY(object != 0);
1109
1110     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1111
1112     QCOMPARE(object->property("xmlTest").toBool(), true);
1113
1114     delete object;
1115 }
1116
1117 // Test the Text DOM element
1118 void tst_qdeclarativexmlhttprequest::text()
1119 {
1120     QDeclarativeComponent component(&engine, TEST_FILE("text.qml"));
1121     QObject *object = component.create();
1122     QVERIFY(object != 0);
1123
1124     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1125
1126     QCOMPARE(object->property("xmlTest").toBool(), true);
1127
1128     delete object;
1129 }
1130
1131 // Test the CDataSection DOM element
1132 void tst_qdeclarativexmlhttprequest::cdata()
1133 {
1134     QDeclarativeComponent component(&engine, TEST_FILE("cdata.qml"));
1135     QObject *object = component.create();
1136     QVERIFY(object != 0);
1137
1138     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1139
1140     QCOMPARE(object->property("xmlTest").toBool(), true);
1141
1142     delete object;
1143 }
1144
1145 QTEST_MAIN(tst_qdeclarativexmlhttprequest)
1146
1147 #include "tst_qdeclarativexmlhttprequest.moc"