1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <qtest.h> |
30 | #include <QQmlEngine> |
31 | #include <QQmlComponent> |
32 | #include <QDebug> |
33 | #include <QScopedPointer> |
34 | #include <QNetworkCookieJar> |
35 | #include <QThread> |
36 | #include <QMutex> |
37 | #include <QWaitCondition> |
38 | #include <QTemporaryFile> |
39 | |
40 | #if QT_CONFIG(process) |
41 | #include <QProcess> |
42 | #include <QProcessEnvironment> |
43 | #endif |
44 | |
45 | #include "testhttpserver.h" |
46 | #include "../../shared/util.h" |
47 | |
48 | class tst_qqmlxmlhttprequest : public QQmlDataTest |
49 | { |
50 | Q_OBJECT |
51 | public: |
52 | tst_qqmlxmlhttprequest() {} |
53 | |
54 | private slots: |
55 | void initTestCase(); |
56 | |
57 | void domExceptionCodes(); |
58 | void callbackException(); |
59 | void callbackException_data(); |
60 | void staticStateValues(); |
61 | void instanceStateValues(); |
62 | void constructor(); |
63 | void defaultState(); |
64 | void open(); |
65 | void open_data(); |
66 | void open_invalid_method(); |
67 | void open_sync(); |
68 | void open_arg_count(); |
69 | void setRequestHeader(); |
70 | void setRequestHeader_caseInsensitive(); |
71 | void setRequestHeader_unsent(); |
72 | void setRequestHeader_illegalName_data(); |
73 | void setRequestHeader_illegalName(); |
74 | void setRequestHeader_sent(); |
75 | void setRequestHeader_args(); |
76 | void send_unsent(); |
77 | void send_alreadySent(); |
78 | void send_ignoreData(); |
79 | void send_withdata(); |
80 | void send_withdata_data(); |
81 | void send_options(); |
82 | void send_options_data(); |
83 | void send_patch(); |
84 | void abort(); |
85 | void abort_unsent(); |
86 | void abort_opened(); |
87 | void getResponseHeader(); |
88 | void getResponseHeader_unsent(); |
89 | void getResponseHeader_sent(); |
90 | void getResponseHeader_args(); |
91 | void getAllResponseHeaders(); |
92 | void getAllResponseHeaders_unsent(); |
93 | void getAllResponseHeaders_sent(); |
94 | void getAllResponseHeaders_args(); |
95 | void getBinaryData(); |
96 | void getJsonData(); |
97 | void status(); |
98 | void status_data(); |
99 | void statusText(); |
100 | void statusText_data(); |
101 | void responseText(); |
102 | void responseText_data(); |
103 | void responseXML_invalid(); |
104 | void invalidMethodUsage(); |
105 | void redirects(); |
106 | void nonUtf8(); |
107 | void nonUtf8_data(); |
108 | |
109 | void sendFileRequest(); |
110 | |
111 | #if QT_CONFIG(process) |
112 | void sendFileRequestNotSet(); |
113 | void sendFileRequestNoWrite(); |
114 | void sendFileRequestNoRead(); |
115 | #endif |
116 | |
117 | // WebDAV |
118 | void sendPropfind(); |
119 | void sendPropfind_data(); |
120 | |
121 | // Attributes |
122 | void document(); |
123 | void element(); |
124 | void attr(); |
125 | void text(); |
126 | void cdata(); |
127 | |
128 | void noQmlContext(); |
129 | |
130 | // Crashes |
131 | // void outstanding_request_at_shutdown(); |
132 | |
133 | // void network_errors() |
134 | // void readyState() |
135 | |
136 | void stateChangeCallingContext(); |
137 | |
138 | private: |
139 | void doFileRequest(std::function<void(QObject *component, QTemporaryFile &writeFile)> verifyFunction); |
140 | |
141 | QScopedPointer<QQmlEngine> engine; |
142 | }; |
143 | |
144 | void tst_qqmlxmlhttprequest::initTestCase() |
145 | { |
146 | QQmlDataTest::initTestCase(); |
147 | |
148 | if (!qEnvironmentVariableIsSet(varName: "TEST_CUSTOM_PERMISSIONS" )) { |
149 | qputenv(varName: "QML_XHR_ALLOW_FILE_READ" , value: "1" ); |
150 | qputenv(varName: "QML_XHR_ALLOW_FILE_WRITE" , value: "1" ); |
151 | } |
152 | |
153 | engine.reset(other: new QQmlEngine); |
154 | } |
155 | |
156 | // Test that the dom exception codes are correct |
157 | void tst_qqmlxmlhttprequest::domExceptionCodes() |
158 | { |
159 | QQmlComponent component(engine.get(), testFileUrl(fileName: "domExceptionCodes.qml" )); |
160 | QScopedPointer<QObject> object(component.create()); |
161 | QVERIFY(!object.isNull()); |
162 | |
163 | QCOMPARE(object->property("index_size_err" ).toInt(), 1); |
164 | QCOMPARE(object->property("domstring_size_err" ).toInt(), 2); |
165 | QCOMPARE(object->property("hierarchy_request_err" ).toInt(), 3); |
166 | QCOMPARE(object->property("wrong_document_err" ).toInt(), 4); |
167 | QCOMPARE(object->property("invalid_character_err" ).toInt(), 5); |
168 | QCOMPARE(object->property("no_data_allowed_err" ).toInt(), 6); |
169 | QCOMPARE(object->property("no_modification_allowed_err" ).toInt(), 7); |
170 | QCOMPARE(object->property("not_found_err" ).toInt(), 8); |
171 | QCOMPARE(object->property("not_supported_err" ).toInt(), 9); |
172 | QCOMPARE(object->property("inuse_attribute_err" ).toInt(), 10); |
173 | QCOMPARE(object->property("invalid_state_err" ).toInt(), 11); |
174 | QCOMPARE(object->property("syntax_err" ).toInt(), 12); |
175 | QCOMPARE(object->property("invalid_modification_err" ).toInt(), 13); |
176 | QCOMPARE(object->property("namespace_err" ).toInt(), 14); |
177 | QCOMPARE(object->property("invalid_access_err" ).toInt(), 15); |
178 | QCOMPARE(object->property("validation_err" ).toInt(), 16); |
179 | QCOMPARE(object->property("type_mismatch_err" ).toInt(), 17); |
180 | } |
181 | |
182 | void tst_qqmlxmlhttprequest::callbackException_data() |
183 | { |
184 | QTest::addColumn<QString>(name: "which" ); |
185 | QTest::addColumn<int>(name: "line" ); |
186 | |
187 | QTest::newRow(dataTag: "on-opened" ) << "1" << 15; |
188 | QTest::newRow(dataTag: "on-loading" ) << "3" << 15; |
189 | QTest::newRow(dataTag: "on-done" ) << "4" << 15; |
190 | } |
191 | |
192 | void tst_qqmlxmlhttprequest::callbackException() |
193 | { |
194 | // Test exception reporting for exceptions thrown at various points. |
195 | |
196 | QFETCH(QString, which); |
197 | QFETCH(int, line); |
198 | |
199 | QString expect = testFileUrl(fileName: "callbackException.qml" ).toString() + ":" +QString::number(line)+": Error: Exception from Callback" ; |
200 | QTest::ignoreMessage(type: QtWarningMsg, message: expect.toLatin1()); |
201 | |
202 | QQmlComponent component(engine.get(), testFileUrl(fileName: "callbackException.qml" )); |
203 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
204 | QVERIFY(!object.isNull()); |
205 | object->setProperty(name: "url" , value: "testdocument.html" ); |
206 | object->setProperty(name: "which" , value: which); |
207 | component.completeCreate(); |
208 | |
209 | QTRY_VERIFY(object->property("threw" ).toBool()); |
210 | } |
211 | |
212 | // Test that the state value properties on the XMLHttpRequest constructor have the correct values. |
213 | // ### WebKit does not do this, but it seems to fit the standard and QML better |
214 | void tst_qqmlxmlhttprequest::staticStateValues() |
215 | { |
216 | QQmlComponent component(engine.get(), testFileUrl(fileName: "staticStateValues.qml" )); |
217 | QScopedPointer<QObject> object(component.create()); |
218 | QVERIFY(!object.isNull()); |
219 | |
220 | QCOMPARE(object->property("unsent" ).toInt(), 0); |
221 | QCOMPARE(object->property("opened" ).toInt(), 1); |
222 | QCOMPARE(object->property("headers_received" ).toInt(), 2); |
223 | QCOMPARE(object->property("loading" ).toInt(), 3); |
224 | QCOMPARE(object->property("done" ).toInt(), 4); |
225 | } |
226 | |
227 | // Test that the state value properties on instances have the correct values. |
228 | void tst_qqmlxmlhttprequest::instanceStateValues() |
229 | { |
230 | QQmlComponent component(engine.get(), testFileUrl(fileName: "instanceStateValues.qml" )); |
231 | QScopedPointer<QObject> object(component.create()); |
232 | QVERIFY(!object.isNull()); |
233 | |
234 | QCOMPARE(object->property("unsent" ).toInt(), 0); |
235 | QCOMPARE(object->property("opened" ).toInt(), 1); |
236 | QCOMPARE(object->property("headers_received" ).toInt(), 2); |
237 | QCOMPARE(object->property("loading" ).toInt(), 3); |
238 | QCOMPARE(object->property("done" ).toInt(), 4); |
239 | } |
240 | |
241 | // Test calling constructor |
242 | void tst_qqmlxmlhttprequest::constructor() |
243 | { |
244 | QQmlComponent component(engine.get(), testFileUrl(fileName: "constructor.qml" )); |
245 | QScopedPointer<QObject> object(component.create()); |
246 | QVERIFY(!object.isNull()); |
247 | |
248 | QCOMPARE(object->property("calledAsConstructor" ).toBool(), true); |
249 | QCOMPARE(object->property("calledAsFunction" ).toBool(), true); |
250 | } |
251 | |
252 | // Test that all the properties are set correctly before any request is sent |
253 | void tst_qqmlxmlhttprequest::defaultState() |
254 | { |
255 | QQmlComponent component(engine.get(), testFileUrl(fileName: "defaultState.qml" )); |
256 | QScopedPointer<QObject> object(component.create()); |
257 | QVERIFY(!object.isNull()); |
258 | |
259 | QCOMPARE(object->property("readState" ).toInt(), 0); |
260 | QCOMPARE(object->property("statusIsException" ).toBool(), true); |
261 | QCOMPARE(object->property("statusTextIsException" ).toBool(), true); |
262 | QCOMPARE(object->property("responseText" ).toString(), QString()); |
263 | QCOMPARE(object->property("responseXMLIsNull" ).toBool(), true); |
264 | } |
265 | |
266 | // Test valid XMLHttpRequest.open() calls |
267 | void tst_qqmlxmlhttprequest::open() |
268 | { |
269 | QFETCH(QUrl, qmlFile); |
270 | QFETCH(QString, url); |
271 | QFETCH(bool, remote); |
272 | |
273 | TestHTTPServer server; |
274 | if (remote) { |
275 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
276 | QVERIFY(server.wait(testFileUrl("open_network.expect" ), |
277 | testFileUrl("open_network.reply" ), |
278 | testFileUrl("testdocument.html" ))); |
279 | url = server.urlString(documentPath: url); |
280 | } |
281 | |
282 | QQmlComponent component(engine.get(), qmlFile); |
283 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
284 | QVERIFY(!object.isNull()); |
285 | object->setProperty(name: "url" , value: url); |
286 | component.completeCreate(); |
287 | |
288 | QCOMPARE(object->property("readyState" ).toBool(), true); |
289 | QCOMPARE(object->property("openedState" ).toBool(), true); |
290 | QCOMPARE(object->property("status" ).toBool(), true); |
291 | QCOMPARE(object->property("statusText" ).toBool(), true); |
292 | QCOMPARE(object->property("responseText" ).toBool(), true); |
293 | QCOMPARE(object->property("responseXML" ).toBool(), true); |
294 | |
295 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
296 | } |
297 | |
298 | void tst_qqmlxmlhttprequest::open_data() |
299 | { |
300 | QTest::addColumn<QUrl>(name: "qmlFile" ); |
301 | QTest::addColumn<QString>(name: "url" ); |
302 | QTest::addColumn<bool>(name: "remote" ); |
303 | |
304 | QTest::newRow(dataTag: "Relative url)" ) << testFileUrl(fileName: "open.qml" ) << "testdocument.html" << false; |
305 | QTest::newRow(dataTag: "Absolute url)" ) << testFileUrl(fileName: "open.qml" ) << testFileUrl(fileName: "testdocument.html" ).toString() << false; |
306 | QTest::newRow(dataTag: "Absolute network url)" ) << testFileUrl(fileName: "open.qml" ) << "/testdocument.html" << true; |
307 | |
308 | // ### Check that the username/password were sent to the server |
309 | QTest::newRow(dataTag: "User/pass" ) << testFileUrl(fileName: "open_user.qml" ) << "/testdocument.html" << true; |
310 | } |
311 | |
312 | // Test that calling XMLHttpRequest.open() with an invalid method raises an exception |
313 | void tst_qqmlxmlhttprequest::open_invalid_method() |
314 | { |
315 | QQmlComponent component(engine.get(), testFileUrl(fileName: "open_invalid_method.qml" )); |
316 | QScopedPointer<QObject> object(component.create()); |
317 | QVERIFY(!object.isNull()); |
318 | |
319 | QCOMPARE(object->property("exceptionThrown" ).toBool(), true); |
320 | } |
321 | |
322 | class TestThreadedHTTPServer : public QObject |
323 | { |
324 | Q_OBJECT |
325 | public: |
326 | TestThreadedHTTPServer(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl) |
327 | : m_server(nullptr) { |
328 | QMutexLocker locker(&m_lock); |
329 | moveToThread(thread: &m_thread); |
330 | m_thread.start(); |
331 | QMetaObject::invokeMethod(obj: this, member: "start" , type: Qt::QueuedConnection, Q_ARG(QUrl, expectUrl), Q_ARG(QUrl, replyUrl), Q_ARG(QUrl, bodyUrl)); |
332 | m_startupCondition.wait(lockedMutex: &m_lock); |
333 | } |
334 | ~TestThreadedHTTPServer() { |
335 | m_server->deleteLater(); |
336 | m_thread.exit(); |
337 | m_thread.wait(); |
338 | } |
339 | |
340 | QUrl serverBaseUrl; |
341 | |
342 | private slots: |
343 | void start(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl) { |
344 | QMutexLocker locker(&m_lock); |
345 | m_server = new TestHTTPServer; |
346 | QVERIFY2(m_server->listen(), qPrintable(m_server->errorString())); |
347 | serverBaseUrl = m_server->baseUrl(); |
348 | QVERIFY(m_server->wait(expectUrl, replyUrl, bodyUrl)); |
349 | m_startupCondition.wakeAll(); |
350 | } |
351 | |
352 | private: |
353 | TestHTTPServer *m_server; |
354 | QThread m_thread; |
355 | QMutex m_lock; |
356 | QWaitCondition m_startupCondition; |
357 | }; |
358 | |
359 | // Test that calling XMLHttpRequest.open() with sync |
360 | void tst_qqmlxmlhttprequest::open_sync() |
361 | { |
362 | TestThreadedHTTPServer server(testFileUrl(fileName: "open_network.expect" ), testFileUrl(fileName: "open_network.reply" ), testFileUrl(fileName: "testdocument.html" )); |
363 | |
364 | QQmlComponent component(engine.get(), testFileUrl(fileName: "open_sync.qml" )); |
365 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
366 | QVERIFY(!object.isNull()); |
367 | object->setProperty(name: "url" , value: server.serverBaseUrl.resolved(QStringLiteral("/testdocument.html" )).toString()); |
368 | component.completeCreate(); |
369 | |
370 | QCOMPARE(object->property("responseText" ).toString(), QStringLiteral("QML Rocks!\n" )); |
371 | } |
372 | |
373 | // Calling with incorrect arg count raises an exception |
374 | void tst_qqmlxmlhttprequest::open_arg_count() |
375 | { |
376 | { |
377 | QQmlComponent component(engine.get(), testFileUrl(fileName: "open_arg_count.1.qml" )); |
378 | QScopedPointer<QObject> object(component.create()); |
379 | QVERIFY(!object.isNull()); |
380 | |
381 | QCOMPARE(object->property("exceptionThrown" ).toBool(), true); |
382 | } |
383 | |
384 | { |
385 | QQmlComponent component(engine.get(), testFileUrl(fileName: "open_arg_count.2.qml" )); |
386 | QScopedPointer<QObject> object(component.create()); |
387 | QVERIFY(!object.isNull()); |
388 | |
389 | QCOMPARE(object->property("exceptionThrown" ).toBool(), true); |
390 | } |
391 | } |
392 | |
393 | // Test valid setRequestHeader() calls |
394 | void tst_qqmlxmlhttprequest::() |
395 | { |
396 | TestHTTPServer server; |
397 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
398 | QVERIFY(server.wait(testFileUrl("setRequestHeader.expect" ), |
399 | testFileUrl("setRequestHeader.reply" ), |
400 | testFileUrl("testdocument.html" ))); |
401 | |
402 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader.qml" )); |
403 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
404 | QVERIFY(!object.isNull()); |
405 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
406 | component.completeCreate(); |
407 | |
408 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
409 | } |
410 | |
411 | // Test valid setRequestHeader() calls with different header cases |
412 | void tst_qqmlxmlhttprequest::() |
413 | { |
414 | TestHTTPServer server; |
415 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
416 | QVERIFY(server.wait(testFileUrl("setRequestHeader.expect" ), |
417 | testFileUrl("setRequestHeader.reply" ), |
418 | testFileUrl("testdocument.html" ))); |
419 | |
420 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader_caseInsensitive.qml" )); |
421 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
422 | QVERIFY(!object.isNull()); |
423 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
424 | component.completeCreate(); |
425 | |
426 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
427 | } |
428 | // Test setting headers before open() throws exception |
429 | void tst_qqmlxmlhttprequest::() |
430 | { |
431 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader_unsent.qml" )); |
432 | QScopedPointer<QObject> object(component.create()); |
433 | QVERIFY(!object.isNull()); |
434 | |
435 | QCOMPARE(object->property("test" ).toBool(), true); |
436 | } |
437 | |
438 | void tst_qqmlxmlhttprequest::() |
439 | { |
440 | QTest::addColumn<QString>(name: "name" ); |
441 | |
442 | QTest::newRow(dataTag: "Accept-Charset" ) << "AccePT-CHArset" ; |
443 | QTest::newRow(dataTag: "Accept-Encoding" ) << "AccEpt-EnCOding" ; |
444 | QTest::newRow(dataTag: "Connection" ) << "ConnECtion" ; |
445 | QTest::newRow(dataTag: "Content-Length" ) << "ContEnt-LenGth" ; |
446 | QTest::newRow(dataTag: "Cookie" ) << "CookIe" ; |
447 | QTest::newRow(dataTag: "Cookie2" ) << "CoOkie2" ; |
448 | QTest::newRow(dataTag: "Content-Transfer-Encoding" ) << "ConteNT-tRANSFER-eNCOding" ; |
449 | QTest::newRow(dataTag: "Date" ) << "DaTE" ; |
450 | QTest::newRow(dataTag: "Expect" ) << "ExPect" ; |
451 | QTest::newRow(dataTag: "Host" ) << "HoST" ; |
452 | QTest::newRow(dataTag: "Keep-Alive" ) << "KEEP-aLive" ; |
453 | QTest::newRow(dataTag: "Referer" ) << "ReferEr" ; |
454 | QTest::newRow(dataTag: "TE" ) << "Te" ; |
455 | QTest::newRow(dataTag: "Trailer" ) << "TraILEr" ; |
456 | QTest::newRow(dataTag: "Transfer-Encoding" ) << "tRANsfer-Encoding" ; |
457 | QTest::newRow(dataTag: "Upgrade" ) << "UpgrADe" ; |
458 | QTest::newRow(dataTag: "User-Agent" ) << "uSEr-Agent" ; |
459 | QTest::newRow(dataTag: "Via" ) << "vIa" ; |
460 | QTest::newRow(dataTag: "Proxy-" ) << "ProXy-" ; |
461 | QTest::newRow(dataTag: "Sec-" ) << "SeC-" ; |
462 | QTest::newRow(dataTag: "Proxy-*" ) << "Proxy-BLAH" ; |
463 | QTest::newRow(dataTag: "Sec-*" ) << "Sec-F" ; |
464 | } |
465 | |
466 | // Tests that using illegal header names has no effect |
467 | void tst_qqmlxmlhttprequest::() |
468 | { |
469 | QFETCH(QString, name); |
470 | |
471 | TestHTTPServer server; |
472 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
473 | QVERIFY(server.wait(testFileUrl("open_network.expect" ), |
474 | testFileUrl("open_network.reply" ), |
475 | testFileUrl("testdocument.html" ))); |
476 | |
477 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader_illegalName.qml" )); |
478 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
479 | QVERIFY(!object.isNull()); |
480 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
481 | object->setProperty(name: "header" , value: name); |
482 | component.completeCreate(); |
483 | |
484 | QCOMPARE(object->property("readyState" ).toBool(), true); |
485 | QCOMPARE(object->property("openedState" ).toBool(), true); |
486 | QCOMPARE(object->property("status" ).toBool(), true); |
487 | QCOMPARE(object->property("statusText" ).toBool(), true); |
488 | QCOMPARE(object->property("responseText" ).toBool(), true); |
489 | QCOMPARE(object->property("responseXML" ).toBool(), true); |
490 | |
491 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
492 | } |
493 | |
494 | // Test that attempting to set a header after a request is sent throws an exception |
495 | void tst_qqmlxmlhttprequest::() |
496 | { |
497 | TestHTTPServer server; |
498 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
499 | QVERIFY(server.wait(testFileUrl("open_network.expect" ), |
500 | testFileUrl("open_network.reply" ), |
501 | testFileUrl("testdocument.html" ))); |
502 | |
503 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader_sent.qml" )); |
504 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
505 | QVERIFY(!object.isNull()); |
506 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
507 | component.completeCreate(); |
508 | |
509 | QCOMPARE(object->property("test" ).toBool(), true); |
510 | |
511 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
512 | } |
513 | |
514 | // Invalid arg count throws exception |
515 | void tst_qqmlxmlhttprequest::() |
516 | { |
517 | QQmlComponent component(engine.get(), testFileUrl(fileName: "setRequestHeader_args.qml" )); |
518 | QScopedPointer<QObject> object(component.create()); |
519 | QVERIFY(!object.isNull()); |
520 | |
521 | QCOMPARE(object->property("exceptionThrown" ).toBool(), true); |
522 | } |
523 | |
524 | // Test that calling send() in UNSENT state throws an exception |
525 | void tst_qqmlxmlhttprequest::send_unsent() |
526 | { |
527 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_unsent.qml" )); |
528 | QScopedPointer<QObject> object(component.create()); |
529 | QVERIFY(!object.isNull()); |
530 | |
531 | QCOMPARE(object->property("test" ).toBool(), true); |
532 | } |
533 | |
534 | // Test attempting to resend a sent request throws an exception |
535 | void tst_qqmlxmlhttprequest::send_alreadySent() |
536 | { |
537 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_alreadySent.qml" )); |
538 | QScopedPointer<QObject> object(component.create()); |
539 | QVERIFY(!object.isNull()); |
540 | |
541 | QCOMPARE(object->property("test" ).toBool(), true); |
542 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
543 | } |
544 | |
545 | // Test that sends for GET, HEAD and DELETE ignore data |
546 | void tst_qqmlxmlhttprequest::send_ignoreData() |
547 | { |
548 | { |
549 | TestHTTPServer server; |
550 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
551 | QVERIFY(server.wait(testFileUrl("send_ignoreData_GET.expect" ), |
552 | testFileUrl("send_ignoreData.reply" ), |
553 | testFileUrl("testdocument.html" ))); |
554 | |
555 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_ignoreData.qml" )); |
556 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
557 | QVERIFY(!object.isNull()); |
558 | object->setProperty(name: "reqType" , value: "GET" ); |
559 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
560 | component.completeCreate(); |
561 | |
562 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
563 | } |
564 | |
565 | { |
566 | TestHTTPServer server; |
567 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
568 | QVERIFY(server.wait(testFileUrl("send_ignoreData_HEAD.expect" ), |
569 | testFileUrl("send_ignoreData.reply" ), |
570 | QUrl())); |
571 | |
572 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_ignoreData.qml" )); |
573 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
574 | QVERIFY(!object.isNull()); |
575 | object->setProperty(name: "reqType" , value: "HEAD" ); |
576 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
577 | component.completeCreate(); |
578 | |
579 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
580 | } |
581 | |
582 | { |
583 | TestHTTPServer server; |
584 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
585 | QVERIFY(server.wait(testFileUrl("send_ignoreData_DELETE.expect" ), |
586 | testFileUrl("send_ignoreData.reply" ), |
587 | QUrl())); |
588 | |
589 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_ignoreData.qml" )); |
590 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
591 | QVERIFY(!object.isNull()); |
592 | object->setProperty(name: "reqType" , value: "DELETE" ); |
593 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
594 | component.completeCreate(); |
595 | |
596 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
597 | } |
598 | } |
599 | |
600 | // Test that send()'ing data works |
601 | void tst_qqmlxmlhttprequest::send_withdata() |
602 | { |
603 | QFETCH(QString, file_expected); |
604 | QFETCH(QString, file_qml); |
605 | |
606 | TestHTTPServer server; |
607 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
608 | QVERIFY(server.wait(testFileUrl(file_expected), |
609 | testFileUrl("send_data.reply" ), |
610 | testFileUrl("testdocument.html" ))); |
611 | |
612 | QQmlComponent component(engine.get(), testFileUrl(fileName: file_qml)); |
613 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
614 | QVERIFY(!object.isNull()); |
615 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
616 | component.completeCreate(); |
617 | |
618 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
619 | } |
620 | |
621 | void tst_qqmlxmlhttprequest::send_withdata_data() |
622 | { |
623 | QTest::addColumn<QString>(name: "file_expected" ); |
624 | QTest::addColumn<QString>(name: "file_qml" ); |
625 | |
626 | QTest::newRow(dataTag: "No content-type" ) << "send_data.1.expect" << "send_data.1.qml" ; |
627 | QTest::newRow(dataTag: "Correct content-type" ) << "send_data.1.expect" << "send_data.2.qml" ; |
628 | QTest::newRow(dataTag: "Incorrect content-type" ) << "send_data.1.expect" << "send_data.3.qml" ; |
629 | QTest::newRow(dataTag: "Correct content-type - out of order" ) << "send_data.4.expect" << "send_data.4.qml" ; |
630 | QTest::newRow(dataTag: "Incorrect content-type - out of order" ) << "send_data.4.expect" << "send_data.5.qml" ; |
631 | QTest::newRow(dataTag: "PUT" ) << "send_data.6.expect" << "send_data.6.qml" ; |
632 | QTest::newRow(dataTag: "Correct content-type - no charset" ) << "send_data.1.expect" << "send_data.7.qml" ; |
633 | QTest::newRow(dataTag: "ArrayBuffer" ) << "send_data.11.expect" << "send_data.11.qml" ; |
634 | } |
635 | |
636 | void tst_qqmlxmlhttprequest::send_options() |
637 | { |
638 | QFETCH(QString, url_suffix); |
639 | QFETCH(QString, file_expected); |
640 | QFETCH(QString, file_qml); |
641 | QFETCH(QString, file_reply); |
642 | |
643 | TestHTTPServer server; |
644 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
645 | QVERIFY(server.wait(testFileUrl(file_expected), |
646 | testFileUrl(file_reply), |
647 | testFileUrl("testdocument.html" ))); |
648 | |
649 | QQmlComponent component(engine.get(), testFileUrl(fileName: file_qml)); |
650 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
651 | QVERIFY(!object.isNull()); |
652 | QString url = server.baseUrl().toString(); |
653 | if (url_suffix != "/" ) |
654 | url.append(c: QLatin1Char('/')); |
655 | if (!url_suffix.isEmpty()) |
656 | url.append(s: url_suffix); |
657 | object->setProperty(name: "url" , value: url); |
658 | component.completeCreate(); |
659 | |
660 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
661 | QTRY_VERIFY(object->property("headerOK" ).toBool()); |
662 | } |
663 | |
664 | void tst_qqmlxmlhttprequest::send_options_data() |
665 | { |
666 | QTest::addColumn<QString>(name: "url_suffix" ); |
667 | QTest::addColumn<QString>(name: "file_expected" ); |
668 | QTest::addColumn<QString>(name: "file_qml" ); |
669 | QTest::addColumn<QString>(name: "file_reply" ); |
670 | |
671 | QTest::newRow(dataTag: "OPTIONS (no data, no resource, no path)" ) << "" << "send_data.8.expect" << "send_data.8.qml" << "send_data.2.reply" ; |
672 | QTest::newRow(dataTag: "OPTIONS (no data, no resource, path- \"/\")" ) << "/" << "send_data.8.expect" << "send_data.8.qml" << "send_data.2.reply" ; |
673 | QTest::newRow(dataTag: "OPTIONS (no data, with resource)" ) << "testdocument.html" << "send_data.9.expect" << "send_data.8.qml" << "send_data.2.reply" ; |
674 | QTest::newRow(dataTag: "OPTIONS (with data)" ) << "testdocument.html" << "send_data.10.expect" << "send_data.9.qml" << "send_data.2.reply" ; |
675 | } |
676 | |
677 | void tst_qqmlxmlhttprequest::send_patch() |
678 | { |
679 | TestHTTPServer server; |
680 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
681 | QVERIFY(server.wait(testFileUrl("send_patch.expect" ), |
682 | testFileUrl("send_patch.reply" ), |
683 | // the content of response file will be ignored due to 204 status code |
684 | testFileUrl("testdocument.html" ))); |
685 | |
686 | QQmlComponent component(engine.get(), testFileUrl(fileName: "send_patch.qml" )); |
687 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
688 | QVERIFY(!object.isNull()); |
689 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/qqmlxmlhttprequest.cpp" )); |
690 | component.completeCreate(); |
691 | |
692 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
693 | QTRY_VERIFY(object->property("headerOK" ).toBool()); |
694 | } |
695 | |
696 | |
697 | // Test abort() has no effect in unsent state |
698 | void tst_qqmlxmlhttprequest::abort_unsent() |
699 | { |
700 | QQmlComponent component(engine.get(), testFileUrl(fileName: "abort_unsent.qml" )); |
701 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
702 | QVERIFY(!object.isNull()); |
703 | object->setProperty(name: "url" , value: "testdocument.html" ); |
704 | component.completeCreate(); |
705 | |
706 | QCOMPARE(object->property("readyState" ).toBool(), true); |
707 | QCOMPARE(object->property("openedState" ).toBool(), true); |
708 | QCOMPARE(object->property("status" ).toBool(), true); |
709 | QCOMPARE(object->property("statusText" ).toBool(), true); |
710 | QCOMPARE(object->property("responseText" ).toBool(), true); |
711 | QCOMPARE(object->property("responseXML" ).toBool(), true); |
712 | |
713 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
714 | } |
715 | |
716 | // Test abort() cancels an open (but unsent) request |
717 | void tst_qqmlxmlhttprequest::abort_opened() |
718 | { |
719 | QQmlComponent component(engine.get(), testFileUrl(fileName: "abort_opened.qml" )); |
720 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
721 | QVERIFY(!object.isNull()); |
722 | object->setProperty(name: "url" , value: "testdocument.html" ); |
723 | component.completeCreate(); |
724 | |
725 | QCOMPARE(object->property("readyState" ).toBool(), true); |
726 | QCOMPARE(object->property("openedState" ).toBool(), true); |
727 | QCOMPARE(object->property("status" ).toBool(), true); |
728 | QCOMPARE(object->property("statusText" ).toBool(), true); |
729 | QCOMPARE(object->property("responseText" ).toBool(), true); |
730 | QCOMPARE(object->property("responseXML" ).toBool(), true); |
731 | |
732 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
733 | } |
734 | |
735 | // Test abort() aborts in progress send |
736 | void tst_qqmlxmlhttprequest::abort() |
737 | { |
738 | TestHTTPServer server; |
739 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
740 | QVERIFY(server.wait(testFileUrl("abort.expect" ), |
741 | testFileUrl("abort.reply" ), |
742 | testFileUrl("testdocument.html" ))); |
743 | |
744 | QQmlComponent component(engine.get(), testFileUrl(fileName: "abort.qml" )); |
745 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
746 | QVERIFY(!object.isNull()); |
747 | const QUrl url = server.url(documentPath: "/testdocument.html" ); |
748 | QUrl dummyUrl = url; |
749 | dummyUrl.setPort(dummyUrl.port() - 1); |
750 | object->setProperty(name: "urlDummy" , value: dummyUrl.toString()); |
751 | object->setProperty(name: "url" , value: url.toString()); |
752 | component.completeCreate(); |
753 | |
754 | QCOMPARE(object->property("seenDone" ).toBool(), true); |
755 | QCOMPARE(object->property("didNotSeeUnsent" ).toBool(), true); |
756 | QCOMPARE(object->property("endStateUnsent" ).toBool(), true); |
757 | |
758 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
759 | } |
760 | |
761 | void tst_qqmlxmlhttprequest::() |
762 | { |
763 | QQmlEngine engine; // Avoid cookie contamination |
764 | |
765 | TestHTTPServer server; |
766 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
767 | QVERIFY(server.wait(testFileUrl("getResponseHeader.expect" ), |
768 | testFileUrl("getResponseHeader.reply" ), |
769 | testFileUrl("testdocument.html" ))); |
770 | |
771 | |
772 | QQmlComponent component(&engine, testFileUrl(fileName: "getResponseHeader.qml" )); |
773 | QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); |
774 | QVERIFY(!object.isNull()); |
775 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
776 | component.completeCreate(); |
777 | |
778 | QCOMPARE(object->property("unsentException" ).toBool(), true); |
779 | QCOMPARE(object->property("openedException" ).toBool(), true); |
780 | QCOMPARE(object->property("readyState" ).toBool(), true); |
781 | QCOMPARE(object->property("openedState" ).toBool(), true); |
782 | |
783 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
784 | |
785 | QCOMPARE(object->property("headersReceivedState" ).toBool(), true); |
786 | QCOMPARE(object->property("headersReceivedNullHeader" ).toBool(), true); |
787 | QCOMPARE(object->property("headersReceivedValidHeader" ).toBool(), true); |
788 | QCOMPARE(object->property("headersReceivedMultiValidHeader" ).toBool(), true); |
789 | QCOMPARE(object->property("headersReceivedCookieHeader" ).toBool(), true); |
790 | |
791 | QCOMPARE(object->property("doneState" ).toBool(), true); |
792 | QCOMPARE(object->property("doneNullHeader" ).toBool(), true); |
793 | QCOMPARE(object->property("doneValidHeader" ).toBool(), true); |
794 | QCOMPARE(object->property("doneMultiValidHeader" ).toBool(), true); |
795 | QCOMPARE(object->property("doneCookieHeader" ).toBool(), true); |
796 | } |
797 | |
798 | // Test getResponseHeader throws an exception in an invalid state |
799 | void tst_qqmlxmlhttprequest::() |
800 | { |
801 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getResponseHeader_unsent.qml" )); |
802 | QScopedPointer<QObject> object(component.create()); |
803 | QVERIFY(!object.isNull()); |
804 | |
805 | QCOMPARE(object->property("test" ).toBool(), true); |
806 | } |
807 | |
808 | // Test getResponseHeader throws an exception in an invalid state |
809 | void tst_qqmlxmlhttprequest::() |
810 | { |
811 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getResponseHeader_sent.qml" )); |
812 | QScopedPointer<QObject> object(component.create()); |
813 | QVERIFY(!object.isNull()); |
814 | |
815 | QCOMPARE(object->property("test" ).toBool(), true); |
816 | } |
817 | |
818 | // Invalid arg count throws exception |
819 | void tst_qqmlxmlhttprequest::() |
820 | { |
821 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getResponseHeader_args.qml" )); |
822 | QScopedPointer<QObject> object(component.create()); |
823 | QVERIFY(!object.isNull()); |
824 | |
825 | QTRY_VERIFY(object->property("exceptionThrown" ).toBool()); |
826 | } |
827 | |
828 | void tst_qqmlxmlhttprequest::() |
829 | { |
830 | QQmlEngine engine; // Avoid cookie contamination |
831 | |
832 | TestHTTPServer server; |
833 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
834 | QVERIFY(server.wait(testFileUrl("getResponseHeader.expect" ), |
835 | testFileUrl("getResponseHeader.reply" ), |
836 | testFileUrl("testdocument.html" ))); |
837 | |
838 | QQmlComponent component(&engine, testFileUrl(fileName: "getAllResponseHeaders.qml" )); |
839 | QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); |
840 | QVERIFY(!object.isNull()); |
841 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
842 | component.completeCreate(); |
843 | |
844 | QCOMPARE(object->property("unsentException" ).toBool(), true); |
845 | QCOMPARE(object->property("openedException" ).toBool(), true); |
846 | QCOMPARE(object->property("readyState" ).toBool(), true); |
847 | QCOMPARE(object->property("openedState" ).toBool(), true); |
848 | |
849 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
850 | |
851 | QCOMPARE(object->property("headersReceivedState" ).toBool(), true); |
852 | QCOMPARE(object->property("headersReceivedHeader" ).toBool(), true); |
853 | |
854 | QCOMPARE(object->property("doneState" ).toBool(), true); |
855 | QCOMPARE(object->property("doneHeader" ).toBool(), true); |
856 | } |
857 | |
858 | // Test getAllResponseHeaders throws an exception in an invalid state |
859 | void tst_qqmlxmlhttprequest::() |
860 | { |
861 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getAllResponseHeaders_unsent.qml" )); |
862 | QScopedPointer<QObject> object(component.create()); |
863 | QVERIFY(!object.isNull()); |
864 | |
865 | QCOMPARE(object->property("test" ).toBool(), true); |
866 | } |
867 | |
868 | // Test getAllResponseHeaders throws an exception in an invalid state |
869 | void tst_qqmlxmlhttprequest::() |
870 | { |
871 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getAllResponseHeaders_sent.qml" )); |
872 | QScopedPointer<QObject> object(component.create()); |
873 | QVERIFY(!object.isNull()); |
874 | |
875 | QCOMPARE(object->property("test" ).toBool(), true); |
876 | } |
877 | |
878 | // Invalid arg count throws exception |
879 | void tst_qqmlxmlhttprequest::() |
880 | { |
881 | QQmlComponent component(engine.get(), testFileUrl(fileName: "getAllResponseHeaders_args.qml" )); |
882 | QScopedPointer<QObject> object(component.create()); |
883 | QVERIFY(!object.isNull()); |
884 | |
885 | QTRY_VERIFY(object->property("exceptionThrown" ).toBool()); |
886 | } |
887 | |
888 | void tst_qqmlxmlhttprequest::getBinaryData() |
889 | { |
890 | TestHTTPServer server; |
891 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
892 | QVERIFY(server.wait(testFileUrl("receive_binary_data.expect" ), |
893 | testFileUrl("receive_binary_data.reply" ), |
894 | testFileUrl("qml_logo.png" ))); |
895 | |
896 | QQmlComponent component(engine.get(), testFileUrl(fileName: "receiveBinaryData.qml" )); |
897 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
898 | QVERIFY(!object.isNull()); |
899 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/gml_logo.png" )); |
900 | component.completeCreate(); |
901 | |
902 | QFileInfo fileInfo("data/qml_logo.png" ); |
903 | QTRY_COMPARE(object->property("readSize" ).toInt(), fileInfo.size()); |
904 | QCOMPARE(object->property("status" ).toInt(), 200); |
905 | } |
906 | |
907 | void tst_qqmlxmlhttprequest::getJsonData() |
908 | { |
909 | TestHTTPServer server; |
910 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
911 | QVERIFY(server.wait(testFileUrl("receive_json_data.expect" ), |
912 | testFileUrl("receive_binary_data.reply" ), |
913 | testFileUrl("json.data" ))); |
914 | |
915 | QQmlComponent component(engine.get(), testFileUrl(fileName: "receiveJsonData.qml" )); |
916 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
917 | QVERIFY(!object.isNull()); |
918 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/json.data" )); |
919 | component.completeCreate(); |
920 | |
921 | QTRY_VERIFY(object->property("result" ).toBool()); |
922 | } |
923 | |
924 | void tst_qqmlxmlhttprequest::status() |
925 | { |
926 | QFETCH(QUrl, replyUrl); |
927 | QFETCH(int, status); |
928 | |
929 | TestHTTPServer server; |
930 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
931 | QVERIFY(server.wait(testFileUrl("status.expect" ), |
932 | replyUrl, |
933 | testFileUrl("testdocument.html" ))); |
934 | |
935 | QQmlComponent component(engine.get(), testFileUrl(fileName: "status.qml" )); |
936 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
937 | QVERIFY(!object.isNull()); |
938 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
939 | object->setProperty(name: "expectedStatus" , value: status); |
940 | component.completeCreate(); |
941 | |
942 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
943 | |
944 | QCOMPARE(object->property("unsentException" ).toBool(), true); |
945 | QCOMPARE(object->property("openedException" ).toBool(), true); |
946 | QCOMPARE(object->property("sentException" ).toBool(), true); |
947 | QCOMPARE(object->property("headersReceived" ).toBool(), true); |
948 | QCOMPARE(object->property("loading" ).toBool(), true); |
949 | QCOMPARE(object->property("done" ).toBool(), true); |
950 | QCOMPARE(object->property("resetException" ).toBool(), true); |
951 | QCOMPARE(object->property("onloadCalled" ).toBool(), true); |
952 | QCOMPARE(object->property("onloadendCalled" ).toBool(), true); |
953 | QCOMPARE(object->property("onerrorCalled" ).toBool(), false); |
954 | } |
955 | |
956 | void tst_qqmlxmlhttprequest::status_data() |
957 | { |
958 | QTest::addColumn<QUrl>(name: "replyUrl" ); |
959 | QTest::addColumn<int>(name: "status" ); |
960 | |
961 | QTest::newRow(dataTag: "OK" ) << testFileUrl(fileName: "status.200.reply" ) << 200; |
962 | QTest::newRow(dataTag: "Not Found" ) << testFileUrl(fileName: "status.404.reply" ) << 404; |
963 | QTest::newRow(dataTag: "Bad Request" ) << testFileUrl(fileName: "status.400.reply" ) << 400; |
964 | } |
965 | |
966 | void tst_qqmlxmlhttprequest::statusText() |
967 | { |
968 | QFETCH(QUrl, replyUrl); |
969 | QFETCH(QString, statusText); |
970 | |
971 | TestHTTPServer server; |
972 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
973 | QVERIFY(server.wait(testFileUrl("status.expect" ), |
974 | replyUrl, |
975 | testFileUrl("testdocument.html" ))); |
976 | |
977 | QQmlComponent component(engine.get(), testFileUrl(fileName: "statusText.qml" )); |
978 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
979 | QVERIFY(!object.isNull()); |
980 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
981 | object->setProperty(name: "expectedStatus" , value: statusText); |
982 | component.completeCreate(); |
983 | |
984 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
985 | |
986 | QCOMPARE(object->property("unsentException" ).toBool(), true); |
987 | QCOMPARE(object->property("openedException" ).toBool(), true); |
988 | QCOMPARE(object->property("sentException" ).toBool(), true); |
989 | QCOMPARE(object->property("headersReceived" ).toBool(), true); |
990 | QCOMPARE(object->property("loading" ).toBool(), true); |
991 | QCOMPARE(object->property("done" ).toBool(), true); |
992 | QCOMPARE(object->property("resetException" ).toBool(), true); |
993 | } |
994 | |
995 | void tst_qqmlxmlhttprequest::statusText_data() |
996 | { |
997 | QTest::addColumn<QUrl>(name: "replyUrl" ); |
998 | QTest::addColumn<QString>(name: "statusText" ); |
999 | |
1000 | QTest::newRow(dataTag: "OK" ) << testFileUrl(fileName: "status.200.reply" ) << "OK" ; |
1001 | QTest::newRow(dataTag: "Not Found" ) << testFileUrl(fileName: "status.404.reply" ) << "Document not found" ; |
1002 | QTest::newRow(dataTag: "Bad Request" ) << testFileUrl(fileName: "status.400.reply" ) << "Bad request" ; |
1003 | } |
1004 | |
1005 | void tst_qqmlxmlhttprequest::responseText() |
1006 | { |
1007 | QFETCH(QUrl, replyUrl); |
1008 | QFETCH(QUrl, bodyUrl); |
1009 | QFETCH(QString, responseText); |
1010 | |
1011 | TestHTTPServer server; |
1012 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1013 | QVERIFY(server.wait(testFileUrl("status.expect" ), |
1014 | replyUrl, |
1015 | bodyUrl)); |
1016 | |
1017 | QQmlComponent component(engine.get(), testFileUrl(fileName: "responseText.qml" )); |
1018 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1019 | QVERIFY(!object.isNull()); |
1020 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/testdocument.html" )); |
1021 | object->setProperty(name: "expectedText" , value: responseText); |
1022 | component.completeCreate(); |
1023 | |
1024 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1025 | |
1026 | QCOMPARE(object->property("unsent" ).toBool(), true); |
1027 | QCOMPARE(object->property("opened" ).toBool(), true); |
1028 | QCOMPARE(object->property("sent" ).toBool(), true); |
1029 | QCOMPARE(object->property("headersReceived" ).toBool(), true); |
1030 | QCOMPARE(object->property("loading" ).toBool(), true); |
1031 | QCOMPARE(object->property("done" ).toBool(), true); |
1032 | QCOMPARE(object->property("reset" ).toBool(), true); |
1033 | } |
1034 | |
1035 | void tst_qqmlxmlhttprequest::responseText_data() |
1036 | { |
1037 | QTest::addColumn<QUrl>(name: "replyUrl" ); |
1038 | QTest::addColumn<QUrl>(name: "bodyUrl" ); |
1039 | QTest::addColumn<QString>(name: "responseText" ); |
1040 | |
1041 | QTest::newRow(dataTag: "OK" ) << testFileUrl(fileName: "status.200.reply" ) << testFileUrl(fileName: "testdocument.html" ) << "QML Rocks!\n" ; |
1042 | QTest::newRow(dataTag: "empty body" ) << testFileUrl(fileName: "status.200.reply" ) << QUrl() << "" ; |
1043 | QTest::newRow(dataTag: "Not Found" ) << testFileUrl(fileName: "status.404.reply" ) << testFileUrl(fileName: "testdocument.html" ) << "QML Rocks!\n" ; |
1044 | QTest::newRow(dataTag: "Bad Request" ) << testFileUrl(fileName: "status.400.reply" ) << testFileUrl(fileName: "testdocument.html" ) << "QML Rocks!\n" ; |
1045 | QTest::newRow(dataTag: "Internal server error" ) << testFileUrl(fileName: "status.500.reply" ) << testFileUrl(fileName: "testdocument.html" ) << "QML Rocks!\n" ; |
1046 | } |
1047 | |
1048 | void tst_qqmlxmlhttprequest::nonUtf8() |
1049 | { |
1050 | QFETCH(QString, fileName); |
1051 | QFETCH(QString, responseText); |
1052 | QFETCH(QString, xmlRootNodeValue); |
1053 | |
1054 | QQmlComponent component(engine.get(), testFileUrl(fileName: "utf16.qml" )); |
1055 | QScopedPointer<QObject> object(component.create()); |
1056 | QVERIFY(!object.isNull()); |
1057 | |
1058 | object->setProperty(name: "fileName" , value: fileName); |
1059 | QMetaObject::invokeMethod(obj: object.data(), member: "startRequest" ); |
1060 | |
1061 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1062 | |
1063 | QCOMPARE(object->property("responseText" ).toString(), responseText); |
1064 | |
1065 | if (!xmlRootNodeValue.isEmpty()) { |
1066 | QString rootNodeValue = object->property(name: "responseXmlRootNodeValue" ).toString(); |
1067 | QCOMPARE(rootNodeValue, xmlRootNodeValue); |
1068 | } |
1069 | } |
1070 | |
1071 | void tst_qqmlxmlhttprequest::nonUtf8_data() |
1072 | { |
1073 | QTest::addColumn<QString>(name: "fileName" ); |
1074 | QTest::addColumn<QString>(name: "responseText" ); |
1075 | QTest::addColumn<QString>(name: "xmlRootNodeValue" ); |
1076 | |
1077 | QString uc; |
1078 | uc.resize(size: 3); |
1079 | uc[0] = QChar(0x10e3); |
1080 | uc[1] = QChar(' '); |
1081 | uc[2] = QChar(0x03a3); |
1082 | |
1083 | QTest::newRow(dataTag: "responseText" ) << "utf16.html" << uc + '\n' << "" ; |
1084 | QTest::newRow(dataTag: "responseXML" ) << "utf16.xml" << "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone='yes'?>\n<root>\n" + uc + "\n</root>\n" << QString('\n' + uc + '\n'); |
1085 | } |
1086 | |
1087 | static const QString testString = QStringLiteral("Test-String" ); |
1088 | |
1089 | void tst_qqmlxmlhttprequest::doFileRequest(std::function<void(QObject *component, QTemporaryFile &writeFile)> verifyFunction) |
1090 | { |
1091 | // Create test files |
1092 | QTemporaryFile writeFile; |
1093 | QTemporaryFile readFile; |
1094 | |
1095 | writeFile.open(); |
1096 | writeFile.close(); |
1097 | |
1098 | QVERIFY(readFile.open()); |
1099 | readFile.write(data: testString.toUtf8()); |
1100 | readFile.close(); |
1101 | |
1102 | // Avoid cached environment variables |
1103 | QQmlEngine engine; |
1104 | |
1105 | QQmlComponent component(&engine, testFileUrl(fileName: "file_request.qml" )); |
1106 | |
1107 | const QVariantMap properties = { |
1108 | {"writeURL" , QUrl::fromLocalFile(localfile: writeFile.fileName()).toString()}, |
1109 | {"readURL" , QUrl::fromLocalFile(localfile: readFile.fileName()).toString()} |
1110 | }; |
1111 | |
1112 | QScopedPointer<QObject> object(component.createWithInitialProperties(initialProperties: properties, context: engine.rootContext())); |
1113 | QVERIFY(!object.isNull()); |
1114 | |
1115 | verifyFunction(object.get(), writeFile); |
1116 | } |
1117 | |
1118 | // Test file:// requests |
1119 | void tst_qqmlxmlhttprequest::sendFileRequest() |
1120 | { |
1121 | // Test with both writing and reading allowed |
1122 | doFileRequest(verifyFunction: [](QObject* object, QTemporaryFile &writeFile) { |
1123 | QTRY_COMPARE(object->property("readResult" ).toString(), testString); |
1124 | |
1125 | QTRY_VERIFY(object->property("writeDone" ).toBool()); |
1126 | |
1127 | QVERIFY(writeFile.open()); |
1128 | QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString); |
1129 | writeFile.close(); |
1130 | }); |
1131 | } |
1132 | |
1133 | #if QT_CONFIG(process) |
1134 | void tst_qqmlxmlhttprequest::sendFileRequestNotSet() { |
1135 | if (qEnvironmentVariableIsSet(varName: "TEST_CUSTOM_PERMISSIONS" )) { |
1136 | // Test with no settings |
1137 | // Should just result in warnings in Qt 5 |
1138 | doFileRequest(verifyFunction: [](QObject* object, QTemporaryFile &writeFile) { |
1139 | QTRY_COMPARE(object->property("readResult" ).toString(), testString); |
1140 | |
1141 | QTRY_VERIFY(object->property("writeDone" ).toBool()); |
1142 | |
1143 | QVERIFY(writeFile.open()); |
1144 | QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString); |
1145 | writeFile.close(); |
1146 | }); |
1147 | return; |
1148 | } |
1149 | |
1150 | QProcess child; |
1151 | child.setProgram(QCoreApplication::applicationFilePath()); |
1152 | child.setArguments(QStringList(QLatin1String("sendFileRequestNotSet" ))); |
1153 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); |
1154 | env.insert(name: QLatin1String("TEST_CUSTOM_PERMISSIONS" ), value: QLatin1String("1" )); |
1155 | env.remove(name: "QML_XHR_ALLOW_FILE_WRITE" ); |
1156 | env.remove(name: "QML_XHR_ALLOW_FILE_READ" ); |
1157 | child.setProcessEnvironment(env); |
1158 | child.start(); |
1159 | QVERIFY(child.waitForFinished()); |
1160 | |
1161 | // Check exit code |
1162 | QCOMPARE(child.exitCode(), 0); |
1163 | |
1164 | // Check if all warnings were printed |
1165 | QString output = QString::fromUtf8(str: child.readAllStandardOutput()); |
1166 | |
1167 | |
1168 | const QString readingWarning = QLatin1String( |
1169 | "XMLHttpRequest: Using GET on a local file is dangerous " |
1170 | "and will be disabled by default in a future Qt version." |
1171 | "Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature." ); |
1172 | |
1173 | const QString writingWarning = QLatin1String( |
1174 | "XMLHttpRequest: Using PUT on a local file is dangerous " |
1175 | "and will be disabled by default in a future Qt version." |
1176 | "Set QML_XHR_ALLOW_FILE_WRITE to 1 if you wish to continue using this feature." ); |
1177 | |
1178 | QVERIFY(output.contains(readingWarning)); |
1179 | QVERIFY(output.contains(writingWarning)); |
1180 | } |
1181 | #endif |
1182 | |
1183 | #if QT_CONFIG(process) |
1184 | void tst_qqmlxmlhttprequest::sendFileRequestNoWrite() { |
1185 | if (qEnvironmentVariableIsSet(varName: "TEST_CUSTOM_PERMISSIONS" )) { |
1186 | // Test with no writing enabled |
1187 | doFileRequest(verifyFunction: [](QObject* object, QTemporaryFile &writeFile) { |
1188 | QTRY_COMPARE(object->property("readResult" ).toString(), testString); |
1189 | |
1190 | // Check that the file stays empty |
1191 | QVERIFY(writeFile.open()); |
1192 | QCOMPARE(QString::fromUtf8(writeFile.readAll()), "" ); |
1193 | writeFile.close(); |
1194 | }); |
1195 | return; |
1196 | } |
1197 | |
1198 | QProcess child; |
1199 | child.setProgram(QCoreApplication::applicationFilePath()); |
1200 | child.setArguments(QStringList(QLatin1String("sendFileRequestNoWrite" ))); |
1201 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); |
1202 | env.insert(name: QLatin1String("TEST_CUSTOM_PERMISSIONS" ), value: QLatin1String("1" )); |
1203 | env.insert(name: QLatin1String("QML_XHR_ALLOW_FILE_WRITE" ), value: QLatin1String("0" )); |
1204 | env.insert(name: QLatin1String("QML_XHR_ALLOW_FILE_READ" ), value: QLatin1String("1" )); |
1205 | child.setProcessEnvironment(env); |
1206 | child.start(); |
1207 | QVERIFY(child.waitForFinished()); |
1208 | QCOMPARE(child.exitCode(), 0); |
1209 | } |
1210 | #endif |
1211 | |
1212 | #if QT_CONFIG(process) |
1213 | void tst_qqmlxmlhttprequest::sendFileRequestNoRead() { |
1214 | if (qEnvironmentVariableIsSet(varName: "TEST_CUSTOM_PERMISSIONS" )) { |
1215 | // Test with no reading enabled |
1216 | doFileRequest(verifyFunction: [](QObject* object, QTemporaryFile &writeFile) { |
1217 | // Check that the write happens |
1218 | QTRY_VERIFY(object->property("writeDone" ).toBool()); |
1219 | |
1220 | QVERIFY(writeFile.open()); |
1221 | QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString); |
1222 | writeFile.close(); |
1223 | |
1224 | // Verify that the read has not yielded any value |
1225 | QVERIFY(object->property("readResult" ).isNull()); |
1226 | }); |
1227 | return; |
1228 | } |
1229 | |
1230 | QProcess child; |
1231 | child.setProgram(QCoreApplication::applicationFilePath()); |
1232 | child.setArguments(QStringList(QLatin1String("sendFileRequestNoRead" ))); |
1233 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); |
1234 | env.insert(name: QLatin1String("TEST_CUSTOM_PERMISSIONS" ), value: QLatin1String("1" )); |
1235 | env.insert(name: QLatin1String("QML_XHR_ALLOW_FILE_WRITE" ), value: QLatin1String("1" )); |
1236 | env.insert(name: QLatin1String("QML_XHR_ALLOW_FILE_READ" ), value: QLatin1String("0" )); |
1237 | child.setProcessEnvironment(env); |
1238 | child.start(); |
1239 | QVERIFY(child.waitForFinished()); |
1240 | QCOMPARE(child.exitCode(), 0); |
1241 | } |
1242 | #endif |
1243 | |
1244 | void tst_qqmlxmlhttprequest::sendPropfind() |
1245 | { |
1246 | const QString prefix = "WebDAV//" ; |
1247 | |
1248 | QFETCH(QString, qml); |
1249 | QFETCH(QString, resource); |
1250 | QFETCH(QString, expectedFile); |
1251 | QFETCH(QString, ); |
1252 | QFETCH(QString, replyBody); |
1253 | |
1254 | TestHTTPServer server; |
1255 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1256 | |
1257 | QVERIFY(server.wait(testFileUrl(prefix + expectedFile), |
1258 | testFileUrl(prefix + replyHeader), |
1259 | testFileUrl(prefix + replyBody))); |
1260 | |
1261 | QQmlComponent component(engine.get(), testFileUrl(fileName: prefix + qml)); |
1262 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1263 | QVERIFY(!object.isNull()); |
1264 | object->setProperty(name: "url" , value: server.urlString(documentPath: resource)); |
1265 | component.completeCreate(); |
1266 | |
1267 | QTRY_VERIFY(object->property("xmlTest" ).toBool()); |
1268 | QCOMPARE(object->property("typeTest" ).toBool(), true); |
1269 | } |
1270 | |
1271 | void tst_qqmlxmlhttprequest::sendPropfind_data() |
1272 | { |
1273 | QTest::addColumn<QString>(name: "qml" ); |
1274 | QTest::addColumn<QString>(name: "resource" ); |
1275 | QTest::addColumn<QString>(name: "expectedFile" ); |
1276 | QTest::addColumn<QString>(name: "replyHeader" ); |
1277 | QTest::addColumn<QString>(name: "replyBody" ); |
1278 | |
1279 | QTest::newRow(dataTag: "Send PROPFIND for file (bigbox, author, DingALing, Random properties). Get response with responseXML." ) << "sendPropfind.responseXML.qml" << "/file" << "propfind.file.expect" << "propfind.file.reply.header" << "propfind.file.reply.body" ; |
1280 | QTest::newRow(dataTag: "Send PROPFIND for file (bigbox, author, DingALing, Random properties). Get response with response." ) << "sendPropfind.response.qml" << "/file" << "propfind.file.expect" << "propfind.file.reply.header" << "propfind.file.reply.body" ; |
1281 | QTest::newRow(dataTag: "Send PROPFIND \"allprop\" request for collection." ) << "sendPropfind.collection.allprop.qml" << "/container/" << "propfind.collection.allprop.expect" << "propfind.file.reply.header" << "propfind.collection.allprop.reply.body" ; |
1282 | } |
1283 | |
1284 | // Test that calling hte XMLHttpRequest methods on a non-XMLHttpRequest object |
1285 | // throws an exception |
1286 | void tst_qqmlxmlhttprequest::invalidMethodUsage() |
1287 | { |
1288 | QQmlComponent component(engine.get(), testFileUrl(fileName: "invalidMethodUsage.qml" )); |
1289 | QScopedPointer<QObject> object(component.create()); |
1290 | QVERIFY(!object.isNull()); |
1291 | |
1292 | QCOMPARE(object->property("readyState" ).toBool(), true); |
1293 | QCOMPARE(object->property("status" ).toBool(), true); |
1294 | QCOMPARE(object->property("statusText" ).toBool(), true); |
1295 | QCOMPARE(object->property("responseText" ).toBool(), true); |
1296 | QCOMPARE(object->property("responseXML" ).toBool(), true); |
1297 | |
1298 | QCOMPARE(object->property("open" ).toBool(), true); |
1299 | QCOMPARE(object->property("setRequestHeader" ).toBool(), true); |
1300 | QCOMPARE(object->property("send" ).toBool(), true); |
1301 | QCOMPARE(object->property("abort" ).toBool(), true); |
1302 | QCOMPARE(object->property("getResponseHeader" ).toBool(), true); |
1303 | QCOMPARE(object->property("getAllResponseHeaders" ).toBool(), true); |
1304 | } |
1305 | |
1306 | // Test that XMLHttpRequest transparently redirects |
1307 | void tst_qqmlxmlhttprequest::redirects() |
1308 | { |
1309 | { |
1310 | TestHTTPServer server; |
1311 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1312 | server.addRedirect(filename: "redirect.html" , redirectName: server.urlString(documentPath: "/redirecttarget.html" )); |
1313 | server.serveDirectory(dataDirectory()); |
1314 | |
1315 | QQmlComponent component(engine.get(), testFileUrl(fileName: "redirects.qml" )); |
1316 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1317 | QVERIFY(!object.isNull()); |
1318 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/redirect.html" )); |
1319 | object->setProperty(name: "expectedText" , value: "" ); |
1320 | component.completeCreate(); |
1321 | |
1322 | QTRY_VERIFY(object->property("done" ).toBool()); |
1323 | QCOMPARE(object->property("dataOK" ).toBool(), true); |
1324 | } |
1325 | |
1326 | { |
1327 | TestHTTPServer server; |
1328 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1329 | server.addRedirect(filename: "redirect.html" , redirectName: server.urlString(documentPath: "/redirectmissing.html" )); |
1330 | server.serveDirectory(dataDirectory()); |
1331 | |
1332 | QQmlComponent component(engine.get(), testFileUrl(fileName: "redirectError.qml" )); |
1333 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1334 | QVERIFY(!object.isNull()); |
1335 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/redirect.html" )); |
1336 | object->setProperty(name: "expectedText" , value: "" ); |
1337 | component.completeCreate(); |
1338 | |
1339 | QTRY_VERIFY(object->property("done" ).toBool()); |
1340 | QCOMPARE(object->property("dataOK" ).toBool(), true); |
1341 | } |
1342 | |
1343 | { |
1344 | TestHTTPServer server; |
1345 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1346 | server.addRedirect(filename: "redirect.html" , redirectName: server.urlString(documentPath: "/redirect.html" )); |
1347 | server.serveDirectory(dataDirectory()); |
1348 | |
1349 | QQmlComponent component(engine.get(), testFileUrl(fileName: "redirectRecur.qml" )); |
1350 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1351 | QVERIFY(!object.isNull()); |
1352 | object->setProperty(name: "url" , value: server.urlString(documentPath: "/redirect.html" )); |
1353 | object->setProperty(name: "expectedText" , value: "" ); |
1354 | component.completeCreate(); |
1355 | |
1356 | for (int ii = 0; ii < 60; ++ii) { |
1357 | if (object->property(name: "done" ).toBool()) break; |
1358 | QTest::qWait(ms: 50); |
1359 | } |
1360 | QVERIFY(object->property("done" ).toBool()); |
1361 | |
1362 | QCOMPARE(object->property("dataOK" ).toBool(), true); |
1363 | } |
1364 | } |
1365 | |
1366 | void tst_qqmlxmlhttprequest::responseXML_invalid() |
1367 | { |
1368 | QQmlComponent component(engine.get(), testFileUrl(fileName: "responseXML_invalid.qml" )); |
1369 | QScopedPointer<QObject> object(component.create()); |
1370 | QVERIFY(!object.isNull()); |
1371 | |
1372 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1373 | |
1374 | QCOMPARE(object->property("xmlNull" ).toBool(), true); |
1375 | } |
1376 | |
1377 | // Test the Document DOM element |
1378 | void tst_qqmlxmlhttprequest::document() |
1379 | { |
1380 | QQmlComponent component(engine.get(), testFileUrl(fileName: "document.qml" )); |
1381 | QScopedPointer<QObject> object(component.create()); |
1382 | QVERIFY(!object.isNull()); |
1383 | |
1384 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1385 | |
1386 | QCOMPARE(object->property("xmlTest" ).toBool(), true); |
1387 | } |
1388 | |
1389 | // Test the Element DOM element |
1390 | void tst_qqmlxmlhttprequest::element() |
1391 | { |
1392 | QQmlComponent component(engine.get(), testFileUrl(fileName: "element.qml" )); |
1393 | QScopedPointer<QObject> object(component.create()); |
1394 | QVERIFY(!object.isNull()); |
1395 | |
1396 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1397 | |
1398 | QCOMPARE(object->property("xmlTest" ).toBool(), true); |
1399 | } |
1400 | |
1401 | // Test the Attr DOM element |
1402 | void tst_qqmlxmlhttprequest::attr() |
1403 | { |
1404 | QQmlComponent component(engine.get(), testFileUrl(fileName: "attr.qml" )); |
1405 | QScopedPointer<QObject> object(component.create()); |
1406 | QVERIFY(!object.isNull()); |
1407 | |
1408 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1409 | |
1410 | QCOMPARE(object->property("xmlTest" ).toBool(), true); |
1411 | } |
1412 | |
1413 | // Test the Text DOM element |
1414 | void tst_qqmlxmlhttprequest::text() |
1415 | { |
1416 | QQmlComponent component(engine.get(), testFileUrl(fileName: "text.qml" )); |
1417 | QScopedPointer<QObject> object(component.create()); |
1418 | QVERIFY(!object.isNull()); |
1419 | |
1420 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1421 | |
1422 | QCOMPARE(object->property("xmlTest" ).toBool(), true); |
1423 | QCOMPARE(object->property("status" ).toInt(), 200); |
1424 | } |
1425 | |
1426 | // Test the CDataSection DOM element |
1427 | void tst_qqmlxmlhttprequest::cdata() |
1428 | { |
1429 | QQmlComponent component(engine.get(), testFileUrl(fileName: "cdata.qml" )); |
1430 | QScopedPointer<QObject> object(component.create()); |
1431 | QVERIFY(!object.isNull()); |
1432 | |
1433 | QTRY_VERIFY(object->property("dataOK" ).toBool()); |
1434 | |
1435 | QCOMPARE(object->property("xmlTest" ).toBool(), true); |
1436 | QCOMPARE(object->property("status" ).toInt(), 200); |
1437 | } |
1438 | |
1439 | void tst_qqmlxmlhttprequest::noQmlContext() |
1440 | { |
1441 | TestHTTPServer server; |
1442 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1443 | QVERIFY(server.wait(testFileUrl("open_network.expect" ), |
1444 | testFileUrl("open_network.reply" ), |
1445 | testFileUrl("testdocument.html" ))); |
1446 | QUrl url = server.urlString(QStringLiteral("/testdocument.html" )); |
1447 | |
1448 | QQmlEngine engine; |
1449 | |
1450 | QFile f(testFile(fileName: "noqmlcontext.js" )); |
1451 | QVERIFY(f.open(QIODevice::ReadOnly)); |
1452 | QString script = QString::fromUtf8(str: f.readAll()); |
1453 | QJSValue testFunction = engine.evaluate(program: script); |
1454 | QVERIFY(testFunction.isCallable()); |
1455 | |
1456 | QJSValue resultCollector = engine.newObject(); |
1457 | |
1458 | testFunction.call(args: QJSValueList() << url.toString() << resultCollector); |
1459 | |
1460 | QTRY_COMPARE(resultCollector.property("responseText" ).toString(), "QML Rocks!\n" ); |
1461 | } |
1462 | |
1463 | void tst_qqmlxmlhttprequest::stateChangeCallingContext() |
1464 | { |
1465 | #ifdef Q_OS_WIN |
1466 | QSKIP("QTBUG-26738" ); |
1467 | #endif |
1468 | |
1469 | // ensure that we don't crash by attempting to evaluate |
1470 | // without a valid calling context. |
1471 | |
1472 | TestHTTPServer server; |
1473 | QVERIFY2(server.listen(), qPrintable(server.errorString())); |
1474 | server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); |
1475 | |
1476 | QQmlComponent component(engine.get(), testFileUrl(fileName: "stateChangeCallingContext.qml" )); |
1477 | QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext())); |
1478 | QVERIFY(!object.isNull()); |
1479 | object->setProperty(name: "serverBaseUrl" , value: server.baseUrl().toString()); |
1480 | component.completeCreate(); |
1481 | server.sendDelayedItem(); |
1482 | QTRY_VERIFY(object->property("success" ).toBool()); |
1483 | } |
1484 | |
1485 | QTEST_MAIN(tst_qqmlxmlhttprequest) |
1486 | |
1487 | #include "tst_qqmlxmlhttprequest.moc" |
1488 | |