From 89fa7ae6d922ff5b62fca65eab95f35845c069eb Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 9 Nov 2009 19:28:31 +1000 Subject: XMLHttpRequest tests --- src/declarative/qml/qmlxmlhttprequest.cpp | 136 +++++-- tests/auto/declarative/declarative.pro | 4 +- .../xmlhttprequest/data/constructor.qml | 14 + .../xmlhttprequest/data/defaultState.qml | 30 ++ .../xmlhttprequest/data/domExceptionCodes.qml | 60 +++ .../xmlhttprequest/data/instanceStateValues.qml | 33 ++ .../auto/declarative/xmlhttprequest/data/open.qml | 53 +++ .../xmlhttprequest/data/open_arg_count.1.qml | 18 + .../xmlhttprequest/data/open_arg_count.2.qml | 18 + .../xmlhttprequest/data/open_invalid_method.qml | 16 + .../xmlhttprequest/data/open_network.expect | 7 + .../xmlhttprequest/data/open_network.reply | 2 + .../xmlhttprequest/data/open_network.wait | 0 .../declarative/xmlhttprequest/data/open_sync.qml | 17 + .../xmlhttprequest/data/open_username.qml | 54 +++ .../xmlhttprequest/data/seconddocument.html | 1 + .../xmlhttprequest/data/setRequestHeader.expect | 9 + .../xmlhttprequest/data/setRequestHeader.qml | 28 ++ .../xmlhttprequest/data/setRequestHeader.reply | 2 + .../data/setRequestHeader_illegalName.qml | 55 +++ .../xmlhttprequest/data/setRequestHeader_sent.qml | 31 ++ .../data/setRequestHeader_unsent.qml | 17 + .../xmlhttprequest/data/staticStateValues.qml | 24 ++ .../xmlhttprequest/data/testdocument.html | 1 + .../declarative/xmlhttprequest/testhttpserver.cpp | 148 +++++++ .../declarative/xmlhttprequest/testhttpserver.h | 75 ++++ .../xmlhttprequest/tst_xmlhttprequest.cpp | 426 +++++++++++++++++++++ .../declarative/xmlhttprequest/xmlhttprequest.pro | 12 + 28 files changed, 1256 insertions(+), 35 deletions(-) create mode 100644 tests/auto/declarative/xmlhttprequest/data/constructor.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/defaultState.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/domExceptionCodes.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/instanceStateValues.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_arg_count.1.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_arg_count.2.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_invalid_method.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_network.expect create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_network.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_network.wait create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_sync.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/open_username.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/seconddocument.html create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader.expect create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader_illegalName.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader_sent.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/setRequestHeader_unsent.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/staticStateValues.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/testdocument.html create mode 100644 tests/auto/declarative/xmlhttprequest/testhttpserver.cpp create mode 100644 tests/auto/declarative/xmlhttprequest/testhttpserver.h create mode 100644 tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp create mode 100644 tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp index 0c0cd9c..f51b59f 100644 --- a/src/declarative/qml/qmlxmlhttprequest.cpp +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -54,8 +54,37 @@ #include -// ### Find real values -#define INVALID_STATE_ERR ((QScriptContext::Error)15) +// From DOM-Level-3-Core spec +// http://www.w3.org/TR/DOM-Level-3-Core/core.html +#define INDEX_SIZE_ERR 1 +#define DOMSTRING_SIZE_ERR 2 +#define HIERARCHY_REQUEST_ERR 3 +#define WRONG_DOCUMENT_ERR 4 +#define INVALID_CHARACTER_ERR 5 +#define NO_DATA_ALLOWED_ERR 6 +#define NO_MODIFICATION_ALLOWED_ERR 7 +#define NOT_FOUND_ERR 8 +#define NOT_SUPPORTED_ERR 9 +#define INUSE_ATTRIBUTE_ERR 10 +#define INVALID_STATE_ERR 11 +#define SYNTAX_ERR 12 +#define INVALID_MODIFICATION_ERR 13 +#define NAMESPACE_ERR 14 +#define INVALID_ACCESS_ERR 15 +#define VALIDATION_ERR 16 +#define TYPE_MISMATCH_ERR 17 + +#define THROW_DOM(error, desc) \ +{ \ + QScriptValue errorValue = context->throwError(QLatin1String(desc)); \ + errorValue.setProperty(QLatin1String("code"), error); \ + return errorValue; \ +} + +#define THROW_SYNTAX(desc) \ + return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc)); +#define THROW_REFERENCE(desc) \ + return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc)); #define D(arg) (arg)->release() #define A(arg) (arg)->addref() @@ -1189,10 +1218,11 @@ void QmlXMLHttpRequest::destroyNetwork() static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine) { QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (context->argumentCount() < 2 || context->argumentCount() > 5) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); // Argument 0 - Method QString method = context->argument(0).toString().toUpper(); @@ -1200,23 +1230,21 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin method != QLatin1String("PUT") && method != QLatin1String("HEAD") && method != QLatin1String("POST")) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Unsupported method")); + THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL - QUrl url(context->argument(1).toString()); // ### Need to resolve correctly + QUrl url(context->argument(1).toString()); if (url.isRelative()) { - QmlContext *ctxt = QmlEnginePrivate::get(engine)->currentExpression?QmlEnginePrivate::get(engine)->currentExpression->context():0; - if (ctxt) - url = ctxt->resolvedUrl(url); - else - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Relative URLs not supported")); + QmlContext *ctxt = QmlEnginePrivate::get(engine)->getContext(context); + Q_ASSERT(ctxt); + url = ctxt->resolvedUrl(url); } // Argument 2 - async (optional) if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Synchronous call not supported")); + THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported"); // Argument 3/4 - user/pass (optional) @@ -1241,15 +1269,16 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) { QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (context->argumentCount() != 2) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + THROW_SYNTAX("Incorrect argument count"); if (request->readyState() != QmlXMLHttpRequest::Opened || request->sendFlag()) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); QString name = context->argument(0).toString(); @@ -1288,13 +1317,14 @@ static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *engine) { QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (request->readyState() != QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); if (request->sendFlag()) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); QByteArray data; if (context->argumentCount() > 0) @@ -1308,7 +1338,8 @@ static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngin static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *engine) { QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); request->abort(); @@ -1319,15 +1350,16 @@ static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (context->argumentCount() != 1) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + THROW_SYNTAX("Incorrect argument count"); if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done && request->readyState() != QmlXMLHttpRequest::HeadersReceived) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); QString headerName = context->argument(0).toString(); @@ -1338,15 +1370,16 @@ static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *cont { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (context->argumentCount() != 0) - return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + THROW_SYNTAX("Incorrect argument count"); if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done && request->readyState() != QmlXMLHttpRequest::HeadersReceived) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); return QScriptValue(request->headers()); } @@ -1356,7 +1389,8 @@ static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScrip { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); return QScriptValue(request->readyState()); } @@ -1365,11 +1399,12 @@ static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEng { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (request->readyState() == QmlXMLHttpRequest::Unsent || request->readyState() == QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); if (request->errorFlag()) return QScriptValue(0); @@ -1381,11 +1416,12 @@ static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScrip { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (request->readyState() == QmlXMLHttpRequest::Unsent || request->readyState() == QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); if (request->errorFlag()) return QScriptValue(0); @@ -1397,19 +1433,21 @@ static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScr { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done) return QScriptValue(QString()); - else + else return QScriptValue(request->responseBody()); } static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine) { QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done) @@ -1422,7 +1460,8 @@ static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context { Q_UNUSED(engine) QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); - if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); if (context->argumentCount()) request->setCallback(context->argument(0)); @@ -1459,6 +1498,13 @@ void qt_add_qmlxmlhttprequest(QScriptEngine *engine) prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + // State values + prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + // Constructor QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype); constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); @@ -1467,6 +1513,28 @@ void qt_add_qmlxmlhttprequest(QScriptEngine *engine) constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor); + + // DOM Exception + QScriptValue domExceptionPrototype = engine->newObject(); + domExceptionPrototype.setProperty("INDEX_SIZE_ERR", INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("DOMSTRING_SIZE_ERR", DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("HIERARCHY_REQUEST_ERR", HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("WRONG_DOCUMENT_ERR", WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("INVALID_CHARACTER_ERR", INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("NO_DATA_ALLOWED_ERR", NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("NO_MODIFICATION_ALLOWED_ERR", NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("NOT_FOUND_ERR", NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("NOT_SUPPORTED_ERR", NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("INUSE_ATTRIBUTE_ERR", INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("INVALID_STATE_ERR", INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("SYNTAX_ERR", SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("INVALID_MODIFICATION_ERR", INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("NAMESPACE_ERR", NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("INVALID_ACCESS_ERR", INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("VALIDATION_ERR", VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty("TYPE_MISMATCH_ERR", TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype); } #include "qmlxmlhttprequest.moc" diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 134ae1b..4c31998 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -46,7 +46,9 @@ SUBDIRS += \ sql \ # Cover states \ # Cover valuetypes \ # Cover - visual # Cover + visual \ # Cover + xmlhttprequest # Cover + # Tests which should run in Pulse PULSE_TESTS = $$SUBDIRS diff --git a/tests/auto/declarative/xmlhttprequest/data/constructor.qml b/tests/auto/declarative/xmlhttprequest/data/constructor.qml new file mode 100644 index 0000000..4b9e9ce --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/constructor.qml @@ -0,0 +1,14 @@ +import Qt 4.6 + +Object { + property bool calledAsConstructor + property bool calledAsFunction + + Component.onCompleted: { + var x1 = new XMLHttpRequest; + var x2 = XMLHttpRequest(); + + calledAsConstructor = (x1 != null && x1 instanceof XMLHttpRequest); + calledAsFunction = (x2 == undefined); + } +} diff --git a/tests/auto/declarative/xmlhttprequest/data/defaultState.qml b/tests/auto/declarative/xmlhttprequest/data/defaultState.qml new file mode 100644 index 0000000..5cc2971 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/defaultState.qml @@ -0,0 +1,30 @@ +import Qt 4.6 + +Object { + property int readyState + property bool statusIsException: false + property bool statusTextIsException: false + property string responseText + property bool responseXMLIsNull + + Component.onCompleted: { + var xhr = new XMLHttpRequest(); + + readyState = xhr.readyState; + try { + status = xhr.status; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + statusIsException = true; + } + try { + statusText = xhr.statusText; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + statusTextIsException = true; + } + responseText = xhr.responseText; + responseXMLIsNull = (xhr.responseXML == null); + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/domExceptionCodes.qml b/tests/auto/declarative/xmlhttprequest/data/domExceptionCodes.qml new file mode 100644 index 0000000..a4ab66c --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/domExceptionCodes.qml @@ -0,0 +1,60 @@ +import Qt 4.6 + +Object { + property int index_size_err: DOMException.INDEX_SIZE_ERR + property int domstring_size_err: DOMException.DOMSTRING_SIZE_ERR + property int hierarchy_request_err: DOMException.HIERARCHY_REQUEST_ERR + property int wrong_document_err: DOMException.WRONG_DOCUMENT_ERR + property int invalid_character_err: DOMException.INVALID_CHARACTER_ERR + property int no_data_allowed_err: DOMException.NO_DATA_ALLOWED_ERR + property int no_modification_allowed_err: DOMException.NO_MODIFICATION_ALLOWED_ERR + property int not_found_err: DOMException.NOT_FOUND_ERR + property int not_supported_err: DOMException.NOT_SUPPORTED_ERR + property int inuse_attribute_err: DOMException.INUSE_ATTRIBUTE_ERR + property int invalid_state_err: DOMException.INVALID_STATE_ERR + property int syntax_err: DOMException.SYNTAX_ERR + property int invalid_modification_err: DOMException.INVALID_MODIFICATION_ERR + property int namespace_err: DOMException.NAMESPACE_ERR + property int invalid_access_err: DOMException.INVALID_ACCESS_ERR + property int validation_err: DOMException.VALIDATION_ERR + property int type_mismatch_err: DOMException.TYPE_MISMATCH_ERR + + Component.onCompleted: { + // Attempt to overwrite and delete values + DOMException.INDEX_SIZE_ERR = 44; + DOMException.DOMSTRING_SIZE_ERR = 44; + DOMException.HIERARCHY_REQUEST_ERR = 44; + DOMException.WRONG_DOCUMENT_ERR = 44; + DOMException.INVALID_CHARACTER_ERR = 44; + DOMException.NO_DATA_ALLOWED_ERR = 44; + DOMException.NO_MODIFICATION_ALLOWED_ERR = 44; + DOMException.NOT_FOUND_ERR = 44; + DOMException.NOT_SUPPORTED_ERR = 44; + DOMException.INUSE_ATTRIBUTE_ERR = 44; + DOMException.INVALID_STATE_ERR = 44; + DOMException.SYNTAX_ERR = 44; + DOMException.INVALID_MODIFICATION_ERR = 44; + DOMException.NAMESPACE_ERR = 44; + DOMException.INVALID_ACCESS_ERR = 44; + DOMException.VALIDATION_ERR = 44; + DOMException.TYPE_MISMATCH_ERR = 44; + + delete DOMException.INDEX_SIZE_ERR; + delete DOMException.DOMSTRING_SIZE_ERR; + delete DOMException.HIERARCHY_REQUEST_ERR; + delete DOMException.WRONG_DOCUMENT_ERR; + delete DOMException.INVALID_CHARACTER_ERR; + delete DOMException.NO_DATA_ALLOWED_ERR; + delete DOMException.NO_MODIFICATION_ALLOWED_ERR; + delete DOMException.NOT_FOUND_ERR; + delete DOMException.NOT_SUPPORTED_ERR; + delete DOMException.INUSE_ATTRIBUTE_ERR; + delete DOMException.INVALID_STATE_ERR; + delete DOMException.SYNTAX_ERR; + delete DOMException.INVALID_MODIFICATION_ERR; + delete DOMException.NAMESPACE_ERR; + delete DOMException.INVALID_ACCESS_ERR; + delete DOMException.VALIDATION_ERR; + delete DOMException.TYPE_MISMATCH_ERR; + } +} diff --git a/tests/auto/declarative/xmlhttprequest/data/instanceStateValues.qml b/tests/auto/declarative/xmlhttprequest/data/instanceStateValues.qml new file mode 100644 index 0000000..ab3064f --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/instanceStateValues.qml @@ -0,0 +1,33 @@ +import Qt 4.6 + +Object { + property int unsent + property int opened + property int headers_received + property int loading + property int done + + Component.onCompleted: { + // Attempt to overwrite and delete values + var x = new XMLHttpRequest(); + + x.UNSENT = 9; + x.OPENED = 9; + x.HEADERS_RECEIVED = 9; + x.LOADING = 9; + x.DONE = 9; + + delete x.UNSENT; + delete x.OPENED; + delete x.HEADERS_RECEIVED; + delete x.LOADING; + delete x.DONE; + + unsent = x.UNSENT + opened = x.OPENED + headers_received = x.HEADERS_RECEIVED + loading = x.LOADING + done = x.DONE + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/open.qml b/tests/auto/declarative/xmlhttprequest/data/open.qml new file mode 100644 index 0000000..7729bab --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open.qml @@ -0,0 +1,53 @@ +import Qt 4.6 + +Object { + property string url + + property bool readyState: false + property bool openedState: false + + property bool status: false + property bool statusText: false + property bool responseText: false + property bool responseXML: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("GET", url); + + if (x.readyState == XMLHttpRequest.OPENED) + openedState = true; + + try { + var a = x.status; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + status = true; + } + try { + var a = x.statusText; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + statusText = true; + } + responseText = (x.responseText == ""); + responseXML = (x.responseXML == null); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + + x.send() + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/open_arg_count.1.qml b/tests/auto/declarative/xmlhttprequest/data/open_arg_count.1.qml new file mode 100644 index 0000000..74f13ba --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_arg_count.1.qml @@ -0,0 +1,18 @@ +import Qt 4.6 + +Object { + property bool exceptionThrown: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.open("GET"); + } catch (e) { + if (e.code == DOMException.SYNTAX_ERR) + exceptionThrown = true; + } + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/open_arg_count.2.qml b/tests/auto/declarative/xmlhttprequest/data/open_arg_count.2.qml new file mode 100644 index 0000000..35dce9f --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_arg_count.2.qml @@ -0,0 +1,18 @@ +import Qt 4.6 + +Object { + property bool exceptionThrown: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.open("GET", "http://www.nokia.com", true, "user", "password", "extra"); + } catch (e) { + if (e.code == DOMException.SYNTAX_ERR) + exceptionThrown = true; + } + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/open_invalid_method.qml b/tests/auto/declarative/xmlhttprequest/data/open_invalid_method.qml new file mode 100644 index 0000000..7fb1a4c --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_invalid_method.qml @@ -0,0 +1,16 @@ +import Qt 4.6 + +Object { + property bool exceptionThrown: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.open("BLAH", "http://www.nokia.com"); + } catch (e) { + if (e.code == DOMException.SYNTAX_ERR) + exceptionThrown = true; + } + } +} diff --git a/tests/auto/declarative/xmlhttprequest/data/open_network.expect b/tests/auto/declarative/xmlhttprequest/data/open_network.expect new file mode 100644 index 0000000..40e648e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_network.expect @@ -0,0 +1,7 @@ +GET /testdocument.html HTTP/1.1 +Connection: Keep-Alive +Accept-Encoding: gzip +accept-language: en,* +User-Agent: Mozilla/5.0 +Host: localhost:14445 + diff --git a/tests/auto/declarative/xmlhttprequest/data/open_network.reply b/tests/auto/declarative/xmlhttprequest/data/open_network.reply new file mode 100644 index 0000000..35b11f4 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_network.reply @@ -0,0 +1,2 @@ +HTTP/1.0 200 OK +Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/xmlhttprequest/data/open_network.wait b/tests/auto/declarative/xmlhttprequest/data/open_network.wait new file mode 100644 index 0000000..e69de29 diff --git a/tests/auto/declarative/xmlhttprequest/data/open_sync.qml b/tests/auto/declarative/xmlhttprequest/data/open_sync.qml new file mode 100644 index 0000000..7133e81 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_sync.qml @@ -0,0 +1,17 @@ +import Qt 4.6 + +Object { + property bool exceptionThrown: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.open("GET", "http://www.nokia.com", false); + } catch (e) { + if (e.code == DOMException.NOT_SUPPORTED_ERR) + exceptionThrown = true; + } + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/open_username.qml b/tests/auto/declarative/xmlhttprequest/data/open_username.qml new file mode 100644 index 0000000..c38110c --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_username.qml @@ -0,0 +1,54 @@ +import Qt 4.6 + +Object { + property string url + + property bool readyState: false + property bool openedState: false + + property bool status: false + property bool statusText: false + property bool responseText: false + property bool responseXML: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("GET", url, true, "sampleusername", "password"); + + if (x.readyState == XMLHttpRequest.OPENED) + openedState = true; + + try { + var a = x.status; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + status = true; + } + try { + var a = x.statusText; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + statusText = true; + } + responseText = (x.responseText == ""); + responseXML = (x.responseXML == null); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + + x.send() + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/seconddocument.html b/tests/auto/declarative/xmlhttprequest/data/seconddocument.html new file mode 100644 index 0000000..a33f44b --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/seconddocument.html @@ -0,0 +1 @@ +This should not be read! diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.expect b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.expect new file mode 100644 index 0000000..031ddff --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.expect @@ -0,0 +1,9 @@ +GET /testdocument.html HTTP/1.1 +TEST-HEADER: value +TEST-HEADER2: value,value2 +Connection: Keep-Alive +Accept-Encoding: gzip +accept-language: en,* +User-Agent: Mozilla/5.0 +Host: localhost:14445 + diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.qml b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.qml new file mode 100644 index 0000000..8ea587a --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.qml @@ -0,0 +1,28 @@ +import Qt 4.6 + +Object { + property string url + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", url); + + x.setRequestHeader("Test-header", "value"); + x.setRequestHeader("Test-header2", "value"); + x.setRequestHeader("Test-header2", "value2"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + x.send(); + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.reply b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.reply new file mode 100644 index 0000000..35b11f4 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader.reply @@ -0,0 +1,2 @@ +HTTP/1.0 200 OK +Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_illegalName.qml b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_illegalName.qml new file mode 100644 index 0000000..cf5ebcc --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_illegalName.qml @@ -0,0 +1,55 @@ +import Qt 4.6 + +Object { + property string url + property string header + + property bool readyState: false + property bool openedState: false + + property bool status: false + property bool statusText: false + property bool responseText: false + property bool responseXML: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("GET", url); + + if (x.readyState == XMLHttpRequest.OPENED) + openedState = true; + + try { + var a = x.status; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + status = true; + } + try { + var a = x.statusText; + } catch (error) { + if (error.code == DOMException.INVALID_STATE_ERR) + statusText = true; + } + responseText = (x.responseText == ""); + responseXML = (x.responseXML == null); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + + x.send() + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_sent.qml b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_sent.qml new file mode 100644 index 0000000..b637f17 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_sent.qml @@ -0,0 +1,31 @@ +import Qt 4.6 + +Object { + property string url + property bool test: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", url); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + x.send(); + + try { + x.setRequestHeader("Test-header", "value"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + test = true; + } + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_unsent.qml b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_unsent.qml new file mode 100644 index 0000000..4e89abf --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/setRequestHeader_unsent.qml @@ -0,0 +1,17 @@ +import Qt 4.6 + +Object { + property bool test: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.setRequestHeader("Test-header", "value"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + test = true; + } + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/staticStateValues.qml b/tests/auto/declarative/xmlhttprequest/data/staticStateValues.qml new file mode 100644 index 0000000..aaaadad --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/staticStateValues.qml @@ -0,0 +1,24 @@ +import Qt 4.6 + +Object { + property int unsent: XMLHttpRequest.UNSENT + property int opened: XMLHttpRequest.OPENED + property int headers_received: XMLHttpRequest.HEADERS_RECEIVED + property int loading: XMLHttpRequest.LOADING + property int done: XMLHttpRequest.DONE + + Component.onCompleted: { + // Attempt to overwrite and delete values + XMLHttpRequest.UNSENT = 9; + XMLHttpRequest.OPENED = 9; + XMLHttpRequest.HEADERS_RECEIVED = 9; + XMLHttpRequest.LOADING = 9; + XMLHttpRequest.DONE = 9; + + delete XMLHttpRequest.UNSENT; + delete XMLHttpRequest.OPENED; + delete XMLHttpRequest.HEADERS_RECEIVED; + delete XMLHttpRequest.LOADING; + delete XMLHttpRequest.DONE; + } +} diff --git a/tests/auto/declarative/xmlhttprequest/data/testdocument.html b/tests/auto/declarative/xmlhttprequest/data/testdocument.html new file mode 100644 index 0000000..8fe0f4b --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/testdocument.html @@ -0,0 +1 @@ +QML Rocks! diff --git a/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp b/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp new file mode 100644 index 0000000..021da05 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testhttpserver.h" +#include +#include +#include + +TestHTTPServer::TestHTTPServer(quint16 port) +: m_hasFailed(false) +{ + QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection())); + + server.listen(QHostAddress::Any, port); +} + +bool TestHTTPServer::isValid() const +{ + return server.isListening(); +} + +bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body) +{ + m_hasFailed = false; + + QFile expectFile(expect.toLocalFile()); + if (!expectFile.open(QIODevice::ReadOnly)) return false; + + QFile replyFile(reply.toLocalFile()); + if (!replyFile.open(QIODevice::ReadOnly)) return false; + + bodyData = QByteArray(); + QFile bodyFile(body.toLocalFile()); + if (bodyFile.open(QIODevice::ReadOnly)) { + bodyData = bodyFile.readAll(); + } + + waitData = expectFile.readAll(); + replyData = replyFile.readAll(); + + if (!replyData.endsWith('\n')) + replyData.append("\n"); + replyData.append("Content-length: " + QByteArray::number(bodyData.length())); + replyData .append("\n\n"); + + for (int ii = 0; ii < replyData.count(); ++ii) { + if (replyData.at(ii) == '\n' && (!ii || replyData.at(ii - 1) != '\r')) { + replyData.insert(ii, '\r'); + ++ii; + } + } + replyData.append(bodyData); + + return true; +} + +bool TestHTTPServer::hasFailed() const +{ + return m_hasFailed; +} + +void TestHTTPServer::newConnection() +{ + QTcpSocket *socket = server.nextPendingConnection(); + if (!socket) return; + + QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); + QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +void TestHTTPServer::disconnected() +{ + sender()->deleteLater(); +} + +void TestHTTPServer::readyRead() +{ + QTcpSocket *socket = qobject_cast(sender()); + if (!socket) return; + + QByteArray ba = socket->readAll(); + + if (m_hasFailed || waitData.isEmpty()) { + qWarning() << "TestHTTPServer: Unexpected data" << ba; + return; + } + + for (int ii = 0; ii < ba.count(); ++ii) { + const char c = ba.at(ii); + if (c == '\r' && waitData.isEmpty()) + continue; + else if (c == waitData.at(0)) + waitData = waitData.mid(1); + else if (c == '\r') + continue; + else { + QByteArray data = ba.mid(ii); + qWarning() << "TestHTTPServer: Unexpected data" << data; + m_hasFailed = true; + socket->disconnect(); + return; + } + } + + if (waitData.isEmpty()) { + socket->write(replyData); + socket->disconnect(); + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/testhttpserver.h b/tests/auto/declarative/xmlhttprequest/testhttpserver.h new file mode 100644 index 0000000..709532e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/testhttpserver.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TESTHTTPSERVER_H +#define TESTHTTPSERVER_H + +#include +#include +#include + +class TestHTTPServer : public QObject +{ + Q_OBJECT +public: + TestHTTPServer(quint16 port); + + bool isValid() const; + + bool wait(const QUrl &expect, const QUrl &reply, const QUrl &body); + bool hasFailed() const; + +private slots: + void newConnection(); + void disconnected(); + void readyRead(); + +private: + QByteArray waitData; + QByteArray replyData; + QByteArray bodyData; + bool m_hasFailed; + + QTcpServer server; +}; + +#endif // TESTHTTPSERVER_H + diff --git a/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp new file mode 100644 index 0000000..9acd6e6 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "testhttpserver.h" + +#define SERVER_PORT 14445 + +class tst_xmlhttprequest : public QObject +{ + Q_OBJECT +public: + tst_xmlhttprequest() {} + +private slots: + void domExceptionCodes(); + void staticStateValues(); + void instanceStateValues(); + void constructor(); + void defaultState(); + void open(); + void open_invalid_method(); + void open_sync(); + void open_arg_count(); + void setRequestHeader(); + void setRequestHeader_unsent(); + void setRequestHeader_illegalName_data(); + void setRequestHeader_illegalName(); + void setRequestHeader_sent(); + + // Crashes + // void outstanding_request_at_shutdown(); + +private: + QmlEngine engine; +}; + +class QWebPageWithJavaScriptConsoleMessages : public QWebPage { +public: + void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) + { + qWarning() << sourceID << ":" << lineNumber << ":" << message; + } +}; + +inline QUrl TEST_FILE(const QString &filename) +{ + return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename); +} + +// Test that the dom exception codes are correct +void tst_xmlhttprequest::domExceptionCodes() +{ + QmlComponent component(&engine, TEST_FILE("domExceptionCodes.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("index_size_err").toInt(), 1); + QCOMPARE(object->property("domstring_size_err").toInt(), 2); + QCOMPARE(object->property("hierarchy_request_err").toInt(), 3); + QCOMPARE(object->property("wrong_document_err").toInt(), 4); + QCOMPARE(object->property("invalid_character_err").toInt(), 5); + QCOMPARE(object->property("no_data_allowed_err").toInt(), 6); + QCOMPARE(object->property("no_modification_allowed_err").toInt(), 7); + QCOMPARE(object->property("not_found_err").toInt(), 8); + QCOMPARE(object->property("not_supported_err").toInt(), 9); + QCOMPARE(object->property("inuse_attribute_err").toInt(), 10); + QCOMPARE(object->property("invalid_state_err").toInt(), 11); + QCOMPARE(object->property("syntax_err").toInt(), 12); + QCOMPARE(object->property("invalid_modification_err").toInt(), 13); + QCOMPARE(object->property("namespace_err").toInt(), 14); + QCOMPARE(object->property("invalid_access_err").toInt(), 15); + QCOMPARE(object->property("validation_err").toInt(), 16); + QCOMPARE(object->property("type_mismatch_err").toInt(), 17); + + delete object; +} + +// Test that the state value properties on the XMLHttpRequest constructor have the correct values. +// ### WebKit does not do this, but it seems to fit the standard and QML better +void tst_xmlhttprequest::staticStateValues() +{ + QmlComponent component(&engine, TEST_FILE("staticStateValues.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("unsent").toInt(), 0); + QCOMPARE(object->property("opened").toInt(), 1); + QCOMPARE(object->property("headers_received").toInt(), 2); + QCOMPARE(object->property("loading").toInt(), 3); + QCOMPARE(object->property("done").toInt(), 4); + + delete object; +} + +// Test that the state value properties on instances have the correct values. +void tst_xmlhttprequest::instanceStateValues() +{ + QmlComponent component(&engine, TEST_FILE("instanceStateValues.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("unsent").toInt(), 0); + QCOMPARE(object->property("opened").toInt(), 1); + QCOMPARE(object->property("headers_received").toInt(), 2); + QCOMPARE(object->property("loading").toInt(), 3); + QCOMPARE(object->property("done").toInt(), 4); + + delete object; +} + +// Test calling constructor +void tst_xmlhttprequest::constructor() +{ + QmlComponent component(&engine, TEST_FILE("constructor.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("calledAsConstructor").toBool(), true); + QCOMPARE(object->property("calledAsFunction").toBool(), true); + + delete object; +} + +// Test that all the properties are set correctly before any request is sent +void tst_xmlhttprequest::defaultState() +{ + QmlComponent component(&engine, TEST_FILE("defaultState.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("readState").toInt(), 0); + QCOMPARE(object->property("statusIsException").toBool(), true); + QCOMPARE(object->property("statusTextIsException").toBool(), true); + QCOMPARE(object->property("responseText").toString(), QString()); + QCOMPARE(object->property("responseXMLIsNull").toBool(), true); + + delete object; +} + +#define TRY_WAIT(expr) \ + do { \ + for (int ii = 0; ii < 6; ++ii) { \ + if ((expr)) break; \ + QTest::qWait(50); \ + } \ + QVERIFY((expr)); \ + } while (false) + +// Test valid XMLHttpRequest.open() calls +void tst_xmlhttprequest::open() +{ + // Relative url + { + QmlComponent component(&engine, TEST_FILE("open.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + QCOMPARE(object->property("status").toBool(), true); + QCOMPARE(object->property("statusText").toBool(), true); + QCOMPARE(object->property("responseText").toBool(), true); + QCOMPARE(object->property("responseXML").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; + } + + // Absolute url + { + QmlComponent component(&engine, TEST_FILE("open.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", TEST_FILE("testdocument.html").toString()); + component.completeCreate(); + + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + QCOMPARE(object->property("status").toBool(), true); + QCOMPARE(object->property("statusText").toBool(), true); + QCOMPARE(object->property("responseText").toBool(), true); + QCOMPARE(object->property("responseXML").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; + } + + // Absolute network url + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("open_network.expect"), + TEST_FILE("open_network.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("open.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + QCOMPARE(object->property("status").toBool(), true); + QCOMPARE(object->property("statusText").toBool(), true); + QCOMPARE(object->property("responseText").toBool(), true); + QCOMPARE(object->property("responseXML").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; + } +} + +// Test that calling XMLHttpRequest.open() with an invalid method raises an exception +void tst_xmlhttprequest::open_invalid_method() +{ + QmlComponent component(&engine, TEST_FILE("open_invalid_method.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("exceptionThrown").toBool(), true); + + delete object; +} + +// Test that calling XMLHttpRequest.open() with sync raises an exception +void tst_xmlhttprequest::open_sync() +{ + QmlComponent component(&engine, TEST_FILE("open_sync.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("exceptionThrown").toBool(), true); + + delete object; +} + +// Calling with incorrect arg count raises an exception +void tst_xmlhttprequest::open_arg_count() +{ + { + QmlComponent component(&engine, TEST_FILE("open_arg_count.1.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("exceptionThrown").toBool(), true); + + delete object; + } + + { + QmlComponent component(&engine, TEST_FILE("open_arg_count.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("exceptionThrown").toBool(), true); + + delete object; + } +} + +// Test valid setRequestHeader() calls +void tst_xmlhttprequest::setRequestHeader() +{ + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("setRequestHeader.expect"), + TEST_FILE("setRequestHeader.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("setRequestHeader.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; +} + +// Test setting headers before open() throws exception +void tst_xmlhttprequest::setRequestHeader_unsent() +{ + QmlComponent component(&engine, TEST_FILE("setRequestHeader_unsent.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test").toBool(), true); + + delete object; +} + +void tst_xmlhttprequest::setRequestHeader_illegalName_data() +{ + QTest::addColumn("name"); + + QTest::newRow("Accept-Charset") << "AccePT-CHArset"; + QTest::newRow("Accept-Encoding") << "AccEpt-EnCOding"; + QTest::newRow("Connection") << "ConnECtion"; + QTest::newRow("Content-Length") << "ContEnt-LenGth"; + QTest::newRow("Cookie") << "CookIe"; + QTest::newRow("Cookie2") << "CoOkie2"; + QTest::newRow("Content-Transfer-Encoding") << "ConteNT-tRANSFER-eNCOding"; + QTest::newRow("Date") << "DaTE"; + QTest::newRow("Expect") << "ExPect"; + QTest::newRow("Host") << "HoST"; + QTest::newRow("Keep-Alive") << "KEEP-aLive"; + QTest::newRow("Referer") << "ReferEr"; + QTest::newRow("TE") << "Te"; + QTest::newRow("Trailer") << "TraILEr"; + QTest::newRow("Transfer-Encoding") << "tRANsfer-Encoding"; + QTest::newRow("Upgrade") << "UpgrADe"; + QTest::newRow("User-Agent") << "uSEr-Agent"; + QTest::newRow("Via") << "vIa"; + QTest::newRow("Proxy-") << "ProXy-"; + QTest::newRow("Sec-") << "SeC-"; + QTest::newRow("Proxy-*") << "Proxy-BLAH"; + QTest::newRow("Sec-*") << "Sec-F"; +} + +// Tests that using illegal header names has no effect +void tst_xmlhttprequest::setRequestHeader_illegalName() +{ + QFETCH(QString, name); + + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("open_network.expect"), + TEST_FILE("open_network.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("setRequestHeader_illegalName.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("header", name); + component.completeCreate(); + + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + QCOMPARE(object->property("status").toBool(), true); + QCOMPARE(object->property("statusText").toBool(), true); + QCOMPARE(object->property("responseText").toBool(), true); + QCOMPARE(object->property("responseXML").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; +} + +// Test that attempting to set a header after a request is sent throws an exception +void tst_xmlhttprequest::setRequestHeader_sent() +{ + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("open_network.expect"), + TEST_FILE("open_network.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("setRequestHeader_sent.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("test").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; +} + + +QTEST_MAIN(tst_xmlhttprequest) + +#include "tst_xmlhttprequest.moc" diff --git a/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro b/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro new file mode 100644 index 0000000..5d35a89 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative webkit network +macx:CONFIG -= app_bundle + +HEADERS += testhttpserver.h + +SOURCES += tst_xmlhttprequest.cpp \ + testhttpserver.cpp + + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" -- cgit v0.12