Initial import from the monolithic Qt.
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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 send for a GET or HEAD ignores 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_PUT.expect"), 
526                             TEST_FILE("send_ignoreData.reply"), 
527                             TEST_FILE("testdocument.html")));
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 // Test that send()'ing data works
543 void tst_qdeclarativexmlhttprequest::send_withdata()
544 {
545     QFETCH(QString, file_expected);
546     QFETCH(QString, file_qml);
547
548     TestHTTPServer server(SERVER_PORT);
549     QVERIFY(server.isValid());
550     QVERIFY(server.wait(TEST_FILE(file_expected), 
551                         TEST_FILE("send_data.reply"), 
552                         TEST_FILE("testdocument.html")));
553
554     QDeclarativeComponent component(&engine, TEST_FILE(file_qml));
555     QObject *object = component.beginCreate(engine.rootContext());
556     QVERIFY(object != 0);
557     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
558     component.completeCreate();
559
560     QTRY_VERIFY(object->property("dataOK").toBool() == true);
561
562     delete object;
563 }
564
565 void tst_qdeclarativexmlhttprequest::send_withdata_data()
566 {
567     QTest::addColumn<QString>("file_expected");
568     QTest::addColumn<QString>("file_qml");
569
570     QTest::newRow("No content-type") << "send_data.1.expect" << "send_data.1.qml";
571     QTest::newRow("Correct content-type") << "send_data.1.expect" << "send_data.2.qml";
572     QTest::newRow("Incorrect content-type") << "send_data.1.expect" << "send_data.3.qml";
573     QTest::newRow("Correct content-type - out of order") << "send_data.4.expect" << "send_data.4.qml";
574     QTest::newRow("Incorrect content-type - out of order") << "send_data.4.expect" << "send_data.5.qml";
575     QTest::newRow("PUT") << "send_data.6.expect" << "send_data.6.qml";
576     QTest::newRow("Correct content-type - no charset") << "send_data.1.expect" << "send_data.7.qml";
577 }
578
579 // Test abort() has no effect in unsent state
580 void tst_qdeclarativexmlhttprequest::abort_unsent()
581 {
582     QDeclarativeComponent component(&engine, TEST_FILE("abort_unsent.qml"));
583     QObject *object = component.beginCreate(engine.rootContext());
584     QVERIFY(object != 0);
585     object->setProperty("url", "testdocument.html");
586     component.completeCreate();
587
588     QCOMPARE(object->property("readyState").toBool(), true);
589     QCOMPARE(object->property("openedState").toBool(), true);
590     QCOMPARE(object->property("status").toBool(), true);
591     QCOMPARE(object->property("statusText").toBool(), true);
592     QCOMPARE(object->property("responseText").toBool(), true);
593     QCOMPARE(object->property("responseXML").toBool(), true);
594
595     QTRY_VERIFY(object->property("dataOK").toBool() == true);
596
597     delete object;
598 }
599
600 // Test abort() cancels an open (but unsent) request
601 void tst_qdeclarativexmlhttprequest::abort_opened()
602 {
603     QDeclarativeComponent component(&engine, TEST_FILE("abort_opened.qml"));
604     QObject *object = component.beginCreate(engine.rootContext());
605     QVERIFY(object != 0);
606     object->setProperty("url", "testdocument.html");
607     component.completeCreate();
608
609     QCOMPARE(object->property("readyState").toBool(), true);
610     QCOMPARE(object->property("openedState").toBool(), true);
611     QCOMPARE(object->property("status").toBool(), true);
612     QCOMPARE(object->property("statusText").toBool(), true);
613     QCOMPARE(object->property("responseText").toBool(), true);
614     QCOMPARE(object->property("responseXML").toBool(), true);
615
616     QTRY_VERIFY(object->property("dataOK").toBool() == true);
617
618     delete object;
619 }
620
621 // Test abort() aborts in progress send
622 void tst_qdeclarativexmlhttprequest::abort()
623 {
624     TestHTTPServer server(SERVER_PORT);
625     QVERIFY(server.isValid());
626     QVERIFY(server.wait(TEST_FILE("abort.expect"), 
627                         TEST_FILE("abort.reply"), 
628                         TEST_FILE("testdocument.html")));
629
630     QDeclarativeComponent component(&engine, TEST_FILE("abort.qml"));
631     QObject *object = component.beginCreate(engine.rootContext());
632     QVERIFY(object != 0);
633     object->setProperty("urlDummy", "http://127.0.0.1:14449/testdocument.html");
634     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
635     component.completeCreate();
636
637     QCOMPARE(object->property("seenDone").toBool(), true);
638     QCOMPARE(object->property("didNotSeeUnsent").toBool(), true);
639     QCOMPARE(object->property("endStateUnsent").toBool(), true);
640
641     QTRY_VERIFY(object->property("dataOK").toBool() == true);
642
643     delete object;
644 }
645
646 void tst_qdeclarativexmlhttprequest::getResponseHeader()
647 {
648     QDeclarativeEngine engine; // Avoid cookie contamination
649
650     TestHTTPServer server(SERVER_PORT);
651     QVERIFY(server.isValid());
652     QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), 
653                         TEST_FILE("getResponseHeader.reply"), 
654                         TEST_FILE("testdocument.html")));
655
656
657     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader.qml"));
658     QObject *object = component.beginCreate(engine.rootContext());
659     QVERIFY(object != 0);
660     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
661     component.completeCreate();
662
663     QCOMPARE(object->property("unsentException").toBool(), true);
664     QCOMPARE(object->property("openedException").toBool(), true);
665     QCOMPARE(object->property("readyState").toBool(), true);
666     QCOMPARE(object->property("openedState").toBool(), true);
667
668     QTRY_VERIFY(object->property("dataOK").toBool() == true);
669
670     QCOMPARE(object->property("headersReceivedState").toBool(), true);
671     QCOMPARE(object->property("headersReceivedNullHeader").toBool(), true);
672     QCOMPARE(object->property("headersReceivedValidHeader").toBool(), true);
673     QCOMPARE(object->property("headersReceivedMultiValidHeader").toBool(), true);
674     QCOMPARE(object->property("headersReceivedCookieHeader").toBool(), true);
675
676     QCOMPARE(object->property("doneState").toBool(), true);
677     QCOMPARE(object->property("doneNullHeader").toBool(), true);
678     QCOMPARE(object->property("doneValidHeader").toBool(), true);
679     QCOMPARE(object->property("doneMultiValidHeader").toBool(), true);
680     QCOMPARE(object->property("doneCookieHeader").toBool(), true);
681
682     delete object;
683 }
684
685 // Test getResponseHeader throws an exception in an invalid state
686 void tst_qdeclarativexmlhttprequest::getResponseHeader_unsent()
687 {
688     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_unsent.qml"));
689     QObject *object = component.create();
690     QVERIFY(object != 0);
691
692     QCOMPARE(object->property("test").toBool(), true);
693
694     delete object;
695 }
696
697 // Test getResponseHeader throws an exception in an invalid state
698 void tst_qdeclarativexmlhttprequest::getResponseHeader_sent()
699 {
700     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_sent.qml"));
701     QObject *object = component.create();
702     QVERIFY(object != 0);
703
704     QCOMPARE(object->property("test").toBool(), true);
705
706     delete object;
707 }
708
709 // Invalid arg count throws exception
710 void tst_qdeclarativexmlhttprequest::getResponseHeader_args()
711 {
712     QDeclarativeComponent component(&engine, TEST_FILE("getResponseHeader_args.qml"));
713     QObject *object = component.create();
714     QVERIFY(object != 0);
715
716     QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
717
718     delete object;
719 }
720
721 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders()
722 {
723     QDeclarativeEngine engine; // Avoid cookie contamination
724
725     TestHTTPServer server(SERVER_PORT);
726     QVERIFY(server.isValid());
727     QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), 
728                         TEST_FILE("getResponseHeader.reply"), 
729                         TEST_FILE("testdocument.html")));
730
731     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders.qml"));
732     QObject *object = component.beginCreate(engine.rootContext());
733     QVERIFY(object != 0);
734     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
735     component.completeCreate();
736
737     QCOMPARE(object->property("unsentException").toBool(), true);
738     QCOMPARE(object->property("openedException").toBool(), true);
739     QCOMPARE(object->property("readyState").toBool(), true);
740     QCOMPARE(object->property("openedState").toBool(), true);
741
742     QTRY_VERIFY(object->property("dataOK").toBool() == true);
743
744     QCOMPARE(object->property("headersReceivedState").toBool(), true);
745     QCOMPARE(object->property("headersReceivedHeader").toBool(), true);
746
747     QCOMPARE(object->property("doneState").toBool(), true);
748     QCOMPARE(object->property("doneHeader").toBool(), true);
749
750     delete object;
751 }
752
753 // Test getAllResponseHeaders throws an exception in an invalid state
754 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_unsent()
755 {
756     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_unsent.qml"));
757     QObject *object = component.create();
758     QVERIFY(object != 0);
759
760     QCOMPARE(object->property("test").toBool(), true);
761
762     delete object;
763 }
764
765 // Test getAllResponseHeaders throws an exception in an invalid state
766 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_sent()
767 {
768     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_sent.qml"));
769     QObject *object = component.create();
770     QVERIFY(object != 0);
771
772     QCOMPARE(object->property("test").toBool(), true);
773
774     delete object;
775 }
776
777 // Invalid arg count throws exception
778 void tst_qdeclarativexmlhttprequest::getAllResponseHeaders_args()
779 {
780     QDeclarativeComponent component(&engine, TEST_FILE("getAllResponseHeaders_args.qml"));
781     QObject *object = component.create();
782     QVERIFY(object != 0);
783
784     QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
785
786     delete object;
787 }
788
789 void tst_qdeclarativexmlhttprequest::status()
790 {
791     QFETCH(QUrl, replyUrl);
792     QFETCH(int, status);
793
794     TestHTTPServer server(SERVER_PORT);
795     QVERIFY(server.isValid());
796     QVERIFY(server.wait(TEST_FILE("status.expect"), 
797                         replyUrl,
798                         TEST_FILE("testdocument.html")));
799
800     QDeclarativeComponent component(&engine, TEST_FILE("status.qml"));
801     QObject *object = component.beginCreate(engine.rootContext());
802     QVERIFY(object != 0);
803     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
804     object->setProperty("expectedStatus", status);
805     component.completeCreate();
806
807     QTRY_VERIFY(object->property("dataOK").toBool() == true);
808
809     QCOMPARE(object->property("unsentException").toBool(), true);
810     QCOMPARE(object->property("openedException").toBool(), true);
811     QCOMPARE(object->property("sentException").toBool(), true);
812     QCOMPARE(object->property("headersReceived").toBool(), true);
813     QCOMPARE(object->property("loading").toBool(), true);
814     QCOMPARE(object->property("done").toBool(), true);
815     QCOMPARE(object->property("resetException").toBool(), true);
816
817     delete object;
818 }
819
820 void tst_qdeclarativexmlhttprequest::status_data()
821 {
822     QTest::addColumn<QUrl>("replyUrl");
823     QTest::addColumn<int>("status");
824
825     QTest::newRow("OK") << TEST_FILE("status.200.reply") << 200;
826     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << 404;
827 }
828
829 void tst_qdeclarativexmlhttprequest::statusText()
830 {
831     QFETCH(QUrl, replyUrl);
832     QFETCH(QString, statusText);
833
834     TestHTTPServer server(SERVER_PORT);
835     QVERIFY(server.isValid());
836     QVERIFY(server.wait(TEST_FILE("status.expect"), 
837                         replyUrl, 
838                         TEST_FILE("testdocument.html")));
839
840     QDeclarativeComponent component(&engine, TEST_FILE("statusText.qml"));
841     QObject *object = component.beginCreate(engine.rootContext());
842     QVERIFY(object != 0);
843     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
844     object->setProperty("expectedStatus", statusText);
845     component.completeCreate();
846
847     QTRY_VERIFY(object->property("dataOK").toBool() == true);
848
849     QCOMPARE(object->property("unsentException").toBool(), true);
850     QCOMPARE(object->property("openedException").toBool(), true);
851     QCOMPARE(object->property("sentException").toBool(), true);
852     QCOMPARE(object->property("headersReceived").toBool(), true);
853     QCOMPARE(object->property("loading").toBool(), true);
854     QCOMPARE(object->property("done").toBool(), true);
855     QCOMPARE(object->property("resetException").toBool(), true);
856
857     delete object;
858 }
859
860 void tst_qdeclarativexmlhttprequest::statusText_data()
861 {
862     QTest::addColumn<QUrl>("replyUrl");
863     QTest::addColumn<QString>("statusText");
864
865     QTest::newRow("OK") << TEST_FILE("status.200.reply") << "OK";
866     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << "Document not found";
867 }
868
869 void tst_qdeclarativexmlhttprequest::responseText()
870 {
871     QFETCH(QUrl, replyUrl);
872     QFETCH(QUrl, bodyUrl);
873     QFETCH(QString, responseText);
874
875     TestHTTPServer server(SERVER_PORT);
876     QVERIFY(server.isValid());
877     QVERIFY(server.wait(TEST_FILE("status.expect"), 
878                         replyUrl, 
879                         bodyUrl));
880
881     QDeclarativeComponent component(&engine, TEST_FILE("responseText.qml"));
882     QObject *object = component.beginCreate(engine.rootContext());
883     QVERIFY(object != 0);
884     object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
885     object->setProperty("expectedText", responseText);
886     component.completeCreate();
887
888     QTRY_VERIFY(object->property("dataOK").toBool() == true);
889
890     QCOMPARE(object->property("unsent").toBool(), true);
891     QCOMPARE(object->property("opened").toBool(), true);
892     QCOMPARE(object->property("sent").toBool(), true);
893     QCOMPARE(object->property("headersReceived").toBool(), true);
894     QCOMPARE(object->property("loading").toBool(), true);
895     QCOMPARE(object->property("done").toBool(), true);
896     QCOMPARE(object->property("reset").toBool(), true);
897
898     delete object;
899 }
900
901 void tst_qdeclarativexmlhttprequest::responseText_data()
902 {
903     QTest::addColumn<QUrl>("replyUrl");
904     QTest::addColumn<QUrl>("bodyUrl");
905     QTest::addColumn<QString>("responseText");
906
907     QTest::newRow("OK") << TEST_FILE("status.200.reply") << TEST_FILE("testdocument.html") << "QML Rocks!\n";
908     QTest::newRow("empty body") << TEST_FILE("status.200.reply") << QUrl() << "";
909     QTest::newRow("Not Found") << TEST_FILE("status.404.reply") << TEST_FILE("testdocument.html") << "";
910 }
911
912 void tst_qdeclarativexmlhttprequest::nonUtf8()
913 {
914     QFETCH(QString, fileName);
915     QFETCH(QString, responseText);
916     QFETCH(QString, xmlRootNodeValue);
917
918     QDeclarativeComponent component(&engine, TEST_FILE("utf16.qml"));
919     QObject *object = component.create();
920     QVERIFY(object != 0);
921
922     object->setProperty("fileName", fileName);
923     QMetaObject::invokeMethod(object, "startRequest");
924
925     QTRY_VERIFY(object->property("dataOK").toBool() == true);
926     
927     QCOMPARE(object->property("responseText").toString(), responseText);
928
929     if (!xmlRootNodeValue.isEmpty()) {
930         QString rootNodeValue = object->property("responseXmlRootNodeValue").toString();
931         QCOMPARE(rootNodeValue, xmlRootNodeValue);
932     }
933
934     delete object;
935 }
936
937 void tst_qdeclarativexmlhttprequest::nonUtf8_data()
938 {
939     QTest::addColumn<QString>("fileName");
940     QTest::addColumn<QString>("responseText");
941     QTest::addColumn<QString>("xmlRootNodeValue");
942
943     QString uc;
944     uc.resize(3);
945     uc[0] = QChar(0x10e3);
946     uc[1] = QChar(' ');
947     uc[2] = QChar(0x03a3);
948
949     QTest::newRow("responseText") << "utf16.html" << uc + '\n' << "";
950     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');
951 }
952
953 // Test that calling hte XMLHttpRequest methods on a non-XMLHttpRequest object
954 // throws an exception
955 void tst_qdeclarativexmlhttprequest::invalidMethodUsage()
956 {
957     QDeclarativeComponent component(&engine, TEST_FILE("invalidMethodUsage.qml"));
958     QObject *object = component.create();
959     QVERIFY(object != 0);
960
961     QCOMPARE(object->property("onreadystatechange").toBool(), true);
962     QCOMPARE(object->property("readyState").toBool(), true);
963     QCOMPARE(object->property("status").toBool(), true);
964     QCOMPARE(object->property("statusText").toBool(), true);
965     QCOMPARE(object->property("responseText").toBool(), true);
966     QCOMPARE(object->property("responseXML").toBool(), true);
967
968     QCOMPARE(object->property("open").toBool(), true);
969     QCOMPARE(object->property("setRequestHeader").toBool(), true);
970     QCOMPARE(object->property("send").toBool(), true);
971     QCOMPARE(object->property("abort").toBool(), true);
972     QCOMPARE(object->property("getResponseHeader").toBool(), true);
973     QCOMPARE(object->property("getAllResponseHeaders").toBool(), true);
974
975     delete object;
976 }
977
978 // Test that XMLHttpRequest transparently redirects
979 void tst_qdeclarativexmlhttprequest::redirects()
980 {
981     {
982         TestHTTPServer server(SERVER_PORT);
983         QVERIFY(server.isValid());
984         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirecttarget.html");
985         server.serveDirectory(SRCDIR "/data");
986
987         QDeclarativeComponent component(&engine, TEST_FILE("redirects.qml"));
988         QObject *object = component.beginCreate(engine.rootContext());
989         QVERIFY(object != 0);
990         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
991         object->setProperty("expectedText", "");
992         component.completeCreate();
993
994         QTRY_VERIFY(object->property("done").toBool() == true);
995         QCOMPARE(object->property("dataOK").toBool(), true);
996
997         delete object;
998     }
999
1000     {
1001         TestHTTPServer server(SERVER_PORT);
1002         QVERIFY(server.isValid());
1003         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirectmissing.html");
1004         server.serveDirectory(SRCDIR "/data");
1005
1006         QDeclarativeComponent component(&engine, TEST_FILE("redirectError.qml"));
1007         QObject *object = component.beginCreate(engine.rootContext());
1008         QVERIFY(object != 0);
1009         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
1010         object->setProperty("expectedText", "");
1011         component.completeCreate();
1012
1013         QTRY_VERIFY(object->property("done").toBool() == true);
1014         QCOMPARE(object->property("dataOK").toBool(), true);
1015
1016         delete object;
1017     }
1018
1019     {
1020         TestHTTPServer server(SERVER_PORT);
1021         QVERIFY(server.isValid());
1022         server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirect.html");
1023         server.serveDirectory(SRCDIR "/data");
1024
1025         QDeclarativeComponent component(&engine, TEST_FILE("redirectRecur.qml"));
1026         QObject *object = component.beginCreate(engine.rootContext());
1027         QVERIFY(object != 0);
1028         object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
1029         object->setProperty("expectedText", "");
1030         component.completeCreate();
1031
1032         for (int ii = 0; ii < 60; ++ii) { 
1033             if (object->property("done").toBool()) break; 
1034             QTest::qWait(50); 
1035         } 
1036         QVERIFY(object->property("done").toBool() == true);
1037
1038         QCOMPARE(object->property("dataOK").toBool(), true);
1039
1040         delete object;
1041     }
1042 }
1043
1044 void tst_qdeclarativexmlhttprequest::responseXML_invalid()
1045 {
1046     QDeclarativeComponent component(&engine, TEST_FILE("responseXML_invalid.qml"));
1047     QObject *object = component.create();
1048     QVERIFY(object != 0);
1049
1050     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1051
1052     QCOMPARE(object->property("xmlNull").toBool(), true);
1053
1054     delete object;
1055 }
1056
1057 // Test the Document DOM element
1058 void tst_qdeclarativexmlhttprequest::document()
1059 {
1060     QDeclarativeComponent component(&engine, TEST_FILE("document.qml"));
1061     QObject *object = component.create();
1062     QVERIFY(object != 0);
1063
1064     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1065
1066     QCOMPARE(object->property("xmlTest").toBool(), true);
1067
1068     delete object;
1069 }
1070
1071 // Test the Element DOM element
1072 void tst_qdeclarativexmlhttprequest::element()
1073 {
1074     QDeclarativeComponent component(&engine, TEST_FILE("element.qml"));
1075     QObject *object = component.create();
1076     QVERIFY(object != 0);
1077
1078     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1079
1080     QCOMPARE(object->property("xmlTest").toBool(), true);
1081
1082     delete object;
1083 }
1084
1085 // Test the Attr DOM element
1086 void tst_qdeclarativexmlhttprequest::attr()
1087 {
1088     QDeclarativeComponent component(&engine, TEST_FILE("attr.qml"));
1089     QObject *object = component.create();
1090     QVERIFY(object != 0);
1091
1092     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1093
1094     QCOMPARE(object->property("xmlTest").toBool(), true);
1095
1096     delete object;
1097 }
1098
1099 // Test the Text DOM element
1100 void tst_qdeclarativexmlhttprequest::text()
1101 {
1102     QDeclarativeComponent component(&engine, TEST_FILE("text.qml"));
1103     QObject *object = component.create();
1104     QVERIFY(object != 0);
1105
1106     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1107
1108     QCOMPARE(object->property("xmlTest").toBool(), true);
1109
1110     delete object;
1111 }
1112
1113 // Test the CDataSection DOM element
1114 void tst_qdeclarativexmlhttprequest::cdata()
1115 {
1116     QDeclarativeComponent component(&engine, TEST_FILE("cdata.qml"));
1117     QObject *object = component.create();
1118     QVERIFY(object != 0);
1119
1120     QTRY_VERIFY(object->property("dataOK").toBool() == true);
1121
1122     QCOMPARE(object->property("xmlTest").toBool(), true);
1123
1124     delete object;
1125 }
1126
1127 QTEST_MAIN(tst_qdeclarativexmlhttprequest)
1128
1129 #include "tst_qdeclarativexmlhttprequest.moc"