QV8Engine: Console APIs
authorAurindam Jana <aurindam.jana@nokia.com>
Tue, 8 Nov 2011 10:39:16 +0000 (11:39 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 11 Nov 2011 11:59:02 +0000 (12:59 +0100)
Modified functionality for console.log, console.debug. Added
script and line information. Added functions console.warn
and console.error.

Change-Id: Id9f4dce5658a09b00522f8e087caf8f4242f418a
Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp
src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h
src/declarative/qml/v8/qv8engine.cpp
tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml
tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp
tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp

index 918fd52..fed0569 100644 (file)
@@ -66,29 +66,69 @@ QT_BEGIN_NAMESPACE
 
 namespace QDeclarativeBuiltinFunctions {
 
-v8::Handle<v8::Value> gc(const v8::Arguments &args)
-{
-    Q_UNUSED(args);
-    QV8Engine::gc();
-    return v8::Undefined();
-}
+enum ConsoleLogTypes {
+    Log,
+    Warn,
+    Error
+};
 
-v8::Handle<v8::Value> print(const v8::Arguments &args)
+v8::Handle<v8::Value> console(ConsoleLogTypes logType, const v8::Arguments &args)
 {
+    int line = -1;
+    QString scriptName;
+    v8::HandleScope handleScope;
+
+    {
+        v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1);
+        if (stackTrace->GetFrameCount()) {
+            v8::Local<v8::StackFrame> currentStackFrame = stackTrace->GetFrame(0);
+            line = currentStackFrame->GetLineNumber();
+            scriptName = V8ENGINE()->toString(currentStackFrame->GetScriptName());
+        }
+    }
+
     QString result;
     for (int i = 0; i < args.Length(); ++i) {
         if (i != 0)
             result.append(QLatin1Char(' '));
 
-        v8::Local<v8::String> jsstr = args[i]->ToString();
-        if (!jsstr.IsEmpty()) {
-            QString qstr;
-            qstr.resize(jsstr->Length());
-            jsstr->Write((uint16_t*)qstr.data());
-            result.append(qstr);
+        v8::Local<v8::Value> value = args[i];
+        //Check for Object Type
+        if (value->IsObject() && !value->IsFunction()
+                && !value->IsArray() && !value->IsDate()
+                && !value->IsRegExp()) {
+            result = QLatin1String("Object");
+        } else {
+            v8::Local<v8::String> jsstr = value->ToString();
+            result.append(V8ENGINE()->toString(jsstr));
+            if (value->IsArray())
+                result = QString(QLatin1String("[%1]")).arg(result);
         }
     }
-    qDebug("%s", qPrintable(result));
+
+    QString log = QString(QLatin1String("%1 (%2:%3)")).arg(result).arg(scriptName).arg(line);
+
+    switch (logType) {
+    case Log:
+        qDebug("%s", qPrintable(log));
+        break;
+    case Warn:
+        qWarning("%s", qPrintable(log));
+        break;
+    case Error:
+        qCritical("%s", qPrintable(log));
+        break;
+    default:
+        break;
+    }
+
+    return v8::Undefined();
+}
+
+v8::Handle<v8::Value> gc(const v8::Arguments &args)
+{
+    Q_UNUSED(args);
+    QV8Engine::gc();
     return v8::Undefined();
 }
 
@@ -114,6 +154,24 @@ v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args)
     return v8::Undefined();
 }
 
