diff options
author | Erik Verbruggen <erik.verbruggen@me.com> | 2013-10-16 12:29:47 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-10 11:01:35 +0100 |
commit | 0910a577f4d12eea4a099c989bd58f1dee6c88db (patch) | |
tree | 53860b5debf08cef684da1eb387769dbe8ef2d42 /tests/auto/qml/qv4debugger | |
parent | 1738e4ee119bbcd20d33353e7018f04d92766639 (diff) |
Debugging with V4
Currently missing, but coming in subsequent patches:
- evaluating expressions
- evaluating breakpoint conditions
Change-Id: Ib43f2a3aaa252741ea7ce857a274480feb8741aa
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'tests/auto/qml/qv4debugger')
-rw-r--r-- | tests/auto/qml/qv4debugger/tst_qv4debugger.cpp | 210 |
1 files changed, 151 insertions, 59 deletions
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 56df3a469a..15a6acc272 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -45,6 +45,9 @@ #include <private/qv4debugging_p.h> #include <private/qv8engine_p.h> +using namespace QV4; +using namespace QV4::Debugging; + static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) { QEventLoop loop; @@ -95,32 +98,109 @@ signals: Q_DECLARE_METATYPE(TestEngine::InjectedFunction) +namespace { +class TestCollector: public QV4::Debugging::Debugger::Collector +{ +public: + TestCollector(QV4::ExecutionEngine *engine) + : Collector(engine) + , destination(0) + {} + + virtual ~TestCollector() {} + + void setDestination(QVariantMap *dest) + { destination = dest; } + +protected: + virtual void addUndefined(const QString &name) + { + destination->insert(name, QStringLiteral("undefined")); // TODO: add a user-defined type for this + } + + virtual void addNull(const QString &name) + { + destination->insert(name, QStringLiteral("null")); // TODO: add a user-defined type for this + } + + virtual void addBoolean(const QString &name, bool value) + { + destination->insert(name, value); + } + + virtual void addString(const QString &name, const QString &value) + { + destination->insert(name, value); + } + + virtual void addObject(const QString &name, QV4::ValueRef value) + { + QV4::Scope scope(engine()); + QV4::ScopedObject obj(scope, value->asObject()); + + QVariantMap props, *prev = &props; + qSwap(destination, prev); + collect(obj); + qSwap(destination, prev); + + destination->insert(name, props); + } + + virtual void addInteger(const QString &name, int value) + { + destination->insert(name, QVariant::fromValue<double>(static_cast<double>(value))); + } + + virtual void addDouble(const QString &name, double value) + { + destination->insert(name, QVariant::fromValue<double>(value)); + } + +private: + QVariantMap *destination; +}; +} + class TestAgent : public QV4::Debugging::DebuggerAgent { Q_OBJECT public: - typedef QV4::Debugging::Debugger Debugger; - TestAgent() : m_wasPaused(false) , m_captureContextInfo(false) { } - virtual void debuggerPaused(Debugger *debugger) + virtual void debuggerPaused(Debugger *debugger, PauseReason reason) { Q_ASSERT(m_debuggers.count() == 1 && m_debuggers.first() == debugger); m_wasPaused = true; + m_pauseReason = reason; m_statesWhenPaused << debugger->currentExecutionState(); + TestCollector collector(debugger->engine()); + QVariantMap tmp; + collector.setDestination(&tmp); + debugger->collectThrownValue(&collector); + m_thrownValue = tmp["exception"]; + foreach (const TestBreakPoint &bp, m_breakPointsToAddWhenPaused) debugger->addBreakPoint(bp.fileName, bp.lineNumber); m_breakPointsToAddWhenPaused.clear(); + m_stackTrace = debugger->stackTrace(); + if (m_captureContextInfo) captureContextInfo(debugger); - debugger->resume(); + debugger->resume(Debugger::FullThrottle); + } + + virtual void sourcesCollected(Debugger *debugger, QStringList sources, int requestSequenceNr) + { + Q_UNUSED(debugger); + Q_UNUSED(sources); + Q_UNUSED(requestSequenceNr); } int debuggerCount() const { return m_debuggers.count(); } @@ -136,25 +216,30 @@ public: void captureContextInfo(Debugger *debugger) { - m_stackTrace = debugger->stackTrace(); + TestCollector collector(debugger->engine()); + for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) { - m_capturedArguments.append(debugger->retrieveArgumentsFromContext(QStringList(), i)); - m_capturedLocals.append(debugger->retrieveLocalsFromContext(QStringList(), i)); + QVariantMap args; + collector.setDestination(&args); + debugger->collectArgumentsInContext(&collector, i); + m_capturedArguments.append(args); + + QVariantMap locals; + collector.setDestination(&locals); + debugger->collectLocalsInContext(&collector, i); + m_capturedLocals.append(locals); } - - foreach (const QStringList &path, m_localPathsToRead) - m_localPathResults += debugger->retrieveLocalsFromContext(path); } bool m_wasPaused; + PauseReason m_pauseReason; bool m_captureContextInfo; - QList<QV4::Debugging::Debugger::ExecutionState> m_statesWhenPaused; + QList<Debugger::ExecutionState> m_statesWhenPaused; QList<TestBreakPoint> m_breakPointsToAddWhenPaused; QVector<QV4::StackFrame> m_stackTrace; - QList<QList<Debugger::VarInfo> > m_capturedArguments; - QList<QList<Debugger::VarInfo> > m_capturedLocals; - QList<QStringList> m_localPathsToRead; - QList<QList<Debugger::VarInfo> > m_localPathResults; + QList<QVariantMap> m_capturedArguments; + QList<QVariantMap> m_capturedLocals; + QVariant m_thrownValue; // Utility methods: void dumpStackTrace() const @@ -170,8 +255,6 @@ class tst_qv4debugger : public QObject { Q_OBJECT - typedef QV4::Debugging::Debugger::VarInfo VarInfo; - private slots: void init(); void cleanup(); @@ -190,6 +273,9 @@ private slots: void readObject(); void readContextInAllFrames(); + // exceptions: + void pauseOnThrow(); + private: void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1) { @@ -278,8 +364,8 @@ void tst_qv4debugger::removePendingBreakPoint() "var i = 42;\n" "var j = i + 1\n" "var k = i\n"; - m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2); - m_debuggerAgent->removeBreakPoint("removePendingBreakPoint", 2); + int id = m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2); + m_debuggerAgent->removeBreakPoint(id); evaluateJavaScript(script, "removePendingBreakPoint"); QVERIFY(!m_debuggerAgent->m_wasPaused); } @@ -339,16 +425,12 @@ void tst_qv4debugger::readArguments() evaluateJavaScript(script, "readArguments"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_capturedArguments[0].size(), 4); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][0].name, QString("a")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][0].type, VarInfo::Number); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][0].value.toDouble(), 1.0); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][1].name, QString("b")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][1].type, VarInfo::String); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][1].value.toString(), QLatin1String("two")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][2].name, QString("c")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][2].type, VarInfo::Null); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][3].name, QString("d")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[0][3].type, VarInfo::Undefined); + QVERIFY(m_debuggerAgent->m_capturedArguments[0].contains(QStringLiteral("a"))); + QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["a"].type(), QVariant::Double); + QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["a"].toDouble(), 1.0); + QVERIFY(m_debuggerAgent->m_capturedArguments[0].contains("b")); + QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["b"].type(), QVariant::String); + QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["b"].toString(), QLatin1String("two")); } void tst_qv4debugger::readLocals() @@ -365,11 +447,11 @@ void tst_qv4debugger::readLocals() evaluateJavaScript(script, "readLocals"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 2); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][0].name, QString("c")); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][0].type, VarInfo::Number); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][0].value.toDouble(), 3.0); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][1].name, QString("d")); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][1].type, VarInfo::Undefined); + QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("c")); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["c"].type(), QVariant::Double); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["c"].toDouble(), 3.0); + QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("d")); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["d"].toString(), QString("undefined")); } void tst_qv4debugger::readObject() @@ -382,31 +464,25 @@ void tst_qv4debugger::readObject() "}\n" "f({head: 1, tail: { head: 'asdf', tail: null }});\n"; m_debuggerAgent->addBreakPoint("readObject", 3); - m_debuggerAgent->m_localPathsToRead.append(QStringList() << QLatin1String("b")); - m_debuggerAgent->m_localPathsToRead.append(QStringList() << QLatin1String("b") << QLatin1String("tail")); evaluateJavaScript(script, "readObject"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 1); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][0].name, QString("b")); - QCOMPARE(m_debuggerAgent->m_capturedLocals[0][0].type, VarInfo::Object); - - QCOMPARE(m_debuggerAgent->m_localPathResults.size(), 2); + QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("b")); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["b"].type(), QVariant::Map); - QList<VarInfo> b = m_debuggerAgent->m_localPathResults[0]; + QVariantMap b = m_debuggerAgent->m_capturedLocals[0]["b"].toMap(); QCOMPARE(b.size(), 2); - QCOMPARE(b[0].name, QLatin1String("head")); - QCOMPARE(b[0].type, VarInfo::Number); - QCOMPARE(b[0].value.toDouble(), 1.0); - QCOMPARE(b[1].name, QLatin1String("tail")); - QCOMPARE(b[1].type, VarInfo::Object); + QVERIFY(b.contains("head")); + QCOMPARE(b["head"].type(), QVariant::Double); + QCOMPARE(b["head"].toDouble(), 1.0); + QVERIFY(b.contains("tail")); + QCOMPARE(b["tail"].type(), QVariant::Map); - QList<VarInfo> b_tail = m_debuggerAgent->m_localPathResults[1]; + QVariantMap b_tail = b["tail"].toMap(); QCOMPARE(b_tail.size(), 2); - QCOMPARE(b_tail[0].name, QLatin1String("head")); - QCOMPARE(b_tail[0].type, VarInfo::String); - QCOMPARE(b_tail[0].value.toString(), QLatin1String("asdf")); - QCOMPARE(b_tail[1].name, QLatin1String("tail")); - QCOMPARE(b_tail[1].type, VarInfo::Null); + QVERIFY(b_tail.contains("head")); + QCOMPARE(b_tail["head"].type(), QVariant::String); + QCOMPARE(b_tail["head"].toString(), QString("asdf")); } void tst_qv4debugger::readContextInAllFrames() @@ -431,23 +507,39 @@ void tst_qv4debugger::readContextInAllFrames() for (int i = 0; i < 12; ++i) { QCOMPARE(m_debuggerAgent->m_capturedArguments[i].size(), 1); - QCOMPARE(m_debuggerAgent->m_capturedArguments[i][0].name, QString("n")); - QCOMPARE(m_debuggerAgent->m_capturedArguments[i][0].type, VarInfo::Number); - QCOMPARE(m_debuggerAgent->m_capturedArguments[i][0].value.toInt(), i + 1); + QVERIFY(m_debuggerAgent->m_capturedArguments[i].contains("n")); + QCOMPARE(m_debuggerAgent->m_capturedArguments[i]["n"].type(), QVariant::Double); + QCOMPARE(m_debuggerAgent->m_capturedArguments[i]["n"].toDouble(), i + 1.0); QCOMPARE(m_debuggerAgent->m_capturedLocals[i].size(), 1); - QCOMPARE(m_debuggerAgent->m_capturedLocals[i][0].name, QString("n_1")); + QVERIFY(m_debuggerAgent->m_capturedLocals[i].contains("n_1")); if (i == 0) { - QCOMPARE(m_debuggerAgent->m_capturedLocals[i][0].type, VarInfo::Undefined); + QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].toString(), QString("undefined")); } else { - QCOMPARE(m_debuggerAgent->m_capturedLocals[i][0].type, VarInfo::Number); - QCOMPARE(m_debuggerAgent->m_capturedLocals[i][0].value.toInt(), i); + QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].type(), QVariant::Double); + QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].toInt(), i); } } QCOMPARE(m_debuggerAgent->m_capturedArguments[12].size(), 0); QCOMPARE(m_debuggerAgent->m_capturedLocals[12].size(), 0); } +void tst_qv4debugger::pauseOnThrow() +{ + QString script = + "function die(n) {\n" + " throw n\n" + "}\n" + "die('hard');\n"; + m_debuggerAgent->setBreakOnThrow(true); + evaluateJavaScript(script, "pauseOnThrow"); + QVERIFY(m_debuggerAgent->m_wasPaused); + QCOMPARE(m_debuggerAgent->m_pauseReason, Throwing); + QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2); + QCOMPARE(m_debuggerAgent->m_thrownValue.type(), QVariant::String); + QCOMPARE(m_debuggerAgent->m_thrownValue.toString(), QString("hard")); +} + QTEST_MAIN(tst_qv4debugger) #include "tst_qv4debugger.moc" |