Commit fa71a487 authored by hjk's avatar hjk
Browse files

debugger: work on autotests

parent af3a387b
......@@ -252,6 +252,7 @@ void GdbEngine::initializeVariables()
m_debuggingHelperState = DebuggingHelperUninitialized;
m_gdbVersion = 100;
m_gdbBuildVersion = -1;
m_isSynchroneous = false;
m_fullToShortName.clear();
m_shortToFullName.clear();
......@@ -1310,6 +1311,16 @@ void GdbEngine::handleShowVersion(const GdbResponse &response)
}
}
void GdbEngine::handleIsSynchroneous(const GdbResponse &response)
{
Q_UNUSED(response);
if (response.resultClass == GdbResultDone) {
m_isSynchroneous = true;
} else {
m_isSynchroneous = false;
}
}
void GdbEngine::handleExecContinue(const GdbResponse &response)
{
if (response.resultClass == GdbResultRunning) {
......@@ -3247,7 +3258,7 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
item.findChild("valuetooltipencoded").data().toInt());
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
setWatchDataValueEditable(data, item.findChild("valueeditable"));
//qDebug() << "HANDLE CHILDREN: " << data.toString();
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
list->append(data);
// try not to repeat data too often
......@@ -3370,7 +3381,6 @@ void GdbEngine::updateLocals()
if (isSynchroneous()) {
QStringList expanded = m_manager->watchHandler()->expandedINames().toList();
qDebug() << "EXPANDED: " << expanded;
postCommand(_("bb %1").arg(expanded.join(_(","))),
WatchUpdate, CB(handleStackFrame1));
postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2));
......@@ -3393,7 +3403,7 @@ void GdbEngine::handleStackFrame1(const GdbResponse &response)
out.chop(1);
//qDebug() << "FIRST CHUNK: " << out;
m_firstChunk = out;
} else if (response.resultClass == GdbResultError) {
} else {
QTC_ASSERT(false, /**/);
}
}
......@@ -3406,24 +3416,25 @@ void GdbEngine::handleStackFrame2(const GdbResponse &response)
out.chop(1);
//qDebug() << "SECOND CHUNK: " << out;
out = m_firstChunk + out;
// FIXME: Hack, make sure dumper does not return "{}"
out.replace(",{}", "");
GdbMi all("[" + out + "]");
qDebug() << "ALL: " << all.toString();
QList<GdbMi> locals = all.children();
//manager()->watchHandler()->insertBulkData(locals);
//setLocals(locals);
//GdbMi all(out);
//qDebug() << "\n\n\nALL: " << all.toString() << "\n";
GdbMi locals = all.findChild("locals");
//qDebug() << "\n\n\nLOCALS: " << locals.toString() << "\n";
WatchData *data = manager()->watchHandler()->findItem(_("local"));
QTC_ASSERT(data, return);
QList<WatchData> list;
foreach (const GdbMi &local, locals)
handleChildren(*data, local, &list);
//foreach (const GdbMi &local, locals.children)
// handleChildren(*data, local, &list);
handleChildren(*data, locals, &list);
//for (int i = 0; i != list.size(); ++i)
// qDebug() << "READ: " << list.at(i).toString();
manager()->watchHandler()->insertBulkData(list);
manager()->watchHandler()->updateWatchers();
} else if (response.resultClass == GdbResultError) {
} else {
QTC_ASSERT(false, /**/);
}
}
......@@ -4094,6 +4105,7 @@ void GdbEngine::handleAdapterStarted()
debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING GDB"));
postCommand(_("show version"), CB(handleShowVersion));
postCommand(_("help bb"), CB(handleIsSynchroneous));
//postCommand(_("-enable-timings");
postCommand(_("set print static-members off")); // Seemingly doesn't work.
//postCommand(_("set debug infrun 1"));
......@@ -4253,7 +4265,7 @@ void GdbEngine::showMessageBox(int icon, const QString &title, const QString &te
bool GdbEngine::isSynchroneous() const
{
return false;
return m_isSynchroneous;
}
//
......
......@@ -269,6 +269,7 @@ private:
void handleShowVersion(const GdbResponse &response);
void handleQuerySources(const GdbResponse &response);
void handleWatchPoint(const GdbResponse &response);
void handleIsSynchroneous(const GdbResponse &response);
bool showToolTip();
// Convenience
......@@ -299,6 +300,7 @@ private:
int m_gdbVersion; // 6.8.0 is 680
int m_gdbBuildVersion; // MAC only?
bool m_isSynchroneous; // Can act synchroneously?
// awful hack to keep track of used files
QMap<QString, QString> m_shortToFullName;
......
......@@ -868,16 +868,21 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
void WatchModel::insertData(const WatchData &data)
{
// qDebug() << "WMI:" << data.toString();
//qDebug() << "WMI:" << data.toString();
//static int bulk = 0;
//qDebug() << "SINGLE: " << ++bulk << data.toString();
QTC_ASSERT(!data.iname.isEmpty(), return);
if (data.iname.isEmpty()) {
int x;
x = 1;
}
QTC_ASSERT(!data.iname.isEmpty(), qDebug() << data.toString(); return);
WatchItem *parent = findItem(parentName(data.iname), m_root);
if (!parent) {
WatchData parent;
parent.iname = parentName(data.iname);
insertData(parent);
//MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
if (!parent.iname.isEmpty())
insertData(parent);
return;
}
QModelIndex index = watchIndex(parent);
......@@ -1098,10 +1103,12 @@ void WatchHandler::insertData(const WatchData &data)
return;
}
if (data.isSomethingNeeded()) {
MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
m_manager->updateWatchData(data);
} else {
WatchModel *model = modelForIName(data.iname);
QTC_ASSERT(model, return);
MODEL_DEBUG("NOTHING NEEDED: " << data.toString());
model->insertData(data);
}
}
......@@ -1372,7 +1379,7 @@ WatchModel *WatchHandler::modelForIName(const QString &iname) const
return m_watchers;
if (iname.startsWith(QLatin1String("tooltip")))
return m_tooltips;
QTC_ASSERT(false, /**/);
QTC_ASSERT(false, qDebug() << "INAME: " << iname);
return 0;
}
......
......@@ -5,8 +5,8 @@
#include <QtCore/private/qobject_p.h>
#include <QtGui/QStandardItemModel>
#include <QtGui/QStringListModel>
//#include <QtGui/QStandardItemModel>
//#include <QtGui/QStringListModel>
#include <QtTest/QtTest>
......@@ -29,6 +29,15 @@
# define NSY ""
#endif
//#define DO_DEBUG 1
#undef DEBUG
#if DO_DEBUG
# define DEBUG(s) qDebug() << s
#else
# define DEBUG(s)
#endif
#define DEBUGX(s) qDebug() << s
#define gettid() QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16)
using namespace Debugger;
......@@ -36,6 +45,7 @@ using namespace Debugger::Internal;
typedef QList<QByteArray> QByteArrayList;
#if 0
static QByteArray operator<<(QByteArray ba, const QByteArray &replacement)
{
int pos = ba.indexOf('%');
......@@ -53,6 +63,7 @@ static QByteArray &operator<<=(QByteArray &ba, const QByteArray &replacement)
template <typename T>
inline QByteArray N(T t) { return QByteArray::number(t); }
#endif
......@@ -84,7 +95,7 @@ public slots:
void handleGdbFinished(int, QProcess::ExitStatus);
void writeToGdbRequested(const QByteArray &ba)
{
//qDebug() << "THREAD GDB IN: " << ba;
DEBUG("THREAD GDB IN: " << ba);
m_proc->write(ba);
m_proc->write("\n");
}
......@@ -92,7 +103,8 @@ public slots:
public:
QByteArray m_output;
QByteArray m_error;
QByteArray m_lastStopped; // last seen "*stopped" message
int m_line; // line extracted from last "*stopped" message
QProcess *m_proc; // owned
tst_Gdb *m_test; // not owned
};
......@@ -102,10 +114,25 @@ class tst_Gdb : public QObject
Q_OBJECT
public:
tst_Gdb() : m_thread(this) {}
tst_Gdb();
void initTestCase() {}
void cleanupTestCase();
void prepare(const QByteArray &function);
void run(const QByteArray &label, const QByteArray &expected,
const QByteArray &expanded = QByteArray());
void next(int n = 1);
signals:
void writeToGdb(const QByteArray &ba);
private slots:
void dumpQString();
void dumpQStringList();
public slots:
void dumperCompatibility();
#if 0
void dumpQAbstractItemAndModelIndex();
void dumpQAbstractItemModel();
void dumpQByteArray();
......@@ -143,20 +170,10 @@ public slots:
void dumpQVariant_QStringList();
void dumpStdVector();
void dumpQWeakPointer();
void initTestCase();
void cleanupTestCase();
void runTestCase(const QByteArray &name,
const QByteArray &type,
const QByteArrayList &expexted);
signals:
void writeToGdb(const QByteArray &ba);
private slots:
void dumpQString();
void dumpQStringList();
#endif
private:
#if 0
void dumpQAbstractItemHelper(QModelIndex &index);
void dumpQAbstractItemModelHelper(QAbstractItemModel &m);
void dumpQDateTimeHelper(const QDateTime &d);
......@@ -177,8 +194,11 @@ private:
void dumpQWeakPointerHelper(QWeakPointer<T> &ptr);
#endif
void dumpQTextCodecHelper(QTextCodec *codec);
#endif
private:
QHash<QByteArray, int> m_lineForLabel;
QByteArray m_function;
Thread m_thread;
};
......@@ -189,37 +209,6 @@ QWaitCondition m_waitCondition;
// Dumpers
//
static void testDumper(QByteArray expected, const void *data, QByteArray outertype,
bool dumpChildren, QByteArray actual____ = QByteArray(),
QByteArray = QByteArray(), int = 0, int = 0, int = 0, int = 0)
{
Q_UNUSED(dumpChildren);
expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
"children=[" + expected + "],arg=''}";
char buf[100];
sprintf(buf, "%p", data);
//if ((!expected.startsWith('t') && !expected.startsWith('f'))
// || expected.startsWith("type"))
// expected = "tiname='$I',addr='$A'," + expected;
expected.replace("$I", "iname");
expected.replace("$T", QByteArray(outertype));
expected.replace("$A", QByteArray(buf));
if (actual____ != expected) {
QByteArrayList l1 = actual____.split(',');
QByteArrayList l2 = expected.split(',');
for (int i = 0; i < l1.size() && i < l2.size(); ++i) {
if (l1.at(i) == l2.at(i))
qWarning() << "== " << l1.at(i);
else
//qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30);
qWarning() << "!= " << l1.at(i) << l2.at(i);
}
if (l1.size() != l2.size())
qWarning() << "!= size: " << l1.size() << l2.size();
}
QCOMPARE(actual____, expected);
}
QByteArray str(const void *p)
{
char buf[100];
......@@ -227,10 +216,12 @@ QByteArray str(const void *p)
return buf;
}
#if 0
static const void *deref(const void *p)
{
return *reinterpret_cast<const char* const*>(p);
}
#endif
void tst_Gdb::dumperCompatibility()
{
......@@ -241,6 +232,7 @@ void tst_Gdb::dumperCompatibility()
QCOMPARE(size_t(&v->array), qVectorDataSize);
}
#if 0
static const QByteArray utfToBase64(const QString &string)
{
return QByteArray(reinterpret_cast<const char *>(string.utf16()), 2 * string.size()).toBase64();
......@@ -396,6 +388,8 @@ void getMapNodeParams(size_t &nodeSize, size_t &valOffset)
#endif
}
#endif
#if 0
void tst_Gdb::dumpQAbstractItemHelper(QModelIndex &index)
{
const QAbstractItemModel *model = index.model();
......@@ -2134,6 +2128,7 @@ void tst_Gdb::dumpQWeakPointer()
dumpQWeakPointerHelper(wpS);
#endif
}
#endif // #if 0
#define VERIFY_OFFSETOF(member) \
do { \
......@@ -2179,16 +2174,40 @@ void Thread::handleGdbFinished(int, QProcess::ExitStatus)
void Thread::readStandardOutput()
{
QByteArray ba = m_proc->readAllStandardOutput();
if (ba.isEmpty())
return;
//DEBUGX("THREAD GDB OUT: " << ba);
// =library-loaded...
if (ba.startsWith("="))
return;
//if (ba.startsWith("~"))
// return;
if (ba.startsWith("*stopped")) {
m_lastStopped = ba;
//qDebug() << "THREAD GDB OUT: " << ba;
if (!ba.contains("func=\"main\"")) {
int pos1 = ba.indexOf(",line=\"") + 7;
int pos2 = ba.indexOf("\"", pos1);
m_line = ba.mid(pos1, pos2 - pos1).toInt();
DEBUG(" LINE 1: " << m_line);
}
}
// The "call" is always aborted with a message like:
// "~"2321\t /* A */ QString s;\n" "
// "&"The program being debugged stopped while in a function called ..."
// "^error,msg="The program being debugged stopped ..."
// Extract the "2321" from this
static QByteArray lastText;
if (ba.startsWith("~"))
lastText = ba;
if (ba.startsWith("&\"The program being debugged")) {
int pos1 = 2;
int pos2 = lastText.indexOf("\\", pos1);
m_line = lastText.mid(pos1, pos2 - pos1).toInt();
DEBUG(" LINE 2: " << m_line);
}
if (ba.startsWith("~\"XXX: "))
qWarning() << "MESSAGE: " << ba.mid(7, ba.size() - 11);
if (!ba.startsWith("~\"locals="))
return;
//qDebug() << "THREAD GDB OUT: " << ba;
//m_output += ba;
ba = ba.mid(2, ba.size() - 4);
ba = ba.replace("\\\"", "\"");
......@@ -2198,11 +2217,8 @@ void Thread::readStandardOutput()
void Thread::readStandardError()
{
return;
QByteArray ba = m_proc->readAllStandardOutput();
qDebug() << "THREAD GDB ERR: " << ba;
m_error += ba;
m_waitCondition.wakeAll();
}
void Thread::handleGdbStarted()
......@@ -2215,44 +2231,98 @@ void Thread::run()
//qDebug() << "\nTHREAD RUN" << getpid() << gettid();
m_proc->start("./gdb -i mi --args ./tst_gdb run");
m_proc->waitForStarted();
m_proc->write("b main\n");
m_proc->write("break main\n");
m_proc->write("run\n");
m_proc->write("handle SIGSTOP stop pass\n");
//qDebug() << "\nTHREAD RUNNING";
exec();
}
void tst_Gdb::initTestCase()
tst_Gdb::tst_Gdb()
: m_thread(this)
{
// FIXME: Wait until gdb proc is running.
QTest::qWait(1000);
QTest::qWait(300);
QFile file("tst_gdb.cpp");
Q_ASSERT(file.open(QIODevice::ReadOnly));
QByteArray funcName;
const QByteArrayList bal = file.readAll().split('\n');
Q_ASSERT(bal.size() > 100);
for (int i = 0; i != bal.size(); ++i) {
const QByteArray &ba = bal.at(i);
if (ba.startsWith("void dump")) {
int pos = ba.indexOf('(');
funcName = ba.mid(5, pos - 5) + '@';
} else if (ba.startsWith(" /*")) {
int pos = ba.indexOf('*', 7);
m_lineForLabel[funcName + ba.mid(7, pos - 8)] = i + 1;
}
}
qWarning() << m_lineForLabel;
}
void tst_Gdb::runTestCase(const QByteArray &name, const QByteArray &type,
const QByteArrayList &expected)
void tst_Gdb::prepare(const QByteArray &function)
{
//qDebug() << "\nABOUT TO RUN TEST: " << name << m_thread.m_proc;
m_function = function;
writeToGdb("b " + function);
writeToGdb("call " + function + "()");
}
writeToGdb("b " + name);
void tst_Gdb::run(const QByteArray &label,
const QByteArray &expected0, const QByteArray &expanded)
{
//qDebug() << "\nABOUT TO RUN TEST: " << function << m_thread.m_proc;
writeToGdb("bb " + expanded);
m_mutex.lock();
m_waitCondition.wait(&m_mutex);
QByteArray ba = m_thread.m_output;
m_mutex.unlock();
//GdbMi locals;
//locals.fromString("{" + ba + "}");
QByteArray received = ba.replace("\"", "'");
//qDebug() << "OUTPUT: " << ba << "\n\n";
//qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
for (int i = 0; i != expected.size(); ++i) {
if (i == 0)
writeToGdb("call " + name + "()");
else
writeToGdb("next");
writeToGdb("bb");
m_mutex.lock();
m_waitCondition.wait(&m_mutex);
QByteArray ba = m_thread.m_output;
m_mutex.unlock();
//GdbMi locals;
//locals.fromString("{" + ba + "}");
QByteArray received = ba.replace("\"", "'");
//qDebug() << "OUTPUT: " << ba << "\n\n";
//qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
testDumper(expected.at(i), 0, type, false, received);
QByteArray actual____ = received;
QByteArray expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
"children=[" + expected0 + "]}";
int line = m_thread.m_line;
if (actual____ != expected) {
qWarning() << "LINE: " << line << "ACT/EXP";
QByteArrayList l1 = actual____.split(',');
QByteArrayList l2 = expected.split(',');
int i = 0;
for ( ; i < l1.size() && i < l2.size(); ++i) {
if (l1.at(i) == l2.at(i))
qWarning() << "== " << l1.at(i);
else
//qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30);
qWarning() << "!= " << l1.at(i) << l2.at(i);
}
for ( ; i < l2.size(); ++i)
qWarning() << "!= " << "-----" << l2.at(i);
for ( ; i < l1.size(); ++i)
qWarning() << "!= " << l1.at(i) << "-----";
if (l1.size() != l2.size())
qWarning() << "!= size: " << l1.size() << l2.size();
}
//qDebug() << "LABEL: " << m_function + '@' + label;
QCOMPARE(actual____, expected);
int expline = m_lineForLabel.value(m_function + '@' + label);
int actline = line;
if (actline != expline) {
qWarning() << "LAST STOPPED: " << m_thread.m_lastStopped;
}
QCOMPARE(actline, expline);
}
void tst_Gdb::next(int n)
{
for (int i = 0; i != n; ++i)
writeToGdb("next");
}
void tst_Gdb::cleanupTestCase()
......@@ -2264,47 +2334,44 @@ void tst_Gdb::cleanupTestCase()
void dumpQStringTest()
{
QString s;
s = "hallo";
s += "x";
s += "y";
}
/* A */ QString s;
/* B */ s = "hallo";
/* C */ s += "x";
/* D */ }
void tst_Gdb::dumpQString()
{
QByteArrayList bal;
bal.append("{iname='local.s',addr='0xbffff19c',name='S',"
"type='"NS"QString',value='<not in scope>',numchild='0'}");
//bal.append("xxx");
//bal.append("xxx");
runTestCase("dumpQStringTest", NS"QString", bal);
/*
testDumper("value='',valueencoded='2',type='$T',numchild='0'",
&s, NS"QString", false);
s = "abc";
testDumper("value='YQBiAGMA',valueencoded='2',type='$T',numchild='0'",
&s, NS"QString", false);
*/
prepare("dumpQStringTest");
run("A", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
"value='<not in scope>',numchild='0'}");
next();
run("B", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
"valueencoded='7',value='',numchild='0'}");
next();
run("C", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
"valueencoded='7',value='680061006c006c006f00',numchild='0'}");
next();
run("D", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
"valueencoded='7',value='680061006c006c006f007800',numchild='0'}");
}
void dumpQStringListTest()
{
QStringList s;
/* A */ QStringList s;
/* B */ s.append("hello");
/* C */ s.append("world");
}
void tst_Gdb::dumpQStringList()
{
QByteArrayList bal;
//bal.append("xxx");
runTestCase("dumpQStringListTest", NS"QStringList", bal);
prepare("dumpQStringListTest");
run("A", "xxx");
}
int runit(int &argc, char *argv[])
{
// Plain call. Start the testing.
QApplication app(argc, argv);
QCoreApplication app(argc, argv);
tst_Gdb test;
return QTest::qExec(&test, argc, argv);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment