From bdb9c0ffa84bfab386de5550bd8f9b013288daca Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 10 Nov 2009 14:53:36 +1000 Subject: XMLHttpRequest tests --- src/declarative/qml/qmlxmlhttprequest.cpp | 115 +++++- .../declarative/xmlhttprequest/data/abort.expect | 10 + .../auto/declarative/xmlhttprequest/data/abort.qml | 42 +++ .../declarative/xmlhttprequest/data/abort.reply | 2 + .../xmlhttprequest/data/abort_opened.qml | 58 +++ .../xmlhttprequest/data/abort_unsent.qml | 54 +++ .../auto/declarative/xmlhttprequest/data/attr.qml | 80 ++++ .../auto/declarative/xmlhttprequest/data/attr.xml | 1 + .../declarative/xmlhttprequest/data/document.qml | 49 +++ .../declarative/xmlhttprequest/data/document.xml | 3 + .../declarative/xmlhttprequest/data/element.qml | 101 ++++++ .../declarative/xmlhttprequest/data/element.xml | 1 + .../xmlhttprequest/data/getAllResponseHeaders.qml | 65 ++++ .../xmlhttprequest/data/getResponseHeader.expect | 7 + .../xmlhttprequest/data/getResponseHeader.qml | 75 ++++ .../xmlhttprequest/data/getResponseHeader.reply | 7 + .../xmlhttprequest/data/responseText.qml | 52 +++ .../xmlhttprequest/data/responseXML_invalid.qml | 24 ++ .../xmlhttprequest/data/status.200.reply | 2 + .../xmlhttprequest/data/status.404.reply | 2 + .../declarative/xmlhttprequest/data/status.expect | 7 + .../declarative/xmlhttprequest/data/status.qml | 77 ++++ .../declarative/xmlhttprequest/data/statusText.qml | 77 ++++ .../declarative/xmlhttprequest/testhttpserver.cpp | 5 +- .../xmlhttprequest/tst_xmlhttprequest.cpp | 403 +++++++++++++++++++++ 25 files changed, 1304 insertions(+), 15 deletions(-) create mode 100644 tests/auto/declarative/xmlhttprequest/data/abort.expect create mode 100644 tests/auto/declarative/xmlhttprequest/data/abort.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/abort.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/abort_opened.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/abort_unsent.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/attr.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/attr.xml create mode 100644 tests/auto/declarative/xmlhttprequest/data/document.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/document.xml create mode 100644 tests/auto/declarative/xmlhttprequest/data/element.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/element.xml create mode 100644 tests/auto/declarative/xmlhttprequest/data/getAllResponseHeaders.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/getResponseHeader.expect create mode 100644 tests/auto/declarative/xmlhttprequest/data/getResponseHeader.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/getResponseHeader.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/responseText.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/responseXML_invalid.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/status.200.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/status.404.reply create mode 100644 tests/auto/declarative/xmlhttprequest/data/status.expect create mode 100644 tests/auto/declarative/xmlhttprequest/data/status.qml create mode 100644 tests/auto/declarative/xmlhttprequest/data/statusText.qml diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp index 6946e7a..a6cdfb1 100644 --- a/src/declarative/qml/qmlxmlhttprequest.cpp +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -134,7 +134,7 @@ public: class DocumentImpl : public QmlRefCount { public: - DocumentImpl() : root(0) {} + DocumentImpl() : root(0) { } virtual ~DocumentImpl() { if (root) D(root); } @@ -242,6 +242,22 @@ public: class Element : public Node { public: + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Attr : public Node +{ +public: + // JS API + static QScriptValue name(QScriptContext *context, QScriptEngine *engine); + static QScriptValue specified(QScriptContext *context, QScriptEngine *engine); + static QScriptValue value(QScriptContext *context, QScriptEngine *engine); + static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine); + static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue isId(QScriptContext *context, QScriptEngine *engine); + + // C++ API static QScriptValue prototype(QScriptEngine *); }; @@ -308,6 +324,7 @@ QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine) { Node node = qscriptvalue_cast(context->thisObject()); if (node.isNull()) return engine->undefinedValue(); + return QScriptValue(node.d->name); } @@ -316,6 +333,15 @@ QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine) Node node = qscriptvalue_cast(context->thisObject()); if (node.isNull()) return engine->undefinedValue(); + if (node.d->type == NodeImpl::Document || + node.d->type == NodeImpl::DocumentFragment || + node.d->type == NodeImpl::DocumentType || + node.d->type == NodeImpl::Element || + node.d->type == NodeImpl::Entity || + node.d->type == NodeImpl::EntityReference || + node.d->type == NodeImpl::Notation) + return engine->nullValue(); + return QScriptValue(node.d->data); } @@ -430,6 +456,8 @@ QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data) switch (data->type) { case NodeImpl::Attr: + instance.setPrototype(Attr::prototype(engine)); + break; case NodeImpl::Comment: case NodeImpl::Document: case NodeImpl::DocumentFragment: @@ -468,6 +496,42 @@ QScriptValue Element::prototype(QScriptEngine *engine) return proto; } +QScriptValue Attr::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->name); +} + +QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->data); +} + +QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return Node::create(engine, node.d->parent); +} + QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine) { Node node = qscriptvalue_cast(context->thisObject()); @@ -581,6 +645,7 @@ QScriptValue Document::load(QScriptEngine *engine, const QString &data) attr->namespaceUri = a.namespaceUri().toString(); attr->name = a.name().toString(); attr->data = a.value().toString(); + attr->parent = node; node->attributes.append(attr); } } @@ -800,17 +865,29 @@ NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValu if (!(flags & HandlesReadAccess)) return 0; - bool ok = false; - uint index = name.toString().toUInt(&ok); - if (!ok) + NamedNodeMap map = qscriptvalue_cast(object.data()); + if (map.isNull()) return 0; - NamedNodeMap map = qscriptvalue_cast(object.data()); - if (map.isNull() || (uint)map.list->count() <= index) - return 0; // ### I think we're meant to raise an exception + bool ok = false; + QString nameString = name.toString(); + uint index = nameString.toUInt(&ok); + if (ok) { + if ((uint)map.list->count() <= index) + return 0; + + *id = index; + return HandlesReadAccess; + } else { + for (int ii = 0; ii < map.list->count(); ++ii) { + if (map.list->at(ii) && map.list->at(ii)->name == nameString) { + *id = ii; + return HandlesReadAccess; + } + } + } - *id = index; - return HandlesReadAccess; + return 0; } QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id) @@ -1050,7 +1127,7 @@ void QmlXMLHttpRequest::addHeader(const QString &name, const QString &value) QString QmlXMLHttpRequest::header(const QString &name) { - QByteArray utfname = name.toUtf8(); + QByteArray utfname = name.toLower().toUtf8(); foreach (const HeaderPair &header, m_headersList) { if (header.first == utfname) @@ -1079,7 +1156,11 @@ void QmlXMLHttpRequest::fillHeadersList() m_headersList.clear(); foreach (const QByteArray &header, headerList) { - HeaderPair pair (header, m_network->rawHeader(header)); + HeaderPair pair (header.toLower(), m_network->rawHeader(header)); + if (pair.first == "set-cookie" || + pair.first == "set-cookie2") + continue; + m_headersList << pair; } } @@ -1190,11 +1271,19 @@ void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error) QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); m_responseEntityBody = QByteArray(); - m_errorFlag = true; - m_request = QNetworkRequest(); + m_request = QNetworkRequest(); destroyNetwork(); + if (error != QNetworkReply::ContentAccessDenied && + error != QNetworkReply::ContentOperationNotPermittedError && + error != QNetworkReply::ContentNotFoundError) { + m_errorFlag = true; + } else { + m_state = Loading; + dispatchCallback(); + } + m_state = Done; dispatchCallback(); } diff --git a/tests/auto/declarative/xmlhttprequest/data/abort.expect b/tests/auto/declarative/xmlhttprequest/data/abort.expect new file mode 100644 index 0000000..5cdc24e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/abort.expect @@ -0,0 +1,10 @@ +PUT /testdocument.html HTTP/1.1 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 9 +Connection: Keep-Alive +Accept-Encoding: gzip +accept-language: en,* +User-Agent: Mozilla/5.0 +Host: localhost:14445 + +Test Data \ No newline at end of file diff --git a/tests/auto/declarative/xmlhttprequest/data/abort.qml b/tests/auto/declarative/xmlhttprequest/data/abort.qml new file mode 100644 index 0000000..132eb96 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/abort.qml @@ -0,0 +1,42 @@ +import Qt 4.6 + +Object { + property string urlDummy + property string url + + property bool seenDone: false + property bool didNotSeeUnsent: true + property bool endStateUnsent: false + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + x.open("GET", urlDummy); + x.setRequestHeader("Test-header", "TestValue"); + x.send(); + + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + seenDone = true; + } else if (x.readyState == XMLHttpRequest.UNSENT) { + didNotSeeUnsent = false; + } + } + + x.abort(); + + if (x.readyState == XMLHttpRequest.UNSENT) { + endStateUnsent = true; + } + + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + x.open("PUT", url); + x.send("Test Data"); + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/abort.reply b/tests/auto/declarative/xmlhttprequest/data/abort.reply new file mode 100644 index 0000000..35b11f4 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/abort.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/abort_opened.qml b/tests/auto/declarative/xmlhttprequest/data/abort_opened.qml new file mode 100644 index 0000000..9c7449f --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/abort_opened.qml @@ -0,0 +1,58 @@ +import Qt 4.6 + +Object { + property string url: "testdocument.html" + + 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; + x.abort(); + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("PUT", url); + + x.abort(); + + 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/abort_unsent.qml b/tests/auto/declarative/xmlhttprequest/data/abort_unsent.qml new file mode 100644 index 0000000..4bc479e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/abort_unsent.qml @@ -0,0 +1,54 @@ +import Qt 4.6 + +Object { + property string url: "testdocument.html" + + 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; + x.abort(); + + 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/attr.qml b/tests/auto/declarative/xmlhttprequest/data/attr.qml new file mode 100644 index 0000000..d0ee720 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/attr.qml @@ -0,0 +1,80 @@ +import Qt 4.6 + +Object { + property bool xmlTest: false + property bool dataOK: false + + Script { + function checkAttr(documentElement, attr) + { + if (attr == null) + return; + + if (attr.name != "attr") + return; + + if (attr.value != "myvalue") + return; + + if (attr.ownerElement.tagName != documentElement.tagName) + return; + + if (attr.nodeName != "attr") + return; + + if (attr.nodeValue != "myvalue") + return; + + if (attr.nodeType != 2) + return; + + if (attr.childNodes.length != 0) + return; + + if (attr.firstChild != null) + return; + + if (attr.lastChild != null) + return; + + if (attr.previousSibling != null) + return; + + if (attr.nextSibling != null) + return; + + if (attr.attributes != null) + return; + + xmlTest = true; + } + + function checkXML(document) + { + checkAttr(document.documentElement, document.documentElement.attributes[0]); + } + } + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", "attr.xml"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + + dataOK = true; + + if (x.responseXML != null) + checkXML(x.responseXML); + + } + } + + x.send() + } +} + + + diff --git a/tests/auto/declarative/xmlhttprequest/data/attr.xml b/tests/auto/declarative/xmlhttprequest/data/attr.xml new file mode 100644 index 0000000..2aa64a3 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/attr.xml @@ -0,0 +1 @@ + diff --git a/tests/auto/declarative/xmlhttprequest/data/document.qml b/tests/auto/declarative/xmlhttprequest/data/document.qml new file mode 100644 index 0000000..fe78e31 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/document.qml @@ -0,0 +1,49 @@ +import Qt 4.6 + +Object { + property bool xmlTest: false + property bool dataOK: false + + Script { + function checkXML(document) + { + if (document.xmlVersion != "1.0") + return; + + if (document.xmlStandalone != true) + return; + + if (document.documentElement == null) + return; + + if (document.nodeValue != null) + return; + + // ### Test other node properties + // ### test encoding (what is a valid qt encoding?) + xmlTest = true; + } + } + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", "document.xml"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + + dataOK = true; + + if (x.responseXML != null) + checkXML(x.responseXML); + + } + } + + x.send() + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/document.xml b/tests/auto/declarative/xmlhttprequest/data/document.xml new file mode 100644 index 0000000..b5fbe31 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/document.xml @@ -0,0 +1,3 @@ + + + diff --git a/tests/auto/declarative/xmlhttprequest/data/element.qml b/tests/auto/declarative/xmlhttprequest/data/element.qml new file mode 100644 index 0000000..a1ae2ab --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/element.qml @@ -0,0 +1,101 @@ +import Qt 4.6 + +Object { + property bool xmlTest: false + property bool dataOK: false + + Script { + function checkElement(e) + { + if (e.tagName != "root") + return; + + if (e.nodeName != "root") + return; + + if (e.nodeValue != null) + return; + + if (e.nodeType != 1) + return; + + var childTagNames = [ "person", "fruit" ]; + + if (e.childNodes.length != childTagNames.length) + return; + + for (var ii = 0; ii < childTagNames.length; ++ii) { + if (e.childNodes[ii].tagName != childTagNames[ii]) + return; + } + + if (e.childNodes[childTagNames.length + 1] != null) + return; + + if (e.firstChild.tagName != e.childNodes[0].tagName) + return; + + if (e.lastChild.tagName != e.childNodes[1].tagName) + return; + + if (e.previousSibling != null) + return; + + if (e.nextSibling != null) + return; + + if (e.attributes == null) + return; + + var attr1 = e.attributes["attr"]; + if (attr1.nodeValue != "value") + return; + + var attrIdx = e.attributes[0]; + if (attrIdx.nodeValue != "value") + return; + + var attr2 = e.attributes["attr2"]; + if (attr2.nodeValue != "value2") + return; + + var attr3 = e.attributes["attr3"]; + if (attr3 != null) + return; + + var attrIdx2 = e.attributes[11]; + if (attrIdx2 != null) + return; + + xmlTest = true; + } + + function checkXML(document) + { + checkElement(document.documentElement); + } + } + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", "element.xml"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + + dataOK = true; + + if (x.responseXML != null) + checkXML(x.responseXML); + + } + } + + x.send() + } +} + + + diff --git a/tests/auto/declarative/xmlhttprequest/data/element.xml b/tests/auto/declarative/xmlhttprequest/data/element.xml new file mode 100644 index 0000000..071ffae --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/element.xml @@ -0,0 +1 @@ + diff --git a/tests/auto/declarative/xmlhttprequest/data/getAllResponseHeaders.qml b/tests/auto/declarative/xmlhttprequest/data/getAllResponseHeaders.qml new file mode 100644 index 0000000..0bee7ad --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/getAllResponseHeaders.qml @@ -0,0 +1,65 @@ +import Qt 4.6 + +Object { + property string url + + property bool unsentException: false + property bool openedException: false + + property bool readyState: false + property bool openedState: false + + property bool headersReceivedState: false + property bool headersReceivedHeader: false + + property bool doneState: false + property bool doneHeader: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.getResponseHeader("Test-Header"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + unsentException = true; + } + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("GET", url); + + if (x.readyState == XMLHttpRequest.OPENED) + openedState = true; + + try { + x.getResponseHeader("Test-Header"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + openedException = true; + } + + var headers = "content-type: text/html; charset=UTF-8\r\ntest-header: TestValue\r\nmultitest-header: TestValue, SecondTestValue\r\ncontent-length: 11"; + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + headersReceivedState = true; + + headersReceivedHeader = (x.getAllResponseHeaders() == headers); + } else if (x.readyState == XMLHttpRequest.DONE) { + doneState = headersReceivedState && true; + + doneHeader = (x.getAllResponseHeaders() == headers); + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + x.send() + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.expect b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.expect new file mode 100644 index 0000000..40e648e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.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/getResponseHeader.qml b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.qml new file mode 100644 index 0000000..798b346 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.qml @@ -0,0 +1,75 @@ +import Qt 4.6 + +Object { + property string url + + property bool unsentException: false + property bool openedException: false + + property bool readyState: false + property bool openedState: false + + property bool headersReceivedState: false + property bool headersReceivedNullHeader: false + property bool headersReceivedValidHeader: false + property bool headersReceivedMultiValidHeader: false + property bool headersReceivedCookieHeader: false + + property bool doneState: false + property bool doneNullHeader: false + property bool doneValidHeader: false + property bool doneMultiValidHeader: false + property bool doneCookieHeader: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + x.getResponseHeader("Test-Header"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + unsentException = true; + } + + if (x.readyState == XMLHttpRequest.UNSENT) + readyState = true; + + x.open("GET", url); + + if (x.readyState == XMLHttpRequest.OPENED) + openedState = true; + + try { + x.getResponseHeader("Test-Header"); + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + openedException = true; + } + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + headersReceivedState = true; + + headersReceivedNullHeader = (x.getResponseHeader("Nonexistant-header") == ""); + headersReceivedValidHeader = (x.getResponseHeader("Test-HEAder") == "TestValue"); + headersReceivedMultiValidHeader = (x.getResponseHeader("MultiTest-HEAder") == "TestValue, SecondTestValue"); + headersReceivedCookieHeader = (x.getResponseHeader("Set-Cookie") == "" && x.getResponseHeader("Set-Cookie2") == ""); + } else if (x.readyState == XMLHttpRequest.DONE) { + doneState = headersReceivedState && true; + + doneNullHeader = (x.getResponseHeader("Nonexistant-header") == ""); + doneValidHeader = (x.getResponseHeader("Test-HEAder") == "TestValue"); + doneMultiValidHeader = (x.getResponseHeader("MultiTest-HEAder") == "TestValue, SecondTestValue"); + doneCookieHeader = (x.getResponseHeader("Set-Cookie") == "" && x.getResponseHeader("Set-Cookie2") == ""); + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + x.send() + } +} + + diff --git a/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.reply b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.reply new file mode 100644 index 0000000..62ec67b --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/getResponseHeader.reply @@ -0,0 +1,7 @@ +HTTP/1.0 200 OK +Content-type: text/html; charset=UTF-8 +Test-Header: TestValue +MultiTest-Header: TestValue +MultiTest-Header: SecondTestValue +Set-Cookie: mycook=Value +Set-Cookie2: mycook=Value diff --git a/tests/auto/declarative/xmlhttprequest/data/responseText.qml b/tests/auto/declarative/xmlhttprequest/data/responseText.qml new file mode 100644 index 0000000..0bb8659 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/responseText.qml @@ -0,0 +1,52 @@ +import Qt 4.6 + +Object { + property string url + property string expectedText + + property bool unsent: false + property bool opened: false + property bool sent: false + property bool headersReceived: false + + property bool loading: false + property bool done: false + + property bool reset: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + unsent = (x.responseText == ""); + + x.open("GET", url); + + opened = (x.responseText == ""); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + headersReceived = (x.responseText == ""); + } else if (x.readyState == XMLHttpRequest.LOADING) { + if (x.responseText == expectedText) + loading = true; + } else if (x.readyState == XMLHttpRequest.DONE) { + if (x.responseText == expectedText) + done = true; + + dataOK = (x.responseText == expectedText); + + x.open("GET", url); + + reset = (x.responseText == ""); + } + } + + x.send() + + sent = (x.responseText == ""); + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/responseXML_invalid.qml b/tests/auto/declarative/xmlhttprequest/data/responseXML_invalid.qml new file mode 100644 index 0000000..4fc4fe5 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/responseXML_invalid.qml @@ -0,0 +1,24 @@ +import Qt 4.6 + +Object { + property bool xmlNull: false + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + x.open("GET", "testdocument.html"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + xmlNull = (x.responseXML == null); + } + } + + + x.send() + } +} + diff --git a/tests/auto/declarative/xmlhttprequest/data/status.200.reply b/tests/auto/declarative/xmlhttprequest/data/status.200.reply new file mode 100644 index 0000000..35b11f4 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/status.200.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/status.404.reply b/tests/auto/declarative/xmlhttprequest/data/status.404.reply new file mode 100644 index 0000000..964a7a8 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/status.404.reply @@ -0,0 +1,2 @@ +HTTP/1.0 404 Document not found +Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/xmlhttprequest/data/status.expect b/tests/auto/declarative/xmlhttprequest/data/status.expect new file mode 100644 index 0000000..40e648e --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/status.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/status.qml b/tests/auto/declarative/xmlhttprequest/data/status.qml new file mode 100644 index 0000000..7b2e8d0 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/status.qml @@ -0,0 +1,77 @@ +import Qt 4.6 + +Object { + property string url + property int expectedStatus + + property bool unsentException: false; + property bool openedException: false; + property bool sentException: false; + + property bool headersReceived: false + property bool loading: false + property bool done: false + + property bool resetException: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + var a = x.status; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + unsentException = true; + } + + x.open("GET", url); + + try { + var a = x.status; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + openedException = true; + } + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + if (x.status == expectedStatus) + headersReceived = true; + } else if (x.readyState == XMLHttpRequest.LOADING) { + if (x.status == expectedStatus) + loading = true; + } else if (x.readyState == XMLHttpRequest.DONE) { + if (x.status == expectedStatus) + done = true; + + if (expectedStatus == 404) { + dataOK = (x.responseText == ""); + } else { + dataOK = (x.responseText == "QML Rocks!\n"); + } + + x.open("GET", url); + + try { + var a = x.status; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + resetException = true; + } + + } + } + + x.send() + + try { + var a = x.status; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + sentException = true; + } + } +} diff --git a/tests/auto/declarative/xmlhttprequest/data/statusText.qml b/tests/auto/declarative/xmlhttprequest/data/statusText.qml new file mode 100644 index 0000000..00d8fdc --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/statusText.qml @@ -0,0 +1,77 @@ +import Qt 4.6 + +Object { + property string url + property string expectedStatus + + property bool unsentException: false; + property bool openedException: false; + property bool sentException: false; + + property bool headersReceived: false + property bool loading: false + property bool done: false + + property bool resetException: false + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + + try { + var a = x.statusText; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + unsentException = true; + } + + x.open("GET", url); + + try { + var a = x.statusText; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + openedException = true; + } + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + if (x.statusText == expectedStatus) + headersReceived = true; + } else if (x.readyState == XMLHttpRequest.LOADING) { + if (x.statusText == expectedStatus) + loading = true; + } else if (x.readyState == XMLHttpRequest.DONE) { + if (x.statusText == expectedStatus) + done = true; + + if (expectedStatus != "OK") { + dataOK = (x.responseText == ""); + } else { + dataOK = (x.responseText == "QML Rocks!\n"); + } + + x.open("GET", url); + + try { + var a = x.statusText; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + resetException = true; + } + + } + } + + x.send() + + try { + var a = x.statusText; + } catch (e) { + if (e.code == DOMException.INVALID_STATE_ERR) + sentException = true; + } + } +} diff --git a/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp b/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp index b579944..b464a1b 100644 --- a/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp +++ b/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp @@ -68,8 +68,9 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod if (!replyFile.open(QIODevice::ReadOnly)) return false; bodyData = QByteArray(); - QFile bodyFile(body.toLocalFile()); - if (bodyFile.open(QIODevice::ReadOnly)) { + if (body.isValid()) { + QFile bodyFile(body.toLocalFile()); + if (!bodyFile.open(QIODevice::ReadOnly)) return false; bodyData = bodyFile.readAll(); } diff --git a/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp index bedb620..5a1955e 100644 --- a/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp +++ b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "testhttpserver.h" #define SERVER_PORT 14445 @@ -75,10 +76,25 @@ private slots: void send_ignoreData(); void send_withdata(); void abort(); + void abort_unsent(); + void abort_opened(); + void getResponseHeader(); + void getAllResponseHeaders(); + void status(); + void statusText(); + void responseText(); + void responseXML_invalid(); + + void document(); + void element(); + void attr(); // Crashes // void outstanding_request_at_shutdown(); + // void network_errors() + // void readyState() + private: QmlEngine engine; }; @@ -610,8 +626,395 @@ void tst_xmlhttprequest::send_withdata() } } +// Test abort() has no effect in unsent state +void tst_xmlhttprequest::abort_unsent() +{ + QmlComponent component(&engine, TEST_FILE("abort_unsent.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; +} + +// Test abort() cancels an open (but unsent) request +void tst_xmlhttprequest::abort_opened() +{ + QmlComponent component(&engine, TEST_FILE("abort_opened.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; +} + +// Test abort() aborts in progress send void tst_xmlhttprequest::abort() { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("abort.expect"), + TEST_FILE("abort.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("abort.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("urlDummy", "http://localhost:14449/testdocument.html"); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("seenDone").toBool(), true); + QCOMPARE(object->property("didNotSeeUnsent").toBool(), true); + QCOMPARE(object->property("endStateUnsent").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + delete object; +} + +void tst_xmlhttprequest::getResponseHeader() +{ + QmlEngine engine; // Avoid cookie contamination + + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), + TEST_FILE("getResponseHeader.reply"), + TEST_FILE("testdocument.html"))); + + + QmlComponent component(&engine, TEST_FILE("getResponseHeader.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("headersReceivedState").toBool(), true); + QCOMPARE(object->property("headersReceivedNullHeader").toBool(), true); + QCOMPARE(object->property("headersReceivedValidHeader").toBool(), true); + QCOMPARE(object->property("headersReceivedMultiValidHeader").toBool(), true); + QCOMPARE(object->property("headersReceivedCookieHeader").toBool(), true); + + QCOMPARE(object->property("doneState").toBool(), true); + QCOMPARE(object->property("doneNullHeader").toBool(), true); + QCOMPARE(object->property("doneValidHeader").toBool(), true); + QCOMPARE(object->property("doneMultiValidHeader").toBool(), true); + QCOMPARE(object->property("doneCookieHeader").toBool(), true); + + delete object; +} + +void tst_xmlhttprequest::getAllResponseHeaders() +{ + QmlEngine engine; // Avoid cookie contamination + + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("getResponseHeader.expect"), + TEST_FILE("getResponseHeader.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("getAllResponseHeaders.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + component.completeCreate(); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("readyState").toBool(), true); + QCOMPARE(object->property("openedState").toBool(), true); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("headersReceivedState").toBool(), true); + QCOMPARE(object->property("headersReceivedHeader").toBool(), true); + + QCOMPARE(object->property("doneState").toBool(), true); + QCOMPARE(object->property("doneHeader").toBool(), true); + + delete object; +} + +void tst_xmlhttprequest::status() +{ + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.200.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("status.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedStatus", 200); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("sentException").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("resetException").toBool(), true); + + delete object; + } + + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.404.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("status.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedStatus", 404); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("sentException").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("resetException").toBool(), true); + + delete object; + } +} + +void tst_xmlhttprequest::statusText() +{ + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.200.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("statusText.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedStatus", "OK"); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("sentException").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("resetException").toBool(), true); + + delete object; + } + + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.404.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("statusText.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedStatus", "Document not found"); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsentException").toBool(), true); + QCOMPARE(object->property("openedException").toBool(), true); + QCOMPARE(object->property("sentException").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("resetException").toBool(), true); + + delete object; + } +} + +void tst_xmlhttprequest::responseText() +{ + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.200.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("responseText.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedText", "QML Rocks!\n"); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsent").toBool(), true); + QCOMPARE(object->property("opened").toBool(), true); + QCOMPARE(object->property("sent").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("reset").toBool(), true); + + delete object; + } + + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.200.reply"), + QUrl())); + + QmlComponent component(&engine, TEST_FILE("responseText.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedText", ""); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsent").toBool(), true); + QCOMPARE(object->property("opened").toBool(), true); + QCOMPARE(object->property("sent").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("reset").toBool(), true); + + delete object; + } + + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + QVERIFY(server.wait(TEST_FILE("status.expect"), + TEST_FILE("status.404.reply"), + TEST_FILE("testdocument.html"))); + + QmlComponent component(&engine, TEST_FILE("responseText.qml")); + QObject *object = component.beginCreate(engine.rootContext()); + QVERIFY(object != 0); + object->setProperty("url", "http://localhost:14445/testdocument.html"); + object->setProperty("expectedText", ""); + component.completeCreate(); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("unsent").toBool(), true); + QCOMPARE(object->property("opened").toBool(), true); + QCOMPARE(object->property("sent").toBool(), true); + QCOMPARE(object->property("headersReceived").toBool(), true); + QCOMPARE(object->property("loading").toBool(), true); + QCOMPARE(object->property("done").toBool(), true); + QCOMPARE(object->property("reset").toBool(), true); + + delete object; + } +} + +void tst_xmlhttprequest::responseXML_invalid() +{ + QmlComponent component(&engine, TEST_FILE("responseXML_invalid.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("xmlNull").toBool(), true); + + delete object; +} + +// Test the Document DOM element +void tst_xmlhttprequest::document() +{ + QmlComponent component(&engine, TEST_FILE("document.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("xmlTest").toBool(), true); + + delete object; +} + +// Test the Element DOM element +void tst_xmlhttprequest::element() +{ + QmlComponent component(&engine, TEST_FILE("element.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("xmlTest").toBool(), true); + + delete object; +} + +// Test the Attr DOM element +void tst_xmlhttprequest::attr() +{ + QmlComponent component(&engine, TEST_FILE("attr.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + TRY_WAIT(object->property("dataOK").toBool() == true); + + QCOMPARE(object->property("xmlTest").toBool(), true); + + delete object; } QTEST_MAIN(tst_xmlhttprequest) -- cgit v0.12 From 2b3f5433d5b522a169cf466d9f0bc820d796b828 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 10 Nov 2009 13:38:13 +0100 Subject: qdoc3: Allow the full signature for QML signals and methods ...in the \qmlmethod and \qmlsignal commands, and the corresponding "attached" ones. Previously, the type was not allowed, but it really should be there, which means the \qmlmethod and \qmlsignal commands should be updated throughout. --- tools/qdoc3/cppcodeparser.cpp | 47 +++++++++++++++++++++++++------------------ tools/qdoc3/cppcodeparser.h | 10 ++++----- tools/qdoc3/node.cpp | 7 +++++++ tools/qdoc3/node.h | 2 ++ 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 90d83ca..ce71e51 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -686,9 +686,9 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_QMLATTACHEDSIGNAL) || (command == COMMAND_QMLATTACHEDMETHOD)) { QString element; - QString name; + QString type; QmlClassNode* qmlClass = 0; - if (splitQmlArg(doc,arg,element,name)) { + if (splitQmlMethodArg(doc,arg,type,element)) { Node* n = tre->findNode(QStringList(element),Node::Fake); if (n && n->subType() == Node::QmlClass) { qmlClass = static_cast(n); @@ -717,15 +717,15 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, :: This function splits the argument into those three - parts, sets \a type, \a element, and \a property, + parts, sets \a type, \a element, and \a name, and returns true. If any of the parts isn't found, - a debug message is output and false is returned. + a qdoc warning is output and false is returned. */ bool CppCodeParser::splitQmlPropertyArg(const Doc& doc, const QString& arg, QString& type, QString& element, - QString& property) + QString& name) { QStringList blankSplit = arg.split(" "); if (blankSplit.size() > 1) { @@ -733,40 +733,47 @@ bool CppCodeParser::splitQmlPropertyArg(const Doc& doc, QStringList colonSplit(blankSplit[1].split("::")); if (colonSplit.size() > 1) { element = colonSplit[0]; - property = colonSplit[1]; + name = colonSplit[1]; return true; } else - doc.location().warning(tr("Missing QML element name or property name")); + doc.location().warning(tr("Missing parent QML element name")); } else - doc.location().warning(tr("Missing QML property type or property path")); + doc.location().warning(tr("Missing property type")); return false; } /*! A QML signal or method argument has the form... - :: + ::(, , ...) This function splits the argument into those two parts, sets \a element, and \a name, and returns true. If either of the parts isn't found, a debug message is output and false is returned. */ -bool CppCodeParser::splitQmlArg(const Doc& doc, - const QString& arg, - QString& element, - QString& name) +bool CppCodeParser::splitQmlMethodArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element) { QStringList colonSplit(arg.split("::")); if (colonSplit.size() > 1) { - element = colonSplit[0]; - name = colonSplit[1]; + QStringList blankSplit = colonSplit[0].split(" "); + if (blankSplit.size() > 1) { + type = blankSplit[0]; + element = blankSplit[1]; + } + else { + type = QString(""); + element = colonSplit[0]; + } return true; } else - doc.location().warning(tr("Missing QML element name or signal/method name")); + doc.location().warning(tr("Missing parent QML element or method signature")); return false; } @@ -811,10 +818,10 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc, ++arg; while (arg != args.end()) { if (splitQmlPropertyArg(doc,(*arg),type,element,property)) { - QmlPropertyNode * qmlPropNode = new QmlPropertyNode(qmlPropGroup, - property, - type, - attached); + QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup, + property, + type, + attached); if (correspondingProperty) { bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*'); qmlPropNode->setWritable(writableList || correspondingProperty->isWritable()); diff --git a/tools/qdoc3/cppcodeparser.h b/tools/qdoc3/cppcodeparser.h index 87c1b69..e2e9d55 100644 --- a/tools/qdoc3/cppcodeparser.h +++ b/tools/qdoc3/cppcodeparser.h @@ -99,11 +99,11 @@ class CppCodeParser : public CodeParser const QString& arg, QString& type, QString& element, - QString& property); - bool splitQmlArg(const Doc& doc, - const QString& arg, - QString& element, - QString& name); + QString& name); + bool splitQmlMethodArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element); #endif virtual QSet otherMetaCommands(); virtual void processOtherMetaCommand(const Doc& doc, diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 1217042..373002c 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -1094,6 +1094,13 @@ QString FunctionNode::signature(bool values) const return s; } +/*! + Print some debugging stuff. + */ +void FunctionNode::debug() const +{ + qDebug() << "QML METHOD" << name() << "rt" << rt << "pp" << pp; +} /*! \class PropertyNode diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 4e12846..7fd3897 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -609,6 +609,8 @@ class FunctionNode : public LeafNode const QString& element() const { return parent()->name(); } bool isAttached() const { return att; } + void debug() const; + private: void setAssociatedProperty(PropertyNode *property); -- cgit v0.12