+v8::Handle<v8::Value> consoleLog(const v8::Arguments &args)
+{
+    //console.log
+    //console.debug
+    //print
+    return console(Log, args);
+}
+
+v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args)
+{
+    return console(Warn, args);
+}
+
+v8::Handle<v8::Value> consoleError(const v8::Arguments &args)
+{
+    return console(Error, args);
+}
+
 v8::Handle<v8::Value> stringArg(const v8::Arguments &args)
 {
     QString value = V8ENGINE()->toString(args.This()->ToString());
index 35ea885..8810f77 100644 (file)
@@ -61,7 +61,11 @@ QT_BEGIN_NAMESPACE
 namespace QDeclarativeBuiltinFunctions
 {
 v8::Handle<v8::Value> gc(const v8::Arguments &args);
-v8::Handle<v8::Value> print(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleLog(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleError(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTime(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args);
 v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
 v8::Handle<v8::Value> rgba(const v8::Arguments &args);
 v8::Handle<v8::Value> hsla(const v8::Arguments &args);
@@ -91,8 +95,6 @@ v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleTime(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args);
 v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
 }
 
index 6f744e5..791c972 100644 (file)
@@ -518,13 +518,17 @@ struct StaticQtMetaObject : public QObject
 void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
 {
     using namespace QDeclarativeBuiltinFunctions;
-    v8::Local<v8::Function> printFn = V8FUNCTION(print, this);
-    v8::Local<v8::Function> consoleTimeFn = V8FUNCTION(consoleTime, this);
-    v8::Local<v8::Function> consoleTimeEndFn = V8FUNCTION(consoleTimeEnd, this);
 
     v8::Local<v8::Object> console = v8::Object::New();
-    console->Set(v8::String::New("log"), printFn);
-    console->Set(v8::String::New("debug"), printFn);
+    v8::Local<v8::Function> consoleLogFn = V8FUNCTION(consoleLog, this);
+    v8::Local<v8::Function> consoleWarnFn = V8FUNCTION(consoleWarn, this);
+    v8::Local<v8::Function> consoleErrorFn = V8FUNCTION(consoleError, this);
+    v8::Local<v8::Function> consoleTimeFn = V8FUNCTION(consoleTime, this);
+    v8::Local<v8::Function> consoleTimeEndFn = V8FUNCTION(consoleTimeEnd, this);
+    console->Set(v8::String::New("log"), consoleLogFn);
+    console->Set(v8::String::New("debug"), consoleLogFn);
+    console->Set(v8::String::New("warn"), consoleWarnFn);
+    console->Set(v8::String::New("error"), consoleErrorFn);
     console->Set(v8::String::New("time"), consoleTimeFn);
     console->Set(v8::String::New("timeEnd"), consoleTimeEndFn);
 
@@ -579,7 +583,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
     global->Set(v8::String::New("qsTrId"), V8FUNCTION(qsTrId, this));
     global->Set(v8::String::New("QT_TRID_NOOP"), V8FUNCTION(qsTrIdNoOp, this));
 
-    global->Set(v8::String::New("print"), printFn);
+    global->Set(v8::String::New("print"), consoleLogFn);
     global->Set(v8::String::New("console"), console);
     global->Set(v8::String::New("Qt"), qt);
     global->Set(v8::String::New("gc"), V8FUNCTION(QDeclarativeBuiltinFunctions::gc, this));
index 515c8fa..34b8e10 100644 (file)
@@ -806,9 +806,11 @@ void tst_qdeclarativeanimations::attached()
 {
     QDeclarativeEngine engine;
 
-    QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("attached.qml")));
-    QTest::ignoreMessage(QtDebugMsg, "off");
-    QTest::ignoreMessage(QtDebugMsg, "on");
+    QUrl url(QUrl::fromLocalFile(TESTDATA("attached.qml")));
+    QDeclarativeComponent c(&engine, url);
+    QString messageFormat = QString(QLatin1String("%1 (%2:%3)"));
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("off")).arg(url.toString()).arg(24).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("on")).arg(url.toString()).arg(20).toLatin1());
     QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
     QVERIFY(rect);
 }
index cccbdb0..492ed73 100644 (file)
@@ -1590,7 +1590,8 @@ void tst_qdeclarativeecmascript::shutdownErrors()
 void tst_qdeclarativeecmascript::compositePropertyType()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
-    QTest::ignoreMessage(QtDebugMsg, "hello world");
+    QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7);
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat));
     QObject *object = qobject_cast<QObject *>(component.create());
     delete object;
 }
@@ -4362,7 +4363,8 @@ void tst_qdeclarativeecmascript::qtbug_9792()
     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
     QVERIFY(object != 0);
 
-    QTest::ignoreMessage(QtDebugMsg, "Hello world!");
+    QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
     object->basicSignal();
 
     delete context;
index 64ab5d8..a3fb5f0 100644 (file)
@@ -850,7 +850,8 @@ void tst_qdeclarativelanguage::dynamicObjectProperties()
 // Tests the declaration of dynamic signals and slots
 void tst_qdeclarativelanguage::dynamicSignalsAndSlots()
 {
-    QTest::ignoreMessage(QtDebugMsg, "1921");
+    QString message = QString(QLatin1String("1921 (%1:%2)")).arg(TEST_FILE("dynamicSignalsAndSlots.qml").toString()).arg(9);
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
 
     QDeclarativeComponent component(&engine, TEST_FILE("dynamicSignalsAndSlots.qml"));
     VERIFY_ERRORS(0);
@@ -1288,9 +1289,10 @@ void tst_qdeclarativelanguage::onCompleted()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("onCompleted.qml"));
     VERIFY_ERRORS(0);
-    QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
-    QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
-    QTest::ignoreMessage(QtDebugMsg, "Completed 10 11");
+    QString formatMessage = QString(QLatin1String("%1 (%2:%3)"));
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(8).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(14).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 10 11")).arg(TEST_FILE("OnCompletedType.qml").toString()).arg(7).toLatin1());
     QObject *object = component.create();
     QVERIFY(object != 0);
 }
@@ -1302,10 +1304,10 @@ void tst_qdeclarativelanguage::onDestruction()
     VERIFY_ERRORS(0);
     QObject *object = component.create();
     QVERIFY(object != 0);
-
-    QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
-    QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
-    QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11");
+    QString formatMessage = QString(QLatin1String("%1 (%2:%3)"));
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(8).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(14).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 10 11")).arg(TEST_FILE("OnDestructionType.qml").toString()).arg(7).toLatin1());
     delete object;
 }
 
