From 9ebf3d12a163b07d900d02f4eadf7e8bc248bb14 Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Thu, 23 Jun 2011 11:39:56 +1000 Subject: [PATCH] get the caller file & line number from v8 stack trace. Change-Id: I0ffebd2d22702bc14e1629b8bc0455a9cf8ea416 --- src/imports/testlib/SignalSpy.qml | 2 +- src/imports/testlib/TestCase.qml | 31 ++++++----- src/imports/testlib/main.cpp | 98 ++++++++++++++++++------------------- src/imports/testlib/testlib.pro | 2 +- src/qmltest/quicktest.cpp | 18 ------- 5 files changed, 66 insertions(+), 85 deletions(-) diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml index 6764129..627ca9f 100644 --- a/src/imports/testlib/SignalSpy.qml +++ b/src/imports/testlib/SignalSpy.qml @@ -66,7 +66,7 @@ Item { i += 50 } var success = (count >= expected) - if (!qtest_results.verify(success, "wait for signal " + signalName, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.verify(success, "wait for signal " + signalName, QtTest.qtest_caller_file(), QtTest.qtest_caller_line())) throw new Error("QtQuickTest::fail") } diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 3659c60..0ba6c3b 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -46,6 +46,9 @@ import "testlogger.js" as TestLogger Item { id: testCase visible: false + TestUtil { + id:util + } // Name of the test case to prefix the function name in messages. property string name @@ -66,7 +69,7 @@ Item { // Property that is set to true when the main window is shown. // We need to set the property value in an odd way to handle // both qmlviewer and the QtQuickTest module test wrapper. - property bool windowShown: Qt.qtest_wrapper ? qtest.windowShown : false + property bool windowShown: util.wrapper ? util.windowShown : false // Internal private state. Identifiers prefixed with qtest are reserved. property bool qtest_prevWhen: true @@ -80,21 +83,21 @@ Item { function fail(msg) { if (msg === undefined) msg = ""; - qtest_results.fail(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()) + qtest_results.fail(msg, util.callerFile(), util.callerLine()) throw new Error("QtQuickTest::fail") } function qtest_fail(msg, frame) { if (msg === undefined) msg = ""; - qtest_results.fail(msg, Qt.qtest_caller_file(frame), Qt.qtest_caller_line(frame)) + qtest_results.fail(msg, util.callerFile(frame), util.callerLine(frame)) throw new Error("QtQuickTest::fail") } function verify(cond, msg) { if (msg === undefined) msg = ""; - if (!qtest_results.verify(cond, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::fail") } @@ -279,7 +282,7 @@ Item { else msg = "Compared values are not the same" } - if (!qtest_results.compare(success, msg, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::fail") } @@ -297,21 +300,21 @@ Item { var act = qtest_formatValue(actual) var exp = qtest_formatValue(value) var success = qtest_compareInternal(actual, value) - if (!qtest_results.compare(success, "property " + prop, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.compare(success, "property " + prop, act, exp, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::fail") } function skip(msg) { if (msg === undefined) msg = "" - qtest_results.skipSingle(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()) + qtest_results.skipSingle(msg, util.callerFile(), util.callerLine()) throw new Error("QtQuickTest::skip") } function skipAll(msg) { if (msg === undefined) msg = "" - qtest_results.skipAll(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()) + qtest_results.skipAll(msg, util.callerFile(), util.callerLine()) throw new Error("QtQuickTest::skip") } @@ -324,7 +327,7 @@ Item { warn("message argument missing from expectFail()") msg = "" } - if (!qtest_results.expectFail(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.expectFail(tag, msg, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::expectFail") } @@ -337,7 +340,7 @@ Item { warn("message argument missing from expectFailContinue()") msg = "" } - if (!qtest_results.expectFailContinue(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())) + if (!qtest_results.expectFailContinue(tag, msg, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::expectFail") } @@ -505,7 +508,7 @@ Item { } function qtest_run() { - if (Qt.qtest_printAvailableFunctions) { + if (util.printAvailableFunctions) { completed = true return } @@ -650,7 +653,7 @@ Item { } } - // The test framework will set qtest.windowShown when the + // The test framework will set util.windowShown when the // window is actually shown. If we are running with qmlviewer, // then this won't happen. So we use a timer instead. Timer { @@ -661,7 +664,7 @@ Item { } Component.onCompleted: { - if (Qt.qtest_printAvailableFunctions) { + if (util.printAvailableFunctions) { var testList = [] for (var prop in testCase) { if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0) @@ -683,7 +686,7 @@ Item { if (optional) TestLogger.log_optional_test(qtest_testId) qtest_prevWhen = when - var isQmlViewer = Qt.qtest_wrapper ? false : true + var isQmlViewer = util.wrapper ? false : true if (isQmlViewer) qtest_windowShowTimer.running = true if (when && !completed && !running) diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 5ef07b9..012a30b 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -47,56 +47,63 @@ #include #include "QtQuickTest/private/quicktestresult_p.h" #include "QtQuickTest/private/quicktestevent_p.h" +#include "private/qtestoptions_p.h" +#include "QtDeclarative/qsgitem.h" +#include QT_BEGIN_NAMESPACE QML_DECLARE_TYPE(QuickTestResult) QML_DECLARE_TYPE(QuickTestEvent) -// Copied from qdeclarativedebughelper_p.h in Qt, to avoid a dependency -// on a private header from Qt. -class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper +#include + +class QuickTestUtil : public QObject { + Q_OBJECT + Q_PROPERTY(bool printAvailableFunctions READ printAvailableFunctions) + Q_PROPERTY(bool wrapper READ wrapper) public: - static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine); - static void setAnimationSlowDownFactor(qreal factor); - static void enableDebugging(); -}; + QuickTestUtil(QObject *parent = 0) + :QObject(parent) + {} -static QScriptContext *qtest_find_frame(QScriptContext *ctx) -{ - qint32 frame = 1; - if (ctx->argumentCount() > 0) - frame = ctx->argument(0).toInt32(); - ++frame; // Exclude the native function; start at its caller. - while (ctx) { - if (frame-- <= 0) - break; - ctx = ctx->parentContext(); + ~QuickTestUtil() + {} + bool printAvailableFunctions() const + { + return QTest::printAvailableFunctions; } - return ctx; -} - -static QScriptValue qtest_caller_file - (QScriptContext *ctx, QScriptEngine *engine) -{ - ctx = qtest_find_frame(ctx); - if (ctx) { - QScriptContextInfo info(ctx); - return engine->newVariant(info.fileName()); + bool wrapper() const + { + return true; } - return engine->newVariant(QLatin1String("")); -} -static QScriptValue qtest_caller_line - (QScriptContext *ctx, QScriptEngine *engine) -{ - ctx = qtest_find_frame(ctx); - if (ctx) { - QScriptContextInfo info(ctx); - return engine->newVariant(info.lineNumber()); +public Q_SLOTS: + QDeclarativeV8Handle callerFile(int frameIndex = 0) const + { + v8::HandleScope scope; + + v8::Local stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + int count = stacks->GetFrameCount(); + if (count >= frameIndex + 2) { + v8::Local frame = stacks->GetFrame(frameIndex + 2); + return QDeclarativeV8Handle::fromHandle(frame->GetScriptNameOrSourceURL()); + } + return QDeclarativeV8Handle(); } - return engine->newVariant(qint32(0)); -} + int callerLine(int frameIndex = 0) const + { + v8::HandleScope scope; + v8::Local stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + int count = stacks->GetFrameCount(); + if (count >= frameIndex + 2) { + v8::Local frame = stacks->GetFrame(frameIndex + 2); + return frame->GetLineNumber(); + } + return -1; + } +}; +QML_DECLARE_TYPE(QuickTestUtil) class QTestQmlModule : public QDeclarativeExtensionPlugin { @@ -107,22 +114,11 @@ public: Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest")); qmlRegisterType(uri,1,0,"TestResult"); qmlRegisterType(uri,1,0,"TestEvent"); + qmlRegisterType(uri,1,0,"TestUtil"); } + void initializeEngine(QDeclarativeEngine *engine, const char *) { - // Install some helper functions in the global "Qt" object - // for walking the stack and finding a caller's location. - // Normally we would use an exception's backtrace, but JSC - // only provides the top-most frame in the backtrace. - QScriptEngine *eng = QDeclarativeDebugHelper::getScriptEngine(engine); - QScriptValue qtObject - = eng->globalObject().property(QLatin1String("Qt")); - qtObject.setProperty - (QLatin1String("qtest_caller_file"), - eng->newFunction(qtest_caller_file)); - qtObject.setProperty - (QLatin1String("qtest_caller_line"), - eng->newFunction(qtest_caller_line)); } }; diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro index 80bd5c5..92c5a09 100644 --- a/src/imports/testlib/testlib.pro +++ b/src/imports/testlib/testlib.pro @@ -21,7 +21,7 @@ symbian { } -QT += declarative script qmltest qmltest-private +QT += declarative script qmltest qmltest-private declarative-private script-private core-private SOURCES += main.cpp HEADERS += diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 19e15f2..9b12b02 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -189,15 +189,6 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport &eventLoop, SLOT(quit())); view.rootContext()->setContextProperty (QLatin1String("qtest"), &rootobj); - QScriptEngine *engine; - engine = QDeclarativeDebugHelper::getScriptEngine(view.engine()); - QScriptValue qtObject - = engine->globalObject().property(QLatin1String("Qt")); - qtObject.setProperty - (QLatin1String("qtest_wrapper"), QScriptValue(true)); - qtObject.setProperty - (QLatin1String("qtest_printAvailableFunctions"), - QScriptValue(QTest::printAvailableFunctions)); foreach (QString path, imports) view.engine()->addImportPath(path); QString path = fi.absoluteFilePath(); @@ -254,15 +245,6 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport view.setViewport((*createViewport)()); view.rootContext()->setContextProperty (QLatin1String("qtest"), &rootobj); - QScriptEngine *engine; - engine = QDeclarativeDebugHelper::getScriptEngine(view.engine()); - QScriptValue qtObject - = engine->globalObject().property(QLatin1String("Qt")); - qtObject.setProperty - (QLatin1String("qtest_wrapper"), QScriptValue(true)); - qtObject.setProperty - (QLatin1String("qtest_printAvailableFunctions"), - QScriptValue(QTest::printAvailableFunctions)); foreach (QString path, imports) view.engine()->addImportPath(path); QString path = fi.absoluteFilePath(); -- 1.7.2.5