From 974db3ce58307069fcafdee2c5636ff72b061134 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 10 Feb 2011 15:31:17 +1000 Subject: Report any exceptions occurring in WorkerScript javascript code Task-number: QTBUG-17183 Change-Id: I709cca0bdce247ca9250c4f334654e2ff57b0b32 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativeworkerscript.cpp | 66 +++++++++++++++++++++- .../data/script_error_onCall.js | 6 ++ .../data/script_error_onLoad.js | 5 ++ .../data/worker_error_onCall.qml | 6 ++ .../data/worker_error_onLoad.qml | 7 +++ .../tst_qdeclarativeworkerscript.cpp | 52 +++++++++++++++++ 6 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onCall.js create mode 100644 tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onLoad.js create mode 100644 tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onCall.qml create mode 100644 tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onLoad.qml diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index ac13c68..9721389 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -43,6 +43,7 @@ #include "private/qdeclarativelistmodel_p.h" #include "private/qdeclarativelistmodelworkeragent_p.h" #include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeexpression_p.h" #include #include @@ -104,6 +105,19 @@ private: int m_id; }; +class WorkerErrorEvent : public QEvent +{ +public: + enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 }; + + WorkerErrorEvent(const QDeclarativeError &error); + + QDeclarativeError error() const; + +private: + QDeclarativeError m_error; +}; + class QDeclarativeWorkerScriptEnginePrivate : public QObject { Q_OBJECT @@ -146,6 +160,7 @@ public: WorkerScript(); int id; + QUrl source; bool initialized; QDeclarativeWorkerScript *owner; QScriptValue object; @@ -173,6 +188,7 @@ protected: private: void processMessage(int, const QVariant &); void processLoad(int, const QUrl &); + void reportScriptException(WorkerScript *); }; QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine) @@ -273,6 +289,11 @@ void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVarian args.setProperty(0, variantToScriptValue(data, workerEngine)); script->callback.call(script->object, args); + + if (workerEngine->hasUncaughtException()) { + reportScriptException(script); + workerEngine->clearExceptions(); + } } } @@ -286,7 +307,7 @@ void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) QFile f(fileName); if (f.open(QIODevice::ReadOnly)) { QByteArray data = f.readAll(); - QString script = QString::fromUtf8(data); + QString sourceCode = QString::fromUtf8(data); QScriptValue activation = getWorker(id); @@ -296,10 +317,19 @@ void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) ctxt->pushScope(urlContext); ctxt->pushScope(activation); ctxt->setActivationObject(activation); - QDeclarativeScriptParser::extractPragmas(script); + QDeclarativeScriptParser::extractPragmas(sourceCode); workerEngine->baseUrl = url; - workerEngine->evaluate(script); + workerEngine->evaluate(sourceCode); + + WorkerScript *script = workers.value(id); + if (script) { + script->source = url; + if (workerEngine->hasUncaughtException()) { + reportScriptException(script); + workerEngine->clearExceptions(); + } + } workerEngine->popContext(); } else { @@ -307,6 +337,22 @@ void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) } } +void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script) +{ + if (!script || !workerEngine->hasUncaughtException()) + return; + + QDeclarativeError error; + QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error); + error.setUrl(script->source); + + QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine); + + QMutexLocker(&p->m_lock); + if (script->owner) + QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error)); +} + QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) { if (value.isBool()) { @@ -453,6 +499,16 @@ int WorkerRemoveEvent::workerId() const return m_id; } +WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error) +: QEvent((QEvent::Type)WorkerError), m_error(error) +{ +} + +QDeclarativeError WorkerErrorEvent::error() const +{ + return m_error; +} + QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent) : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent)) { @@ -687,6 +743,10 @@ bool QDeclarativeWorkerScript::event(QEvent *event) emit message(value); } return true; + } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) { + WorkerErrorEvent *workerEvent = static_cast(event); + QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error()); + return true; } else { return QObject::event(event); } diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onCall.js b/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onCall.js new file mode 100644 index 0000000..f589b0e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onCall.js @@ -0,0 +1,6 @@ +WorkerScript.onMessage = function(msg) { + var a = 123 + var b = 345 + var f = getData() +} + diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onLoad.js b/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onLoad.js new file mode 100644 index 0000000..1d6eab2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onLoad.js @@ -0,0 +1,5 @@ +WorkerScript.onMessage = function(msg) { + var a = 123 + aoij awef aljfaow eij +} + diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onCall.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onCall.qml new file mode 100644 index 0000000..90c4617 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onCall.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +BaseWorker { + source: "script_error_onCall.js" +} + diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onLoad.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onLoad.qml new file mode 100644 index 0000000..0b9d21d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_error_onLoad.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +BaseWorker { + source: "script_error_onLoad.js" +} + + diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp index aaedd82..4b922fb 100644 --- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp +++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -58,6 +60,13 @@ Q_DECLARE_METATYPE(QScriptValue) #define SRCDIR "." #endif +inline QUrl TEST_FILE(const QString &filename) +{ + QFileInfo fileInfo(__FILE__); + return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(filename)); +} + + class tst_QDeclarativeWorkerScript : public QObject { Q_OBJECT @@ -70,6 +79,8 @@ private slots: void messaging_sendQObjectList(); void messaging_sendJsObject(); void script_with_pragma(); + void scriptError_onLoad(); + void scriptError_onCall(); private: void waitForEchoMessage(QDeclarativeWorkerScript *worker) { @@ -215,6 +226,47 @@ void tst_QDeclarativeWorkerScript::script_with_pragma() delete worker; } +static QString qdeclarativeworkerscript_lastWarning; +static void qdeclarativeworkerscript_warningsHandler(QtMsgType type, const char *msg) +{ + if (type == QtWarningMsg) + qdeclarativeworkerscript_lastWarning = QString::fromUtf8(msg); +} + +void tst_QDeclarativeWorkerScript::scriptError_onLoad() +{ + QDeclarativeComponent component(&m_engine, SRCDIR "/data/worker_error_onLoad.qml"); + + QtMsgHandler previousMsgHandler = qInstallMsgHandler(qdeclarativeworkerscript_warningsHandler); + QDeclarativeWorkerScript *worker = qobject_cast(component.create()); + QVERIFY(worker != 0); + + QTRY_COMPARE(qdeclarativeworkerscript_lastWarning, + TEST_FILE("data/script_error_onLoad.js").toString() + QLatin1String(":3: SyntaxError: Parse error")); + + qInstallMsgHandler(previousMsgHandler); + qApp->processEvents(); + delete worker; +} + +void tst_QDeclarativeWorkerScript::scriptError_onCall() +{ + QDeclarativeComponent component(&m_engine, SRCDIR "/data/worker_error_onCall.qml"); + QDeclarativeWorkerScript *worker = qobject_cast(component.create()); + QVERIFY(worker != 0); + + QtMsgHandler previousMsgHandler = qInstallMsgHandler(qdeclarativeworkerscript_warningsHandler); + QVariant value; + QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value))); + + QTRY_COMPARE(qdeclarativeworkerscript_lastWarning, + TEST_FILE("data/script_error_onCall.js").toString() + QLatin1String(":4: ReferenceError: Can't find variable: getData")); + + qInstallMsgHandler(previousMsgHandler); + qApp->processEvents(); + delete worker; +} + QTEST_MAIN(tst_QDeclarativeWorkerScript) -- cgit v0.12