index 4c581cf..afb758a 100644 (file)
@@ -1,8 +1,30 @@
 import QtQuick 2.0
 
 QtObject {
+    id: root
     Component.onCompleted: {
+        var a = [1, 2]
+        var b = {a: "hello", d: 1 }
+        var c
+        var d = 12
+        var e = function() { return 5;}
+        var f = true
+        var g = {toString: function() { throw new Error('toString'); }}
+
+
         console.log("completed", "ok")
         console.log("completed ok")
+        console.debug("completed ok")
+        console.warn("completed ok")
+        console.error("completed ok")
+        console.log(a)
+        console.log(b)
+        console.log(c)
+        console.log(d)
+        console.log(e)
+        console.log(f)
+        console.log(root)
+        console.log(g)
+        console.log(exception) //This has to be at the end
     }
 }
index b6cebf4..c550ac2 100644 (file)
@@ -437,8 +437,8 @@ void tst_qdeclarativeqt::createQmlObject()
     QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n    " + TEST_FILE("main.qml").toString() + ":4:1: Duplicate property name";
     QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object";
     QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments";
-    QString warning6 = "RunTimeError:  Qt.createQmlObject(): failed to create object: \n    " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method";
-
+    QString messageFormat = QString(QLatin1String("%1 (%2:%3)"));
+    QString warning6 = messageFormat.arg("RunTimeError:  Qt.createQmlObject(): failed to create object: \n    " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method").arg(TEST_FILE("createQmlObject.qml").toString()).arg(23);
     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3));
@@ -461,9 +461,34 @@ void tst_qdeclarativeqt::createQmlObject()
 
 void tst_qdeclarativeqt::consoleLog()
 {
-    QTest::ignoreMessage(QtDebugMsg, "completed ok");
-    QTest::ignoreMessage(QtDebugMsg, "completed ok");
-    QDeclarativeComponent component(&engine, TEST_FILE("consoleLog.qml"));
+    int startLineNumber = 15;
+    QUrl testFileUrl = TEST_FILE("consoleLog.qml");
+    QString testString = QString(QLatin1String("completed ok (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(testString.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtCriticalMsg, qPrintable(testString.arg(startLineNumber++)));
+
+    QString testArray = QString(QLatin1String("[1,2] (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testArray.arg(startLineNumber++)));
+    QString testObject = QString(QLatin1String("Object (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++)));
+    QString testUndefined = QString(QLatin1String("undefined (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testUndefined.arg(startLineNumber++)));
+    QString testNumber = QString(QLatin1String("12 (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testNumber.arg(startLineNumber++)));
+    QString testFunction = QString(QLatin1String("function () { return 5;} (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testFunction.arg(startLineNumber++)));
+    QString testBoolean = QString(QLatin1String("true (%1:%2)")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testBoolean.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++)));
+    QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++)));
+
+    QString testException = QString(QLatin1String("%1:%2: ReferenceError: Can't find variable: exception")).arg(testFileUrl.toString());
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(testException.arg(startLineNumber++)));
+
+    QDeclarativeComponent component(&engine, testFileUrl);
     QObject *object = component.create();
     QVERIFY(object != 0);
     delete object;
index 05975aa..5c9760a 100644 (file)
@@ -1228,8 +1228,9 @@ void tst_qdeclarativestates::tempState()
     QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
     QVERIFY(rect != 0);
     QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
-    QTest::ignoreMessage(QtDebugMsg, "entering placed");
-    QTest::ignoreMessage(QtDebugMsg, "entering idle");
+    QString messageFormat = QString(QLatin1String("%1 (file://%2:%3)"));
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering placed")).arg(TESTDATA("legalTempState.qml")).arg(11).toLatin1());
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering idle")).arg(TESTDATA("legalTempState.qml")).arg(15).toLatin1());
     rectPrivate->setState("placed");
     QCOMPARE(rectPrivate->state(), QLatin1String("idle"));
 }
index db0e05b..b9a249f 100644 (file)
@@ -1059,8 +1059,9 @@ void tst_qdeclarativevaluetypes::bindingConflict()
 // doesn't crash
 void tst_qdeclarativevaluetypes::deletedObject()
 {
+    QString messageFormat = QString(QLatin1String("%1 (%2:%3)"));
     QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
-    QTest::ignoreMessage(QtDebugMsg, "Test: 2");
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: 2")).arg(TEST_FILE("deletedObject.js").toString()).arg(6).toLatin1());
     MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
     QVERIFY(object != 0);
 
@@ -1068,7 +1069,7 @@ void tst_qdeclarativevaluetypes::deletedObject()
     QVERIFY(dObject != 0);
     delete dObject;
 
-    QTest::ignoreMessage(QtDebugMsg, "Test: undefined");
+    QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: undefined")).arg(TEST_FILE("deletedObject.js").toString()).arg(11).toLatin1());
     object->emitRunScript();
 
     delete object;