get the caller file & line number from v8 stack trace.
authorCharles Yin <charles.yin@nokia.com>
Thu, 23 Jun 2011 01:39:56 +0000 (11:39 +1000)
committerCharles Yin <charles.yin@nokia.com>
Thu, 23 Jun 2011 01:39:56 +0000 (11:39 +1000)
Change-Id: I0ffebd2d22702bc14e1629b8bc0455a9cf8ea416

src/imports/testlib/SignalSpy.qml
src/imports/testlib/TestCase.qml
src/imports/testlib/main.cpp
src/imports/testlib/testlib.pro
src/qmltest/quicktest.cpp

index 6764129..627ca9f 100644 (file)
@@ -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")
     }
 
index 3659c60..0ba6c3b 100644 (file)
@@ -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)
index 5ef07b9..012a30b 100644 (file)
 #include <QtScript/qscriptengine.h>
 #include "QtQuickTest/private/quicktestresult_p.h"
 #include "QtQuickTest/private/quicktestevent_p.h"
+#include "private/qtestoptions_p.h"
+#include "QtDeclarative/qsgitem.h"
+#include <QtDeclarative/private/qdeclarativeengine_p.h>
 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 <QtDebug>
+
+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<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
+        int count = stacks->GetFrameCount();
+        if (count >= frameIndex + 2) {
+            v8::Local<v8::StackFrame> 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<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
+        int count = stacks->GetFrameCount();
+        if (count >= frameIndex + 2) {
+            v8::Local<v8::StackFrame> 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<QuickTestResult>(uri,1,0,"TestResult");
         qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
+        qmlRegisterType<QuickTestUtil>(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));
     }
 };
 
index 80bd5c5..92c5a09 100644 (file)
@@ -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 +=
index 19e15f2..9b12b02 100644 (file)
@@ -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();