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