diff options
39 files changed, 1319 insertions, 81 deletions
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index f8e685a..105c673 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -48,6 +48,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qdebug.h> #include <private/qmlbindingoptimizations_p.h> +#include <private/qscriptdeclarativeclass_p.h> #include <QtDeclarative/qmlinfo.h> QT_BEGIN_NAMESPACE @@ -69,7 +70,7 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); scriptContext->pushScope(enginePriv->contextClass->newContext(q, scopeObject)); QScriptValue scope = scriptEngine->newObject(); diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index faf9f5a..d2d60ee 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -47,6 +47,7 @@ #include "QtCore/qdebug.h" #include "qmlcompiler_p.h" #include <QtScript/qscriptprogram.h> +#include <private/qscriptdeclarativeclass_p.h> Q_DECLARE_METATYPE(QList<QObject *>); @@ -117,7 +118,7 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, } #endif - QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); scriptContext->pushScope(ep->contextClass->newContext(ctxt, me)); #if !defined(Q_OS_SYMBIAN) @@ -305,7 +306,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUnd if (!data->expressionFunctionValid) { - QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); scriptContext->pushScope(ep->contextClass->newContext(data->context(), data->me)); if (data->expressionRewritten) { @@ -314,7 +315,12 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUnd } else { QmlRewrite::RewriteBinding rewriteBinding; - const QString code = rewriteBinding(data->expression); + bool ok = true; + const QString code = rewriteBinding(data->expression, &ok); + if (!ok) { + scriptEngine->popContext(); + return QVariant(); + } data->expressionFunction = scriptEngine->evaluate(code, data->url.toString(), data->line); } diff --git a/src/declarative/qml/qmlrewrite.cpp b/src/declarative/qml/qmlrewrite.cpp index b86f2f2..32e2fef 100644 --- a/src/declarative/qml/qmlrewrite.cpp +++ b/src/declarative/qml/qmlrewrite.cpp @@ -49,7 +49,7 @@ DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP); namespace QmlRewrite { -QString RewriteBinding::operator()(const QString &code) +QString RewriteBinding::operator()(const QString &code, bool *ok) { Engine engine; NodePool pool(QString(), &engine); @@ -57,6 +57,12 @@ QString RewriteBinding::operator()(const QString &code) Parser parser(&engine); lexer.setCode(code, 0); parser.parseStatement(); + if (!parser.statement()) { + if (ok) *ok = false; + return QString(); + } else { + if (ok) *ok = true; + } return rewrite(code, 0, parser.statement()); } diff --git a/src/declarative/qml/qmlrewrite_p.h b/src/declarative/qml/qmlrewrite_p.h index 914f997..a5cb841 100644 --- a/src/declarative/qml/qmlrewrite_p.h +++ b/src/declarative/qml/qmlrewrite_p.h @@ -69,7 +69,7 @@ class RewriteBinding: protected AST::Visitor TextWriter *_writer; public: - QString operator()(const QString &code); + QString operator()(const QString &code, bool *ok = 0); protected: using AST::Visitor::visit; 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 <QtCore/qdebug.h> -// ### 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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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<QmlXMLHttpRequest *>(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/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 94cdadf..435ddae 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -388,7 +388,7 @@ void QmlAbstractAnimation::setRepeat(bool r) int QmlAbstractAnimation::currentTime() { - return qtAnimation()->currentTime(); + return qtAnimation()->currentLoopTime(); } void QmlAbstractAnimation::setCurrentTime(int time) diff --git a/src/declarative/util/qmlanimation_p_p.h b/src/declarative/util/qmlanimation_p_p.h index 1372343..21c0284 100644 --- a/src/declarative/util/qmlanimation_p_p.h +++ b/src/declarative/util/qmlanimation_p_p.h @@ -108,7 +108,7 @@ public: protected: virtual void updateCurrentTime(int) {} - virtual void updateState(State /*oldState*/, State newState) + virtual void updateState(State newState, State /*oldState*/) { if (newState == Running) { if (animAction) @@ -147,9 +147,9 @@ protected: if (animValue) animValue->setValue(value.toDouble()); } - virtual void updateState(State oldState, State newState) + virtual void updateState(State newState, State oldState) { - QVariantAnimation::updateState(oldState, newState); + QVariantAnimation::updateState(newState, oldState); if (newState == Running) { //check for new from every loop if (fromSourced) diff --git a/src/declarative/util/qmltransition.cpp b/src/declarative/util/qmltransition.cpp index d61359d..7eb9e53 100644 --- a/src/declarative/util/qmltransition.cpp +++ b/src/declarative/util/qmltransition.cpp @@ -74,7 +74,7 @@ public: ParallelAnimationWrapper(QObject *parent) : QParallelAnimationGroup(parent) {} QmlTransitionPrivate *trans; protected: - virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); }; class QmlTransitionPrivate : public QObjectPrivate @@ -124,13 +124,13 @@ void QmlTransitionPrivate::AnimationList::append(QmlAbstractAnimation *a) parent->group->addAnimation(a->qtAnimation()); } -void ParallelAnimationWrapper::updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState) +void ParallelAnimationWrapper::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) { - QParallelAnimationGroup::updateState(oldState, newState); + QParallelAnimationGroup::updateState(newState, oldState); //XXX not 100% guaranteed to be at end (if there are many zero duration animations at the end)? if (newState == Stopped && - ((direction() == QAbstractAnimation::Forward && currentTime() == duration()) || - (direction() == QAbstractAnimation::Backward && currentTime() == 0))) + ((direction() == QAbstractAnimation::Forward && currentLoopTime() == duration()) || + (direction() == QAbstractAnimation::Backward && currentLoopTime() == 0))) { trans->complete(); } diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index de759c6..216f325 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1137,7 +1137,7 @@ void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) QScriptContext *context = q->currentContext(); while (context) { - JSC::ScopeChainNode *node = ((JSC::ExecState *)context)->scopeChain(); + JSC::ScopeChainNode *node = frameForContext(context)->scopeChain(); JSC::ScopeChainIterator it(node); for (it = node->begin(); it != node->end(); ++it) { JSC::JSObject *object = *it; @@ -2288,35 +2288,6 @@ QScriptContext *QScriptEngine::pushContext() return d->contextForFrame(newFrame); } -/*! - Enters a new execution context and returns the associated - QScriptContext object. - - Once you are done with the context, you should call popContext() to - restore the old context. - - By default, the `this' object of the new context is the Global Object. - The context's \l{QScriptContext::callee()}{callee}() will be invalid. - - Unlike pushContext(), the default scope chain is reset to include - only the global object and the QScriptContext's activation object. - - \sa popContext() -*/ -QScriptContext *QScriptEngine::pushCleanContext() -{ - Q_D(QScriptEngine); - - JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject, - JSC::ArgList(), /*callee = */0, false, true); - - if (agent()) - agent()->contextPush(); - - return d->contextForFrame(newFrame); -} - - /*! \internal push a context for a native function. JSC native function doesn't have different stackframe or context. so we need to create one. diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index de4dc02..7db61e1 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -160,7 +160,6 @@ public: QScriptContext *currentContext() const; QScriptContext *pushContext(); - QScriptContext *pushCleanContext(); void popContext(); bool canEvaluate(const QString &program) const; diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index f0c1c45..b5d9bf5 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -44,6 +44,7 @@ #include "qscriptobject_p.h" #include <QtScript/qscriptstring.h> #include <QtScript/qscriptengine.h> +#include <QtScript/qscriptengineagent.h> #include <private/qscriptengine_p.h> #include <private/qscriptvalue_p.h> #include <private/qscriptqobject_p.h> @@ -217,6 +218,38 @@ QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, i return QScriptValue(); } +/*! + Enters a new execution context and returns the associated + QScriptContext object. + + Once you are done with the context, you should call popContext() to + restore the old context. + + By default, the `this' object of the new context is the Global Object. + The context's \l{QScriptContext::callee()}{callee}() will be invalid. + + Unlike pushContext(), the default scope chain is reset to include + only the global object and the QScriptContext's activation object. + + \sa QScriptEngine::popContext() +*/ +QScriptContext * QScriptDeclarativeClass::pushCleanContext(QScriptEngine *engine) +{ + if (!engine) + return 0; + + QScriptEnginePrivate *d = QScriptEnginePrivate::get(engine); + + JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, + d->currentFrame->globalData().dynamicGlobalObject, + JSC::ArgList(), /*callee = */0, false, true); + + if (engine->agent()) + engine->agent()->contextPush(); + + return d->contextForFrame(newFrame); +} + QScriptDeclarativeClass::~QScriptDeclarativeClass() { } diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 4e06931..d0e653d 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -77,6 +77,7 @@ public: static QScriptValue property(const QScriptValue &, const Identifier &); static QScriptValue scopeChainValue(QScriptContext *, int index); + static QScriptContext *pushCleanContext(QScriptEngine *); class Q_SCRIPT_EXPORT PersistentIdentifier { 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 --- /dev/null +++ b/tests/auto/declarative/xmlhttprequest/data/open_network.wait 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 <QTcpSocket> +#include <QDebug> +#include <QFile> + +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<QTcpSocket *>(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 <QObject> +#include <QTcpServer> +#include <QUrl> + +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 <qtest.h> +#include <QmlEngine> +#include <QmlComponent> +#include <QDebug> +#include <QWebPage> +#include <QWebFrame> +#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<QString>("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\\\" |