From dfbb731676e59b42f548dfca15e60f08cfcdc2f5 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 29 May 2013 15:21:59 +0200 Subject: [PATCH] add exceptionhandler code for connected signals/JS methods - there wasn't any error information if a C++ triggered signal resulted in a JS method which has an error, now it will create an exception for it - creating messagebox inside the lib is something what we want to avoid, so the developer itself is responsible to catch these exceptions - most cases of the installer code does that already Change-Id: I07486f73be9de13a486de235f14e3a7d7b54f5b1 Reviewed-by: Karsten Heimrich --- src/libs/installer/scriptengine.cpp | 8 +++ src/libs/installer/scriptengine.h | 7 +-- .../scriptengine/data/broken_connect.qs | 11 ++++ .../installer/scriptengine/scriptengine.qrc | 1 + .../scriptengine/tst_scriptengine.cpp | 52 +++++++++++++++++-- 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 tests/auto/installer/scriptengine/data/broken_connect.qs diff --git a/src/libs/installer/scriptengine.cpp b/src/libs/installer/scriptengine.cpp index 6178f467..9ff8ae75 100644 --- a/src/libs/installer/scriptengine.cpp +++ b/src/libs/installer/scriptengine.cpp @@ -209,6 +209,8 @@ ScriptEngine::ScriptEngine(PackageManagerCore *core) globalObject().property(QLatin1String("installer")) .setProperty(QLatin1String("components"), scriptComponentsObject); + + connect(this, SIGNAL(signalHandlerException(QScriptValue)), SLOT(handleException(QScriptValue))); } ScriptEngine::~ScriptEngine() @@ -279,6 +281,12 @@ QScriptValue ScriptEngine::loadInConext(const QString &context, const QString &f return scriptContext; } +void ScriptEngine::handleException(const QScriptValue &value) +{ + if (!value.engine()) + return; + throw Error(uncaughtExceptionString(this, tr("Fatal error while evaluating a script."))); +} /*! Tries to call the method with \a name within the script and returns the result. If the method diff --git a/src/libs/installer/scriptengine.h b/src/libs/installer/scriptengine.h index 9c7d84fc..50c50539 100644 --- a/src/libs/installer/scriptengine.h +++ b/src/libs/installer/scriptengine.h @@ -71,11 +71,12 @@ public: explicit ScriptEngine(PackageManagerCore *core); ~ScriptEngine(); void setGuiQObject(QObject *guiQObject); - QScriptValue callScriptMethod(const QScriptValue &scriptContext, const QString &name, - const QScriptValueList ¶meters = QScriptValueList()) const; + QScriptValue callScriptMethod(const QScriptValue &scriptContext, const QString &methodName, + const QScriptValueList &arguments = QScriptValueList()) const; QScriptValue loadInConext(const QString &context, const QString &fileName, const QString &scriptInjection = QString()); - +private slots: + void handleException(const QScriptValue &value); private: QScriptValue generateMessageBoxObject(); QScriptValue generateDesktopServicesObject(); diff --git a/tests/auto/installer/scriptengine/data/broken_connect.qs b/tests/auto/installer/scriptengine/data/broken_connect.qs new file mode 100644 index 00000000..2fe873b6 --- /dev/null +++ b/tests/auto/installer/scriptengine/data/broken_connect.qs @@ -0,0 +1,11 @@ +function BrokenConnect() +{ + emiter.emitted.connect(receive) +} + +function receive() +{ + print("function receive()"); + // this should throw an exception, "foo" does not exist + foo.bar = "test"; +} diff --git a/tests/auto/installer/scriptengine/scriptengine.qrc b/tests/auto/installer/scriptengine/scriptengine.qrc index d3816817..0bf68385 100644 --- a/tests/auto/installer/scriptengine/scriptengine.qrc +++ b/tests/auto/installer/scriptengine/scriptengine.qrc @@ -3,5 +3,6 @@ data/auto-install.qs data/component1.qs data/component2.qs + data/broken_connect.qs diff --git a/tests/auto/installer/scriptengine/tst_scriptengine.cpp b/tests/auto/installer/scriptengine/tst_scriptengine.cpp index c6332ff7..283d7bda 100644 --- a/tests/auto/installer/scriptengine/tst_scriptengine.cpp +++ b/tests/auto/installer/scriptengine/tst_scriptengine.cpp @@ -11,8 +11,6 @@ using namespace QInstaller; -// -- InstallerGui - class TestGui : public QInstaller::PackageManagerGui { Q_OBJECT @@ -34,6 +32,18 @@ public: } }; +class EmitSignalObject : public QObject +{ + Q_OBJECT + +public: + EmitSignalObject() {} + ~EmitSignalObject() {} + void produceSignal() { emit emitted(); } +signals: + void emitted(); +}; + class tst_ScriptEngine : public QObject { @@ -54,6 +64,42 @@ private slots: m_scriptEngine = m_core.scriptEngine(); } + void testBrokenJSMethodConnect() + { + EmitSignalObject emiter; + m_scriptEngine->globalObject().setProperty(QLatin1String("emiter"), + m_scriptEngine->newQObject(&emiter)); + + QScriptValue context = m_scriptEngine->loadInConext(QLatin1String("BrokenConnect"), + ":///data/broken_connect.qs"); + + QVERIFY(context.isValid()); + + if (m_scriptEngine->hasUncaughtException()) { + QFAIL(qPrintable(QString::fromLatin1("ScriptEngine hasUncaughtException:\n %1").arg( + uncaughtExceptionString(m_scriptEngine)))); + } + + const QString debugMesssage( + "create Error-Exception: \"Fatal error while evaluating a script.\n\n" + "ReferenceError: Can't find variable: foo\n\n" + "Backtrace:\n" +#if QT_VERSION < 0x050000 + "\t()@:///data/broken_connect.qs:10\" "); +#else + "\treceive() at :///data/broken_connect.qs:10\n" + "\t() at -1\" "); +#endif + try { + // ignore Output from script + setExpectedScriptOutput("function receive()"); + setExpectedScriptOutput(qPrintable(debugMesssage)); + emiter.produceSignal(); + } catch (const Error &error) { + QVERIFY2(debugMesssage.contains(error.message()), "There was some unexpected error."); + } + } + void testScriptPrint() { setExpectedScriptOutput("test"); @@ -199,7 +245,7 @@ private: PackageManagerCore m_core; Component *m_component; - QScriptEngine *m_scriptEngine; + ScriptEngine *m_scriptEngine; };