File indexing completed on 2024-05-12 04:39:57

0001 /*
0002     SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com>
0003     SPDX-FileCopyrightText: 2013 Vlas Puhov <vlas.puhov@mail.ru>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "test_gdb.h"
0009 
0010 #include "debugsession.h"
0011 #include "gdbframestackmodel.h"
0012 #include "mi/micommand.h"
0013 #include "mi/milexer.h"
0014 #include "mi/miparser.h"
0015 #include "tests/debuggers-tests-config.h"
0016 #include "tests/testhelper.h"
0017 
0018 #include <execute/iexecuteplugin.h>
0019 #include <debugger/breakpoint/breakpoint.h>
0020 #include <debugger/breakpoint/breakpointmodel.h>
0021 #include <debugger/framestack/framestackmodel.h>
0022 #include <debugger/interfaces/ivariablecontroller.h>
0023 #include <debugger/variable/variablecollection.h>
0024 #include <interfaces/idebugcontroller.h>
0025 #include <interfaces/iplugincontroller.h>
0026 #include <tests/autotestshell.h>
0027 #include <tests/testcore.h>
0028 #include <shell/shellextension.h>
0029 
0030 #include <KIO/Global>
0031 #include <KProcess>
0032 #include <KSharedConfig>
0033 #include <KShell>
0034 
0035 #include <QApplication>
0036 #include <QDebug>
0037 #include <QDir>
0038 #include <QFileInfo>
0039 #include <QStandardPaths>
0040 #include <QSignalSpy>
0041 #include <QTest>
0042 #include <QTemporaryFile>
0043 
0044 using KDevelop::AutoTestShell;
0045 using KDevMI::findExecutable;
0046 using KDevMI::findSourceFile;
0047 using KDevMI::findFile;
0048 
0049 namespace KDevMI { namespace GDB {
0050 
0051 void GdbTest::initTestCase()
0052 {
0053 #ifdef Q_OS_WIN
0054     QSKIP("apparently this test is killing processes, but is leaving kdeinit5, dbus-daemon and klauncher running, "
0055           "breaking the Windows CI builder");
0056 #endif
0057     AutoTestShell::init();
0058     KDevelop::TestCore::initialize(KDevelop::Core::NoUi);
0059 
0060     m_iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute"))->extension<IExecutePlugin>();
0061     Q_ASSERT(m_iface);
0062 }
0063 
0064 void GdbTest::cleanupTestCase()
0065 {
0066     KDevelop::TestCore::shutdown();
0067 }
0068 
0069 void GdbTest::init()
0070 {
0071     //remove all breakpoints - so we can set our own in the test
0072     KConfigGroup breakpoints = KSharedConfig::openConfig()->group("breakpoints");
0073     breakpoints.writeEntry("number", 0);
0074     breakpoints.sync();
0075 
0076     KDevelop::BreakpointModel* m = KDevelop::ICore::self()->debugController()->breakpointModel();
0077     m->removeRows(0, m->rowCount());
0078 
0079     KDevelop::VariableCollection *vc = KDevelop::ICore::self()->debugController()->variableCollection();
0080     for (int i=0; i < vc->watches()->childCount(); ++i) {
0081         delete vc->watches()->child(i);
0082     }
0083     vc->watches()->clear();
0084 }
0085 
0086 class TestFrameStackModel : public GdbFrameStackModel
0087 {
0088     Q_OBJECT
0089 
0090 public:
0091 
0092     explicit TestFrameStackModel(DebugSession* session)
0093         : GdbFrameStackModel(session), fetchFramesCalled(0), fetchThreadsCalled(0) {}
0094 
0095     int fetchFramesCalled;
0096     int fetchThreadsCalled;
0097     void fetchFrames(int threadNumber, int from, int to) override
0098     {
0099         fetchFramesCalled++;
0100         GdbFrameStackModel::fetchFrames(threadNumber, from, to);
0101     }
0102 
0103     void fetchThreads() override
0104     {
0105         fetchThreadsCalled++;
0106         GdbFrameStackModel::fetchThreads();
0107     }
0108 };
0109 
0110 class TestDebugSession : public DebugSession
0111 {
0112     Q_OBJECT
0113 public:
0114     TestDebugSession() : DebugSession()
0115     {
0116         setSourceInitFile(false);
0117         setAutoDisableASLR(false);
0118         m_frameStackModel = new TestFrameStackModel(this);
0119         KDevelop::ICore::self()->debugController()->addSession(this);
0120     }
0121 
0122     QUrl url() { return currentUrl(); }
0123     int line() { return currentLine(); }
0124 
0125     TestFrameStackModel* frameStackModel() const override
0126     {
0127         return m_frameStackModel;
0128     }
0129 
0130 private:
0131     TestFrameStackModel* m_frameStackModel;
0132 };
0133 
0134 static const QString debugeeFileName = findSourceFile(QStringLiteral("debugee.cpp"));
0135 
0136 KDevelop::BreakpointModel* breakpoints()
0137 {
0138     return KDevelop::ICore::self()->debugController()->breakpointModel();
0139 }
0140 
0141 void GdbTest::testStdOut()
0142 {
0143     auto *session = new TestDebugSession;
0144 
0145     QSignalSpy outputSpy(session, &TestDebugSession::inferiorStdoutLines);
0146 
0147     TestLaunchConfiguration cfg;
0148     session->startDebugging(&cfg, m_iface);
0149     WAIT_FOR_STATE(session, KDevelop::IDebugSession::EndedState);
0150 
0151     {
0152         QCOMPARE(outputSpy.count(), 1);
0153         QList<QVariant> arguments = outputSpy.takeFirst();
0154         QCOMPARE(arguments.count(), 1);
0155         QCOMPARE(arguments.first().toStringList(), QStringList() << "Hello, world!" << "Hello");
0156     }
0157 }
0158 
0159 void GdbTest::testEnvironmentSet()
0160 {
0161     KDevMI::testEnvironmentSet(new TestDebugSession, QStringLiteral("GdbTestGroup"), m_iface);
0162 }
0163 
0164 void GdbTest::testBreakpoint()
0165 {
0166     auto *session = new TestDebugSession;
0167 
0168     TestLaunchConfiguration cfg;
0169 
0170     KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28);
0171     QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState);
0172 
0173     session->startDebugging(&cfg, m_iface);
0174     WAIT_FOR_STATE(session, DebugSession::PausedState);
0175     QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState);
0176     session->stepInto();
0177     WAIT_FOR_STATE(session, DebugSession::PausedState);
0178     session->stepInto();
0179     WAIT_FOR_STATE(session, DebugSession::PausedState);
0180     session->run();
0181     WAIT_FOR_STATE(session, DebugSession::EndedState);
0182 
0183     QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState);
0184 }
0185 
0186 void GdbTest::testDisableBreakpoint()
0187 {
0188     //Description: We must stop only on the third breakpoint
0189 
0190     int firstBreakLine=28;
0191     int secondBreakLine=23;
0192     int thirdBreakLine=24;
0193     int fourthBreakLine=31;
0194 
0195     auto *session = new TestDebugSession;
0196 
0197     TestLaunchConfiguration cfg;
0198 
0199     KDevelop::Breakpoint *b;
0200 
0201     b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), firstBreakLine);
0202     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
0203 
0204 
0205     //this is needed to emulate debug from GUI. If we are in edit mode, the debugSession doesn't exist.
0206     KDevelop::ICore::self()->debugController()->breakpointModel()->blockSignals(true);
0207     b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), secondBreakLine);
0208     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
0209     //all disabled breakpoints were added
0210 
0211     KDevelop::Breakpoint * thirdBreak = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), thirdBreakLine);
0212     KDevelop::ICore::self()->debugController()->breakpointModel()->blockSignals(false);
0213 
0214 
0215     session->startDebugging(&cfg, m_iface);
0216     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0217 
0218     QCOMPARE(session->currentLine(), thirdBreak->line());
0219 
0220     //disable existing breakpoint
0221     thirdBreak->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
0222 
0223     //add another disabled breakpoint
0224     b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), fourthBreakLine);
0225     QTest::qWait(300);
0226     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
0227 
0228     QTest::qWait(300);
0229     session->run();
0230     WAIT_FOR_STATE(session, DebugSession::EndedState);
0231 }
0232 
0233 void GdbTest::testChangeLocationBreakpoint()
0234 {
0235     auto *session = new TestDebugSession;
0236 
0237     TestLaunchConfiguration cfg;
0238 
0239     KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 27);
0240 
0241     session->startDebugging(&cfg, m_iface);
0242     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0243     QCOMPARE(session->line(), 28);
0244 
0245     QTest::qWait(100);
0246     b->setLine(29);
0247     QTest::qWait(100);
0248     session->run();
0249 
0250     QTest::qWait(100);
0251     WAIT_FOR_STATE(session, DebugSession::PausedState);
0252     QCOMPARE(session->line(), 29);
0253     QTest::qWait(500);
0254     breakpoints()->setData(breakpoints()->index(0, KDevelop::Breakpoint::LocationColumn), QString(debugeeFileName+":31"));
0255     QCOMPARE(b->line(), 30);
0256     QTest::qWait(100);
0257     QCOMPARE(b->line(), 30);
0258     session->run();
0259     QTest::qWait(100);
0260     WAIT_FOR_STATE(session, DebugSession::PausedState);
0261     QCOMPARE(session->line(), 30);
0262     session->run();
0263 
0264     WAIT_FOR_STATE(session, DebugSession::EndedState);
0265 }
0266 
0267 void GdbTest::testDeleteBreakpoint()
0268 {
0269     auto *session = new TestDebugSession;
0270 
0271     TestLaunchConfiguration cfg;
0272 
0273     QCOMPARE(breakpoints()->rowCount(), 0);
0274     //add breakpoint before startDebugging
0275     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21);
0276     QCOMPARE(breakpoints()->rowCount(), 1);
0277     QVERIFY(breakpoints()->removeRow(0));
0278     QCOMPARE(breakpoints()->rowCount(), 0);
0279 
0280     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22);
0281 
0282     session->startDebugging(&cfg, m_iface);
0283     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0284     QVERIFY(breakpoints()->removeRow(0));
0285     session->run();
0286 
0287     WAIT_FOR_STATE(session, DebugSession::EndedState);
0288 }
0289 
0290 void GdbTest::testPendingBreakpoint()
0291 {
0292     auto *session = new TestDebugSession;
0293     TestLaunchConfiguration cfg;
0294 
0295     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28);
0296 
0297     KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile(QStringLiteral("debugeeqt.cpp"))), 10);
0298     QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState);
0299 
0300     session->startDebugging(&cfg, m_iface);
0301     WAIT_FOR_STATE(session, DebugSession::PausedState);
0302     QCOMPARE(b->state(), KDevelop::Breakpoint::PendingState);
0303     session->run();
0304     WAIT_FOR_STATE(session, DebugSession::EndedState);
0305 }
0306 
0307 void GdbTest::testUpdateBreakpoint()
0308 {
0309     auto *session = new TestDebugSession;
0310     TestLaunchConfiguration cfg;
0311 
0312     // breakpoint 1: real line 29: foo();
0313     KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28);
0314     QCOMPARE(breakpoints()->rowCount(), 1);
0315 
0316     session->startDebugging(&cfg, m_iface);
0317 
0318     // breakpoint 2: real line 32: const char *x = "Hello";
0319     //insert custom command as user might do it using GDB console
0320     session->addCommand(std::make_unique<MI::UserCommand>(MI::NonMI, "break " + debugeeFileName + ":32"));
0321 
0322     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // stop at breakpoint 1, with custom command handled
0323     QCOMPARE(session->currentLine(), 28);
0324 
0325     // check breakpoint 2 got picked up
0326     QCOMPARE(breakpoints()->rowCount(), 2);
0327     b = breakpoints()->breakpoint(1);
0328     QCOMPARE(b->url(), QUrl::fromLocalFile(debugeeFileName));
0329     QCOMPARE(b->line(), 32);
0330 
0331     session->run();
0332     WAIT_FOR_STATE(session, DebugSession::PausedState); // stop at breakpoint 2
0333     QCOMPARE(session->currentLine(), 32);
0334     session->run();
0335     WAIT_FOR_STATE(session, DebugSession::EndedState);
0336 }
0337 
0338 void GdbTest::testIgnoreHitsBreakpoint()
0339 {
0340     auto *session = new TestDebugSession;
0341     TestLaunchConfiguration cfg;
0342 
0343     KDevelop::Breakpoint * b1 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21);
0344     b1->setIgnoreHits(1);
0345 
0346     KDevelop::Breakpoint * b2 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22);
0347 
0348     session->startDebugging(&cfg, m_iface);
0349 
0350     //WAIT_FOR_STATE(session, DebugSession::PausedState);
0351     WAIT_FOR(session, session->state() == DebugSession::PausedState && b2->hitCount() == 1);
0352     b2->setIgnoreHits(1);
0353     session->run();
0354     //WAIT_FOR_STATE(session, DebugSession::PausedState);
0355     WAIT_FOR(session, session->state() == DebugSession::PausedState && b1->hitCount() == 1);
0356     session->run();
0357     WAIT_FOR_STATE(session, DebugSession::EndedState);
0358 }
0359 
0360 void GdbTest::testConditionBreakpoint()
0361 {
0362     auto *session = new TestDebugSession;
0363     TestLaunchConfiguration cfg;
0364 
0365     KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39);
0366     b->setCondition(QStringLiteral("x[0] == 'H'"));
0367 
0368     b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 23);
0369     b->setCondition(QStringLiteral("i==2"));
0370 
0371     b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
0372 
0373     session->startDebugging(&cfg, m_iface);
0374 
0375     WAIT_FOR(session, session->state() == DebugSession::PausedState && session->line() == 24);
0376     b->setCondition(QStringLiteral("i == 0"));
0377     QTest::qWait(100);
0378     session->run();
0379     WAIT_FOR_STATE(session, DebugSession::PausedState);
0380     QCOMPARE(session->line(), 23);
0381     session->run();
0382     WAIT_FOR_STATE(session, DebugSession::PausedState);
0383     QCOMPARE(session->line(), 39);
0384     session->run();
0385     WAIT_FOR_STATE(session, DebugSession::EndedState);
0386 }
0387 
0388 void GdbTest::testBreakOnWriteBreakpoint()
0389 {
0390     auto *session = new TestDebugSession;
0391     TestLaunchConfiguration cfg;
0392 
0393     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
0394 
0395     session->startDebugging(&cfg, m_iface);
0396 
0397     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0398     QCOMPARE(session->line(), 24);
0399 
0400     breakpoints()->addWatchpoint(QStringLiteral("i"));
0401     QTest::qWait(100);
0402 
0403     session->run();
0404     WAIT_FOR_STATE(session, DebugSession::PausedState);
0405     QCOMPARE(session->line(), 22); // line 23: ++i; int j = i;
0406     session->run();
0407     WAIT_FOR_STATE(session, DebugSession::PausedState);
0408     QCOMPARE(session->line(), 24);
0409     session->run();
0410     WAIT_FOR_STATE(session, DebugSession::EndedState);
0411 }
0412 
0413 void GdbTest::testBreakOnWriteWithConditionBreakpoint()
0414 {
0415     auto *session = new TestDebugSession;
0416     TestLaunchConfiguration cfg;
0417 
0418     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
0419 
0420     session->startDebugging(&cfg, m_iface);
0421 
0422     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0423     QCOMPARE(session->line(), 24);
0424 
0425     KDevelop::Breakpoint *b = breakpoints()->addWatchpoint(QStringLiteral("i"));
0426     b->setCondition(QStringLiteral("i==2"));
0427     QTest::qWait(100);
0428 
0429     session->run();
0430     WAIT_FOR_STATE(session, DebugSession::PausedState);
0431     QCOMPARE(session->line(), 22); // line 23: ++i; int j = i;
0432     session->run();
0433     WAIT_FOR_STATE(session, DebugSession::PausedState);
0434     QCOMPARE(session->line(), 24);
0435     session->run();
0436     WAIT_FOR_STATE(session, DebugSession::EndedState);
0437 }
0438 
0439 void GdbTest::testBreakOnReadBreakpoint()
0440 {
0441     /*
0442     test disabled because of gdb bug: http://sourceware.org/bugzilla/show_bug.cgi?id=10136
0443 
0444     TestDebugSession *session = new TestDebugSession;
0445     TestLaunchConfiguration cfg;
0446 
0447     KDevelop::Breakpoint *b = breakpoints()->addReadWatchpoint("foo::i");
0448 
0449     session->startDebugging(&cfg, m_iface);
0450 
0451     WAIT_FOR_STATE(session, DebugSession::PausedState);
0452     QCOMPARE(session->line(), 23);
0453     session->run();
0454     WAIT_FOR_STATE(session, DebugSession::EndedState);
0455     */
0456 }
0457 
0458 void GdbTest::testBreakOnReadBreakpoint2()
0459 {
0460     auto *session = new TestDebugSession;
0461     TestLaunchConfiguration cfg;
0462 
0463     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
0464 
0465     session->startDebugging(&cfg, m_iface);
0466 
0467     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0468     QCOMPARE(session->line(), 24);
0469 
0470     breakpoints()->addReadWatchpoint(QStringLiteral("i"));
0471 
0472     session->run();
0473     WAIT_FOR_STATE(session, DebugSession::PausedState);
0474     QCOMPARE(session->line(), 22); // ++i
0475 
0476     session->run();
0477     WAIT_FOR_STATE(session, DebugSession::PausedState);
0478     QCOMPARE(session->line(), 22); // int j = i
0479 
0480     session->run();
0481     WAIT_FOR_STATE(session, DebugSession::PausedState);
0482     if(session->line() == 22) { // some GDB versions break 3 times on this line
0483         session->run();
0484         WAIT_FOR_STATE(session, DebugSession::PausedState);
0485     }
0486     QCOMPARE(session->line(), 24);
0487 
0488     session->run();
0489     WAIT_FOR_STATE(session, DebugSession::EndedState);
0490 }
0491 
0492 void GdbTest::testBreakOnAccessBreakpoint()
0493 {
0494     auto *session = new TestDebugSession;
0495     TestLaunchConfiguration cfg;
0496 
0497     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
0498 
0499     session->startDebugging(&cfg, m_iface);
0500 
0501     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0502     QCOMPARE(session->line(), 24);
0503 
0504     breakpoints()->addAccessWatchpoint(QStringLiteral("i"));
0505 
0506     session->run();
0507     WAIT_FOR_STATE(session, DebugSession::PausedState);
0508     QCOMPARE(session->line(), 22); // line 23: ++i (read)
0509 
0510     session->run();
0511     WAIT_FOR_STATE(session, DebugSession::PausedState);
0512     QCOMPARE(session->line(), 22); // line 23: ++i (write)
0513 
0514     session->run();
0515     WAIT_FOR_STATE(session, DebugSession::PausedState);
0516     QCOMPARE(session->line(), 22); // line 23: int j = i (read)
0517 
0518     session->run();
0519     WAIT_FOR_STATE(session, DebugSession::PausedState);
0520     QCOMPARE(session->line(), 24);
0521 
0522     session->run();
0523     WAIT_FOR_STATE(session, DebugSession::EndedState);
0524 }
0525 
0526 void GdbTest::testInsertBreakpointWhileRunning()
0527 {
0528     auto *session = new TestDebugSession;
0529     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow"));
0530     QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp"));
0531 
0532     session->startDebugging(&cfg, m_iface);
0533 
0534     WAIT_FOR_STATE(session, DebugSession::ActiveState);
0535     QTest::qWait(2000);
0536     qDebug() << "adding breakpoint";
0537     KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 29); // ++i;
0538     QTest::qWait(500);
0539     WAIT_FOR_STATE(session, DebugSession::PausedState);
0540     QTest::qWait(500);
0541     QCOMPARE(session->line(), 29); // ++i;
0542     breakpoints()->removeBreakpoint(b);
0543     session->run();
0544     WAIT_FOR_STATE(session, DebugSession::EndedState);
0545 }
0546 
0547 void GdbTest::testInsertBreakpointWhileRunningMultiple()
0548 {
0549     auto *session = new TestDebugSession;
0550     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow"));
0551     QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp"));
0552 
0553     session->startDebugging(&cfg, m_iface);
0554 
0555     WAIT_FOR_STATE(session, DebugSession::ActiveState);
0556     QTest::qWait(2000);
0557     qDebug() << "adding breakpoint";
0558     KDevelop::Breakpoint *b1 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 29); // static int i=0;
0559     KDevelop::Breakpoint *b2 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 30); // ++i;
0560     QTest::qWait(500);
0561     WAIT_FOR_STATE(session, DebugSession::PausedState);
0562     QTest::qWait(500);
0563     QCOMPARE(session->line(), 29); // static int i=0;
0564     session->run();
0565     WAIT_FOR_STATE(session, DebugSession::PausedState);
0566     QTest::qWait(500);
0567     QCOMPARE(session->line(), 30); // ++i;
0568     breakpoints()->removeBreakpoint(b1);
0569     breakpoints()->removeBreakpoint(b2);
0570     session->run();
0571     WAIT_FOR_STATE(session, DebugSession::EndedState);
0572 }
0573 
0574 void GdbTest::testInsertBreakpointFunctionName()
0575 {
0576     auto *session = new TestDebugSession;
0577     TestLaunchConfiguration cfg;
0578 
0579     breakpoints()->addCodeBreakpoint(QStringLiteral("main"));
0580 
0581     session->startDebugging(&cfg, m_iface);
0582     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0583     QCOMPARE(session->line(), 28);
0584     session->run();
0585     WAIT_FOR_STATE(session, DebugSession::EndedState);
0586 }
0587 
0588 void GdbTest::testManualBreakpoint()
0589 {
0590     auto *session = new TestDebugSession;
0591     TestLaunchConfiguration cfg;
0592 
0593     breakpoints()->addCodeBreakpoint(QStringLiteral("main"));
0594 
0595     session->startDebugging(&cfg, m_iface);
0596     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0597     QCOMPARE(session->line(), 28);
0598 
0599     breakpoints()->removeRows(0, 1);
0600     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0601     QCOMPARE(breakpoints()->rowCount(), 0);
0602 
0603     session->addCommand(MI::NonMI, QStringLiteral("break debugee.cpp:23"));
0604     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0605     QCOMPARE(breakpoints()->rowCount(), 1);
0606 
0607     KDevelop::Breakpoint* b = breakpoints()->breakpoint(0);
0608     QCOMPARE(b->line(), 22);
0609 
0610     session->addCommand(MI::NonMI, QStringLiteral("disable 2"));
0611     session->addCommand(MI::NonMI, QStringLiteral("condition 2 i == 1"));
0612     session->addCommand(MI::NonMI, QStringLiteral("ignore 2 1"));
0613     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0614     QCOMPARE(b->enabled(), false);
0615     QCOMPARE(b->condition(), QString("i == 1"));
0616     QCOMPARE(b->ignoreHits(), 1);
0617 
0618     session->addCommand(MI::NonMI, QStringLiteral("delete 2"));
0619     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0620     QCOMPARE(breakpoints()->rowCount(), 0);
0621 
0622     session->run();
0623     WAIT_FOR_STATE(session, DebugSession::EndedState);
0624 }
0625 
0626 void GdbTest::testShowStepInSource()
0627 {
0628     auto *session = new TestDebugSession;
0629 
0630     QSignalSpy showStepInSourceSpy(session, &TestDebugSession::showStepInSource);
0631 
0632     TestLaunchConfiguration cfg;
0633 
0634     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29);
0635     session->startDebugging(&cfg, m_iface);
0636     WAIT_FOR_STATE(session, DebugSession::PausedState);
0637     session->stepInto();
0638     WAIT_FOR_STATE(session, DebugSession::PausedState);
0639     session->stepInto();
0640     WAIT_FOR_STATE(session, DebugSession::PausedState);
0641     session->run();
0642     WAIT_FOR_STATE(session, DebugSession::EndedState);
0643 
0644     {
0645         QCOMPARE(showStepInSourceSpy.count(), 3);
0646         QList<QVariant> arguments = showStepInSourceSpy.takeFirst();
0647         QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName));
0648         QCOMPARE(arguments.at(1).toInt(), 29);
0649 
0650         arguments = showStepInSourceSpy.takeFirst();
0651         QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName));
0652         QCOMPARE(arguments.at(1).toInt(), 22);
0653 
0654         arguments = showStepInSourceSpy.takeFirst();
0655         QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName));
0656         QCOMPARE(arguments.at(1).toInt(), 23);
0657     }
0658 }
0659 
0660 void GdbTest::testStack()
0661 {
0662     auto *session = new TestDebugSession;
0663     TestLaunchConfiguration cfg;
0664 
0665     TestFrameStackModel *stackModel = session->frameStackModel();
0666 
0667     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21);
0668     QVERIFY(session->startDebugging(&cfg, m_iface));
0669     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0670 
0671     QModelIndex tIdx = stackModel->index(0,0);
0672     QCOMPARE(stackModel->rowCount(QModelIndex()), 1);
0673     QCOMPARE(stackModel->columnCount(QModelIndex()), 3);
0674     COMPARE_DATA(tIdx, "#1 at foo");
0675 
0676     QCOMPARE(stackModel->rowCount(tIdx), 2);
0677     QCOMPARE(stackModel->columnCount(tIdx), 3);
0678     COMPARE_DATA(stackModel->index(0, 0, tIdx), "0");
0679     COMPARE_DATA(stackModel->index(0, 1, tIdx), "foo");
0680     COMPARE_DATA(stackModel->index(0, 2, tIdx), debugeeFileName+":23");
0681     COMPARE_DATA(stackModel->index(1, 0, tIdx), "1");
0682     COMPARE_DATA(stackModel->index(1, 1, tIdx), "main");
0683     COMPARE_DATA(stackModel->index(1, 2, tIdx), debugeeFileName+":30");
0684 
0685 
0686     session->stepOut();
0687     WAIT_FOR_STATE(session, DebugSession::PausedState);
0688     COMPARE_DATA(tIdx, "#1 at main");
0689     QCOMPARE(stackModel->rowCount(tIdx), 1);
0690     COMPARE_DATA(stackModel->index(0, 0, tIdx), "0");
0691     COMPARE_DATA(stackModel->index(0, 1, tIdx), "main");
0692     // depending on the compiler and gdb version, we may either end up in
0693     // one line or the other
0694     const auto last = stackModel->index(0, 2, tIdx).data().toString();
0695     if (last.endsWith(":30"))
0696         QCOMPARE(last, debugeeFileName + ":30");
0697     else
0698         QCOMPARE(last, debugeeFileName + ":31");
0699 
0700     session->run();
0701     WAIT_FOR_STATE(session, DebugSession::PausedState);
0702     session->run();
0703     WAIT_FOR_STATE(session, DebugSession::EndedState);
0704 }
0705 
0706 void GdbTest::testStackFetchMore()
0707 {
0708     auto *session = new TestDebugSession;
0709     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeerecursion"));
0710     QString fileName = findSourceFile(QStringLiteral("debugeerecursion.cpp"));
0711 
0712     TestFrameStackModel *stackModel = session->frameStackModel();
0713 
0714     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 25);
0715     QVERIFY(session->startDebugging(&cfg, m_iface));
0716     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0717     QCOMPARE(session->frameStackModel()->fetchFramesCalled, 1);
0718 
0719     QModelIndex tIdx = stackModel->index(0,0);
0720     QCOMPARE(stackModel->rowCount(QModelIndex()), 1);
0721     QCOMPARE(stackModel->columnCount(QModelIndex()), 3);
0722     COMPARE_DATA(tIdx, "#1 at foo");
0723 
0724     QCOMPARE(stackModel->rowCount(tIdx), 21);
0725     COMPARE_DATA(stackModel->index(0, 0, tIdx), "0");
0726     COMPARE_DATA(stackModel->index(0, 1, tIdx), "foo");
0727     COMPARE_DATA(stackModel->index(0, 2, tIdx), fileName+":26");
0728     COMPARE_DATA(stackModel->index(1, 0, tIdx), "1");
0729     COMPARE_DATA(stackModel->index(1, 1, tIdx), "foo");
0730     COMPARE_DATA(stackModel->index(1, 2, tIdx), fileName+":24");
0731     COMPARE_DATA(stackModel->index(2, 0, tIdx), "2");
0732     COMPARE_DATA(stackModel->index(2, 1, tIdx), "foo");
0733     COMPARE_DATA(stackModel->index(2, 2, tIdx), fileName+":24");
0734     COMPARE_DATA(stackModel->index(19, 0, tIdx), "19");
0735     COMPARE_DATA(stackModel->index(20, 0, tIdx), "20");
0736 
0737     stackModel->fetchMoreFrames();
0738     QTest::qWait(200);
0739     QCOMPARE(stackModel->fetchFramesCalled, 2);
0740     QCOMPARE(stackModel->rowCount(tIdx), 41);
0741     COMPARE_DATA(stackModel->index(20, 0, tIdx), "20");
0742     COMPARE_DATA(stackModel->index(21, 0, tIdx), "21");
0743     COMPARE_DATA(stackModel->index(22, 0, tIdx), "22");
0744     COMPARE_DATA(stackModel->index(39, 0, tIdx), "39");
0745     COMPARE_DATA(stackModel->index(40, 0, tIdx), "40");
0746 
0747     stackModel->fetchMoreFrames();
0748     QTest::qWait(200);
0749     QCOMPARE(stackModel->fetchFramesCalled, 3);
0750     QCOMPARE(stackModel->rowCount(tIdx), 121);
0751     COMPARE_DATA(stackModel->index(40, 0, tIdx), "40");
0752     COMPARE_DATA(stackModel->index(41, 0, tIdx), "41");
0753     COMPARE_DATA(stackModel->index(42, 0, tIdx), "42");
0754     COMPARE_DATA(stackModel->index(119, 0, tIdx), "119");
0755     COMPARE_DATA(stackModel->index(120, 0, tIdx), "120");
0756 
0757     stackModel->fetchMoreFrames();
0758     QTest::qWait(200);
0759     QCOMPARE(stackModel->fetchFramesCalled, 4);
0760     QCOMPARE(stackModel->rowCount(tIdx), 299);
0761     COMPARE_DATA(stackModel->index(120, 0, tIdx), "120");
0762     COMPARE_DATA(stackModel->index(121, 0, tIdx), "121");
0763     COMPARE_DATA(stackModel->index(122, 0, tIdx), "122");
0764     COMPARE_DATA(stackModel->index(298, 0, tIdx), "298");
0765     COMPARE_DATA(stackModel->index(298, 1, tIdx), "main");
0766     COMPARE_DATA(stackModel->index(298, 2, tIdx), fileName+":30");
0767 
0768     stackModel->fetchMoreFrames(); //nothing to fetch, we are at the end
0769     QTest::qWait(200);
0770     QCOMPARE(stackModel->fetchFramesCalled, 4);
0771     QCOMPARE(stackModel->rowCount(tIdx), 299);
0772 
0773     session->run();
0774     WAIT_FOR_STATE(session, DebugSession::EndedState);
0775 }
0776 
0777 void GdbTest::testStackDeactivateAndActive()
0778 {
0779     auto *session = new TestDebugSession;
0780     TestLaunchConfiguration cfg;
0781 
0782     TestFrameStackModel *stackModel = session->frameStackModel();
0783 
0784     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21);
0785     QVERIFY(session->startDebugging(&cfg, m_iface));
0786     WAIT_FOR_STATE(session, DebugSession::PausedState);
0787 
0788     QModelIndex tIdx = stackModel->index(0,0);
0789 
0790     session->stepOut();
0791     WAIT_FOR_STATE(session, DebugSession::PausedState);
0792     QTest::qWait(200);
0793     COMPARE_DATA(tIdx, "#1 at main");
0794     QCOMPARE(stackModel->rowCount(tIdx), 1);
0795     COMPARE_DATA(stackModel->index(0, 0, tIdx), "0");
0796     COMPARE_DATA(stackModel->index(0, 1, tIdx), "main");
0797     // depending on the compiler and gdb version, we may either end up in
0798     // one line or the other
0799     const auto last = stackModel->index(0, 2, tIdx).data().toString();
0800     if (last.endsWith(":30"))
0801         QCOMPARE(last, debugeeFileName + ":30");
0802     else
0803         QCOMPARE(last, debugeeFileName + ":31");
0804 
0805     session->run();
0806     WAIT_FOR_STATE(session, DebugSession::PausedState);
0807     session->run();
0808     WAIT_FOR_STATE(session, DebugSession::EndedState);
0809 }
0810 
0811 void GdbTest::testStackSwitchThread()
0812 {
0813     auto *session = new TestDebugSession;
0814     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeethreads"));
0815     QString fileName = findSourceFile(QStringLiteral("debugeethreads.cpp"));
0816 
0817     TestFrameStackModel *stackModel = session->frameStackModel();
0818 
0819     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 42); // t3.start();
0820     QVERIFY(session->startDebugging(&cfg, m_iface));
0821     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
0822 
0823     qDebug() << stackModel->rowCount();
0824     QVERIFY(stackModel->rowCount() > 2);
0825 
0826     QModelIndex tIdx = stackModel->index(0,0);
0827     COMPARE_DATA(tIdx, "#1 at main");
0828     QCOMPARE(stackModel->rowCount(tIdx), 1);
0829     COMPARE_DATA(stackModel->index(0, 0, tIdx), "0");
0830     COMPARE_DATA(stackModel->index(0, 1, tIdx), "main");
0831     COMPARE_DATA(stackModel->index(0, 2, tIdx), fileName+":43"); // QThread::usleep(500000);
0832 
0833     tIdx = stackModel->index(1,0);
0834     QVERIFY(stackModel->data(tIdx).toString().startsWith("#2 at "));
0835     stackModel->setCurrentThread(2);
0836     QTRY_VERIFY(stackModel->rowCount(tIdx) > 3);
0837 
0838     session->run();
0839     WAIT_FOR_STATE(session, DebugSession::EndedState);
0840 }
0841 
0842 void GdbTest::testAttach()
0843 {
0844     SKIP_IF_ATTACH_FORBIDDEN();
0845 
0846     QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp"));
0847 
0848     KProcess debugeeProcess;
0849     debugeeProcess << QStringLiteral("nice") << findExecutable(QStringLiteral("debuggee_debugeeslow")).toLocalFile();
0850     debugeeProcess.start();
0851     QVERIFY(debugeeProcess.waitForStarted());
0852     QTest::qWait(100);
0853 
0854     auto *session = new TestDebugSession;
0855     session->attachToProcess(debugeeProcess.processId());
0856     WAIT_FOR_STATE(session, DebugSession::PausedState);
0857 
0858     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 39); // } after foo();
0859     QTest::qWait(100);
0860     session->run();
0861     QTest::qWait(2000);
0862     WAIT_FOR_STATE(session, DebugSession::PausedState);
0863     if (session->line() < 39 || session->line() < 40) {
0864         QCOMPARE(session->line(), 39);
0865     }
0866 
0867     session->run();
0868     WAIT_FOR_STATE(session, DebugSession::EndedState);
0869 }
0870 
0871 void GdbTest::testManualAttach()
0872 {
0873     SKIP_IF_ATTACH_FORBIDDEN();
0874 
0875     KProcess debugeeProcess;
0876     debugeeProcess << QStringLiteral("nice") << findExecutable(QStringLiteral("debuggee_debugeeslow")).toLocalFile();
0877     debugeeProcess.start();
0878     QVERIFY(debugeeProcess.waitForStarted());
0879 
0880     auto *session = new TestDebugSession;
0881 
0882     TestLaunchConfiguration cfg;
0883     cfg.config().writeEntry(Config::RemoteGdbRunEntry,
0884                             QUrl::fromLocalFile(findFile(GDB_SRC_DIR,
0885                                                          QStringLiteral("unittests/gdb_script_empty"))));
0886     QVERIFY(session->startDebugging(&cfg, m_iface));
0887 
0888     session->addCommand(MI::NonMI, QStringLiteral("attach %0").arg(debugeeProcess.processId()));
0889     WAIT_FOR_STATE(session, DebugSession::PausedState);
0890 
0891     session->run();
0892     QTest::qWait(2000); // give the slow inferior some extra time to run
0893     WAIT_FOR_STATE(session, DebugSession::EndedState);
0894 }
0895 
0896 void GdbTest::testCoreFile()
0897 {
0898     QFileInfo f(QStringLiteral("core"));
0899     f.setCaching(false); // don't cache information
0900     if (f.exists()) {
0901         QVERIFY(QFile::remove(f.canonicalFilePath()));
0902     }
0903 
0904     KProcess debugeeProcess;
0905     debugeeProcess.setOutputChannelMode(KProcess::MergedChannels);
0906     debugeeProcess << QStringLiteral("bash") << QStringLiteral("-c")
0907                    << "ulimit -c unlimited; "
0908                       + findExecutable(QStringLiteral("debuggee_crash")).toLocalFile();
0909     debugeeProcess.start();
0910     debugeeProcess.waitForFinished();
0911     qDebug() << "Debuggee output:\n" << debugeeProcess.readAll();
0912 
0913     bool coreFileFound = f.exists();
0914     if (!coreFileFound) {
0915         // Try to use coredumpctl
0916         auto coredumpctl = QStandardPaths::findExecutable(QStringLiteral("coredumpctl"));
0917         if (!coredumpctl.isEmpty()) {
0918             KProcess::execute(coredumpctl, {"-1", "-o", f.absoluteFilePath(), "dump", "debuggee_crash"}, 5000);
0919             // coredumpctl seems to create an empty file "core" even if no cores can be delivered
0920             // (like when run inside docker containers as on KDE CI or with kernel.core_pattern=|/dev/null)
0921             // so also check for size != 0
0922             coreFileFound = f.exists() && (f.size() > 0);
0923         }
0924     }
0925     if (!coreFileFound)
0926         QSKIP("no core dump found, check your system configuration (see /proc/sys/kernel/core_pattern).");
0927 
0928     auto *session = new TestDebugSession;
0929     session->examineCoreFile(findExecutable(QStringLiteral("debuggee_crash")),
0930                              QUrl::fromLocalFile(f.canonicalFilePath()));
0931 
0932     TestFrameStackModel *stackModel = session->frameStackModel();
0933 
0934     WAIT_FOR_STATE(session, DebugSession::StoppedState);
0935 
0936     QModelIndex tIdx = stackModel->index(0,0);
0937     QCOMPARE(stackModel->rowCount(QModelIndex()), 1);
0938     QCOMPARE(stackModel->columnCount(QModelIndex()), 3);
0939     COMPARE_DATA(tIdx, "#1 at foo");
0940 
0941     session->stopDebugger();
0942     WAIT_FOR_STATE(session, DebugSession::EndedState);
0943 }
0944 
0945 
0946 KDevelop::VariableCollection *variableCollection()
0947 {
0948     return KDevelop::ICore::self()->debugController()->variableCollection();
0949 }
0950 
0951 void GdbTest::testVariablesLocals()
0952 {
0953     auto *session = new TestDebugSession;
0954     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
0955 
0956     TestLaunchConfiguration cfg;
0957 
0958     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22);
0959     QVERIFY(session->startDebugging(&cfg, m_iface));
0960     WAIT_FOR_STATE(session, DebugSession::PausedState);
0961     QTest::qWait(1000);
0962 
0963     QCOMPARE(variableCollection()->rowCount(), 2);
0964     QModelIndex i = variableCollection()->index(1, 0);
0965     COMPARE_DATA(i, "Locals");
0966     QCOMPARE(variableCollection()->rowCount(i), 2);
0967     COMPARE_DATA(variableCollection()->index(0, 0, i), "i");
0968     COMPARE_DATA(variableCollection()->index(0, 1, i), "0");
0969     COMPARE_DATA(variableCollection()->index(1, 0, i), "j");
0970     // COMPARE_DATA(variableCollection()->index(1, 1, i), "1"); // j is not initialized yet
0971     session->run();
0972     QTest::qWait(1000);
0973     WAIT_FOR_STATE(session, DebugSession::PausedState);
0974     COMPARE_DATA(variableCollection()->index(0, 0, i), "i");
0975     COMPARE_DATA(variableCollection()->index(0, 1, i), "1");
0976     COMPARE_DATA(variableCollection()->index(1, 0, i), "j");
0977     COMPARE_DATA(variableCollection()->index(1, 1, i), "1");
0978     session->run();
0979     WAIT_FOR_STATE(session, DebugSession::EndedState);
0980 }
0981 
0982 void GdbTest::testVariablesLocalsStruct()
0983 {
0984     auto *session = new TestDebugSession;
0985     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
0986 
0987     TestLaunchConfiguration cfg;
0988 
0989     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39);
0990     QVERIFY(session->startDebugging(&cfg, m_iface));
0991     WAIT_FOR_STATE(session, DebugSession::PausedState);
0992     QTest::qWait(1000);
0993 
0994     QModelIndex i = variableCollection()->index(1, 0);
0995     QCOMPARE(variableCollection()->rowCount(i), 4);
0996 
0997     int structIndex = 0;
0998     for(int j=0; j<3; ++j) {
0999         if (variableCollection()->index(j, 0, i).data().toString() == QLatin1String("ts")) {
1000             structIndex = j;
1001         }
1002     }
1003 
1004     COMPARE_DATA(variableCollection()->index(structIndex, 0, i), "ts");
1005     COMPARE_DATA(variableCollection()->index(structIndex, 1, i), "{...}");
1006     QModelIndex ts = variableCollection()->index(structIndex, 0, i);
1007     COMPARE_DATA(variableCollection()->index(0, 0, ts), "...");
1008     variableCollection()->expanded(ts);
1009     QTest::qWait(100);
1010     COMPARE_DATA(variableCollection()->index(0, 0, ts), "a");
1011     COMPARE_DATA(variableCollection()->index(0, 1, ts), "0");
1012     COMPARE_DATA(variableCollection()->index(1, 0, ts), "b");
1013     COMPARE_DATA(variableCollection()->index(1, 1, ts), "1");
1014     COMPARE_DATA(variableCollection()->index(2, 0, ts), "c");
1015     COMPARE_DATA(variableCollection()->index(2, 1, ts), "2");
1016 
1017     session->stepInto();
1018     WAIT_FOR_STATE(session, DebugSession::PausedState);
1019     QTest::qWait(1000);
1020     COMPARE_DATA(variableCollection()->index(structIndex, 0, i), "ts");
1021     COMPARE_DATA(variableCollection()->index(structIndex, 1, i), "{...}");
1022     COMPARE_DATA(variableCollection()->index(0, 1, ts), "1");
1023 
1024     session->run();
1025     WAIT_FOR_STATE(session, DebugSession::EndedState);
1026 }
1027 
1028 void GdbTest::testVariablesWatches()
1029 {
1030     auto *session = new TestDebugSession;
1031     KDevelop::ICore::self()->debugController()->variableCollection()->variableWidgetShown();
1032 
1033     TestLaunchConfiguration cfg;
1034 
1035     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39);
1036     QVERIFY(session->startDebugging(&cfg, m_iface));
1037     WAIT_FOR_STATE(session, DebugSession::PausedState);
1038 
1039     variableCollection()->watches()->add(QStringLiteral("ts"));
1040     QTest::qWait(300);
1041 
1042     QModelIndex i = variableCollection()->index(0, 0);
1043     QCOMPARE(variableCollection()->rowCount(i), 1);
1044     COMPARE_DATA(variableCollection()->index(0, 0, i), "ts");
1045     COMPARE_DATA(variableCollection()->index(0, 1, i), "{...}");
1046     QModelIndex ts = variableCollection()->index(0, 0, i);
1047     COMPARE_DATA(variableCollection()->index(0, 0, ts), "...");
1048     variableCollection()->expanded(ts);
1049     QTest::qWait(100);
1050     COMPARE_DATA(variableCollection()->index(0, 0, ts), "a");
1051     COMPARE_DATA(variableCollection()->index(0, 1, ts), "0");
1052     COMPARE_DATA(variableCollection()->index(1, 0, ts), "b");
1053     COMPARE_DATA(variableCollection()->index(1, 1, ts), "1");
1054     COMPARE_DATA(variableCollection()->index(2, 0, ts), "c");
1055     COMPARE_DATA(variableCollection()->index(2, 1, ts), "2");
1056 
1057     session->stepInto();
1058     WAIT_FOR_STATE(session, DebugSession::PausedState);
1059     QTest::qWait(100);
1060     COMPARE_DATA(variableCollection()->index(0, 0, i), "ts");
1061     COMPARE_DATA(variableCollection()->index(0, 1, i), "{...}");
1062     COMPARE_DATA(variableCollection()->index(0, 1, ts), "1");
1063 
1064     session->run();
1065     WAIT_FOR_STATE(session, DebugSession::EndedState);
1066 }
1067 
1068 void GdbTest::testVariablesWatchesQuotes()
1069 {
1070     auto *session = new TestDebugSession;
1071     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches);
1072 
1073     TestLaunchConfiguration cfg;
1074 
1075     // the unquoted string (the actual content):               t\"t
1076     // quoted string (what we would write as a c string):     "t\\\"t"
1077     // written in source file:                             R"("t\\\"t")"
1078     const QString testString(QStringLiteral("t\\\"t")); // the actual content
1079     const QString quotedTestString(QStringLiteral(R"("t\\\"t")"));
1080 
1081     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
1082     QVERIFY(session->startDebugging(&cfg, m_iface));
1083     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1084 
1085     variableCollection()->watches()->add(quotedTestString); //just a constant string
1086     QTest::qWait(300);
1087 
1088     QModelIndex i = variableCollection()->index(0, 0);
1089     QCOMPARE(variableCollection()->rowCount(i), 1);
1090     COMPARE_DATA(variableCollection()->index(0, 0, i), quotedTestString);
1091     COMPARE_DATA(variableCollection()->index(0, 1, i), "[" + QString::number(testString.length() + 1) + "]");
1092 
1093     QModelIndex testStr = variableCollection()->index(0, 0, i);
1094     COMPARE_DATA(variableCollection()->index(0, 0, testStr), "...");
1095     variableCollection()->expanded(testStr);
1096     QTest::qWait(100);
1097     int len = testString.length();
1098     for (int ind = 0; ind < len; ind++)
1099     {
1100         COMPARE_DATA(variableCollection()->index(ind, 0, testStr), QString::number(ind));
1101         QChar c = testString.at(ind);
1102         QString value = QString::number(c.toLatin1()) + " '";
1103         if (c == '\\')
1104             value += QLatin1String("\\\\");
1105         else if (c == '\'')
1106             value += QLatin1String("\\'");
1107         else
1108             value += c;
1109         value += QLatin1String("'");
1110         COMPARE_DATA(variableCollection()->index(ind, 1, testStr), value);
1111     }
1112     COMPARE_DATA(variableCollection()->index(len, 0, testStr), QString::number(len));
1113     COMPARE_DATA(variableCollection()->index(len, 1, testStr), "0 '\\000'");
1114 
1115     session->run();
1116     WAIT_FOR_STATE(session, DebugSession::EndedState);
1117 }
1118 
1119 void GdbTest::testVariablesWatchesTwoSessions()
1120 {
1121     auto *session = new TestDebugSession;
1122     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches);
1123 
1124     TestLaunchConfiguration cfg;
1125 
1126     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
1127     QVERIFY(session->startDebugging(&cfg, m_iface));
1128     WAIT_FOR_STATE(session, DebugSession::PausedState);
1129 
1130     variableCollection()->watches()->add(QStringLiteral("ts"));
1131     QTest::qWait(300);
1132 
1133     QModelIndex ts = variableCollection()->index(0, 0, variableCollection()->index(0, 0));
1134     variableCollection()->expanded(ts);
1135     QTest::qWait(100);
1136     session->run();
1137     WAIT_FOR_STATE(session, DebugSession::EndedState);
1138 
1139     //check if variable is marked as out-of-scope
1140     QCOMPARE(variableCollection()->watches()->childCount(), 1);
1141     auto* v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0));
1142     QVERIFY(v);
1143     QVERIFY(!v->inScope());
1144     QCOMPARE(v->childCount(), 3);
1145     v = qobject_cast<KDevelop::Variable*>(v->child(0));
1146     QVERIFY(!v->inScope());
1147 
1148     //start a second debug session
1149     session = new TestDebugSession;
1150     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches);
1151     QVERIFY(session->startDebugging(&cfg, m_iface));
1152     WAIT_FOR_STATE(session, DebugSession::PausedState);
1153     QTest::qWait(300);
1154 
1155     QCOMPARE(variableCollection()->watches()->childCount(), 1);
1156     ts = variableCollection()->index(0, 0, variableCollection()->index(0, 0));
1157     v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0));
1158     QVERIFY(v);
1159     QVERIFY(v->inScope());
1160     QCOMPARE(v->childCount(), 3);
1161 
1162     v = qobject_cast<KDevelop::Variable*>(v->child(0));
1163     QVERIFY(v->inScope());
1164     QCOMPARE(v->data(1, Qt::DisplayRole).toString(), QString::number(0));
1165 
1166     session->run();
1167     WAIT_FOR_STATE(session, DebugSession::EndedState);
1168 
1169     //check if variable is marked as out-of-scope
1170     v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0));
1171     QVERIFY(!v->inScope());
1172     QVERIFY(!dynamic_cast<KDevelop::Variable*>(v->child(0))->inScope());
1173 }
1174 
1175 void GdbTest::testVariablesStopDebugger()
1176 {
1177     auto *session = new TestDebugSession;
1178     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1179 
1180     TestLaunchConfiguration cfg;
1181 
1182     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
1183     QVERIFY(session->startDebugging(&cfg, m_iface));
1184     WAIT_FOR_STATE(session, DebugSession::PausedState);
1185 
1186     session->stopDebugger();
1187     QTest::qWait(300);
1188 }
1189 
1190 
1191 void GdbTest::testVariablesStartSecondSession()
1192 {
1193     QPointer<TestDebugSession> session = new TestDebugSession;
1194     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1195 
1196     TestLaunchConfiguration cfg;
1197 
1198     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
1199     QVERIFY(session->startDebugging(&cfg, m_iface));
1200     WAIT_FOR_STATE(session, DebugSession::PausedState);
1201 
1202     QPointer<TestDebugSession> session2 = new TestDebugSession;
1203     session2->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1204 
1205     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
1206     QVERIFY(session2->startDebugging(&cfg, m_iface));
1207     WAIT_FOR_STATE(session2, DebugSession::PausedState);
1208 
1209     session2->run();
1210     WAIT_FOR_STATE(session2, DebugSession::EndedState);
1211 }
1212 
1213 void GdbTest::testVariablesSwitchFrame()
1214 {
1215     auto *session = new TestDebugSession;
1216     TestLaunchConfiguration cfg;
1217 
1218     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1219     TestFrameStackModel *stackModel = session->frameStackModel();
1220 
1221     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
1222     QVERIFY(session->startDebugging(&cfg, m_iface));
1223     WAIT_FOR_STATE(session, DebugSession::PausedState);
1224     QTest::qWait(500);
1225 
1226     QModelIndex i = variableCollection()->index(1, 0);
1227     COMPARE_DATA(i, "Locals");
1228     QCOMPARE(variableCollection()->rowCount(i), 2);
1229     COMPARE_DATA(variableCollection()->index(0, 0, i), "i");
1230     COMPARE_DATA(variableCollection()->index(0, 1, i), "1");
1231     COMPARE_DATA(variableCollection()->index(1, 0, i), "j");
1232 
1233     stackModel->setCurrentFrame(1);
1234     QTest::qWait(200);
1235 
1236     i = variableCollection()->index(1, 0);
1237     QCOMPARE(variableCollection()->rowCount(i), 4);
1238     COMPARE_DATA(variableCollection()->index(2, 0, i), "argc");
1239     COMPARE_DATA(variableCollection()->index(2, 1, i), "1");
1240     COMPARE_DATA(variableCollection()->index(3, 0, i), "argv");
1241 
1242     breakpoints()->removeRow(0);
1243     session->run();
1244     WAIT_FOR_STATE(session, DebugSession::EndedState);
1245 }
1246 
1247 void GdbTest::testVariablesQuicklySwitchFrame()
1248 {
1249     auto *session = new TestDebugSession;
1250     TestLaunchConfiguration cfg;
1251 
1252     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1253     TestFrameStackModel *stackModel = session->frameStackModel();
1254 
1255     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
1256     QVERIFY(session->startDebugging(&cfg, m_iface));
1257     WAIT_FOR_STATE(session, DebugSession::PausedState);
1258     QTest::qWait(500);
1259 
1260     QModelIndex i = variableCollection()->index(1, 0);
1261     COMPARE_DATA(i, "Locals");
1262     QCOMPARE(variableCollection()->rowCount(i), 2);
1263     COMPARE_DATA(variableCollection()->index(0, 0, i), "i");
1264     COMPARE_DATA(variableCollection()->index(0, 1, i), "1");
1265     COMPARE_DATA(variableCollection()->index(1, 0, i), "j");
1266 
1267     stackModel->setCurrentFrame(1);
1268     QTest::qWait(300);
1269     stackModel->setCurrentFrame(0);
1270     QTest::qWait(1);
1271     stackModel->setCurrentFrame(1);
1272     QTest::qWait(1);
1273     stackModel->setCurrentFrame(0);
1274     QTest::qWait(1);
1275     stackModel->setCurrentFrame(1);
1276     QTest::qWait(500);
1277 
1278     i = variableCollection()->index(1, 0);
1279     QCOMPARE(variableCollection()->rowCount(i), 4);
1280     QStringList locs;
1281     for (int j = 0; j < variableCollection()->rowCount(i); ++j) {
1282         locs << variableCollection()->index(j, 0, i).data().toString();
1283     }
1284     QVERIFY(locs.contains("argc"));
1285     QVERIFY(locs.contains("argv"));
1286     QVERIFY(locs.contains("x"));
1287 
1288     breakpoints()->removeRow(0);
1289     session->run();
1290     WAIT_FOR_STATE(session, DebugSession::EndedState);
1291 }
1292 
1293 
1294 void GdbTest::testSegfaultDebugee()
1295 {
1296     auto *session = new TestDebugSession;
1297     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1298     TestLaunchConfiguration cfg(QStringLiteral("debuggee_crash"));
1299     QString fileName = findSourceFile(QStringLiteral("debugeecrash.cpp"));
1300 
1301     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 23);
1302 
1303     QVERIFY(session->startDebugging(&cfg, m_iface));
1304 
1305     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1306     QCOMPARE(session->line(), 23);
1307     session->run();
1308 
1309     WAIT_FOR_STATE(session, DebugSession::PausedState);
1310     QCOMPARE(session->line(), 24);
1311 
1312     session->stopDebugger();
1313     WAIT_FOR_STATE(session, DebugSession::EndedState);
1314 }
1315 
1316 void GdbTest::testSwitchFrameGdbConsole()
1317 {
1318     auto *session = new TestDebugSession;
1319 
1320     TestLaunchConfiguration cfg;
1321 
1322     TestFrameStackModel *stackModel = session->frameStackModel();
1323 
1324     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24);
1325     QVERIFY(session->startDebugging(&cfg, m_iface));
1326     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1327     QCOMPARE(stackModel->currentFrame(), 0);
1328     stackModel->setCurrentFrame(1);
1329     QCOMPARE(stackModel->currentFrame(), 1);
1330     QTest::qWait(500);
1331     QCOMPARE(stackModel->currentFrame(), 1);
1332 
1333     session->addUserCommand(QStringLiteral("print x"));
1334     QTest::qWait(500);
1335     //currentFrame must not reset to 0; Bug 222882
1336     QCOMPARE(stackModel->currentFrame(), 1);
1337 
1338 }
1339 
1340 //Bug 201771
1341 void GdbTest::testInsertAndRemoveBreakpointWhileRunning()
1342 {
1343 #ifdef Q_OS_FREEBSD
1344     QSKIP("apparently this test doesn't work on FreeBSD");
1345 #endif
1346 
1347     auto *session = new TestDebugSession;
1348     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow"));
1349     QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp"));
1350 
1351     session->startDebugging(&cfg, m_iface);
1352 
1353     WAIT_FOR_STATE(session, DebugSession::ActiveState);
1354     QTest::qWait(2000);
1355     qDebug() << "adding breakpoint";
1356     KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 30); // ++i;
1357     breakpoints()->removeBreakpoint(b);
1358     WAIT_FOR_STATE(session, DebugSession::EndedState);
1359 }
1360 
1361 //Bug 274390
1362 void GdbTest::testCommandOrderFastStepping()
1363 {
1364     auto *session = new TestDebugSession;
1365 
1366     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeqt"));
1367 
1368     breakpoints()->addCodeBreakpoint(QStringLiteral("main"));
1369     QVERIFY(session->startDebugging(&cfg, m_iface));
1370     for(int i=0; i<20; i++) {
1371         session->stepInto();
1372     }
1373     WAIT_FOR_STATE(session, DebugSession::PausedState);
1374     session->run();
1375     WAIT_FOR_STATE(session, DebugSession::EndedState);
1376 }
1377 
1378 void GdbTest::testPickupManuallyInsertedBreakpoint()
1379 {
1380     auto *session = new TestDebugSession;
1381 
1382     TestLaunchConfiguration cfg;
1383 
1384     breakpoints()->addCodeBreakpoint(QStringLiteral("main"));
1385     QVERIFY(session->startDebugging(&cfg, m_iface));
1386     session->addCommand(MI::NonMI, QStringLiteral("break debugee.cpp:33"));
1387     session->stepInto();
1388     WAIT_FOR_STATE(session, DebugSession::PausedState);
1389     QTest::qWait(1000); //wait for breakpoints update
1390     QCOMPARE(breakpoints()->breakpoints().count(), 2);
1391     QCOMPARE(breakpoints()->rowCount(), 2);
1392     KDevelop::Breakpoint *b = breakpoints()->breakpoint(1);
1393     QVERIFY(b);
1394     QCOMPARE(b->line(), 32); //we start with 0, gdb with 1
1395     QCOMPARE(b->url().fileName(), QString("debugee.cpp"));
1396 }
1397 
1398 //Bug 270970
1399 void GdbTest::testPickupManuallyInsertedBreakpointOnlyOnce()
1400 {
1401     auto *session = new TestDebugSession;
1402 
1403     //inject here, so it behaves similar like a command from .gdbinit
1404     QTemporaryFile configScript;
1405     configScript.open();
1406     configScript.write(QStringLiteral("file %0\n").arg(findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile()).toLocal8Bit());
1407     configScript.write("break debugee.cpp:32\n");
1408     configScript.close();
1409 
1410     TestLaunchConfiguration cfg;
1411     KConfigGroup grp = cfg.config();
1412     grp.writeEntry(Config::RemoteGdbConfigEntry, QUrl::fromLocalFile(configScript.fileName()));
1413 
1414     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(QStringLiteral("debugee.cpp")), 31);
1415     QVERIFY(session->startDebugging(&cfg, m_iface));
1416 
1417     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1418     QCOMPARE(breakpoints()->breakpoints().count(), 1);
1419 
1420     session->run();
1421     WAIT_FOR_STATE(session, DebugSession::EndedState);
1422 }
1423 
1424 void GdbTest::testPickupCatchThrowOnlyOnce()
1425 {
1426     QTemporaryFile configScript;
1427     configScript.open();
1428     configScript.write("catch throw\n");
1429     configScript.close();
1430 
1431     TestLaunchConfiguration cfg;
1432     KConfigGroup grp = cfg.config();
1433     grp.writeEntry(Config::RemoteGdbConfigEntry, QUrl::fromLocalFile(configScript.fileName()));
1434 
1435 
1436     for (int i = 0; i < 2; ++i) {
1437         auto* session = new TestDebugSession;
1438         QVERIFY(session->startDebugging(&cfg, m_iface));
1439         WAIT_FOR_STATE(session, DebugSession::EndedState);
1440     }
1441 
1442     QTRY_COMPARE(breakpoints()->rowCount(), 1); //one from kdevelop, one from runScript
1443 }
1444 
1445 void GdbTest::testRunGdbScript()
1446 {
1447     auto *session = new TestDebugSession;
1448 
1449     QTemporaryFile runScript;
1450     runScript.open();
1451 
1452     runScript.write("file " + KShell::quoteArg(findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile()).toUtf8() + "\n");
1453     runScript.write("break main\n");
1454     runScript.write("run\n");
1455     runScript.close();
1456 
1457     TestLaunchConfiguration cfg;
1458     KConfigGroup grp = cfg.config();
1459     grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName()));
1460 
1461     QVERIFY(session->startDebugging(&cfg, m_iface));
1462 
1463     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1464 
1465     QCOMPARE(session->line(), 28);
1466 
1467     session->run();
1468     WAIT_FOR_STATE(session, DebugSession::EndedState);
1469 }
1470 
1471 void GdbTest::testRemoteDebug()
1472 {
1473     const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver"));
1474     if (gdbserverExecutable.isEmpty()) {
1475         QSKIP("Skipping, gdbserver not available");
1476     }
1477 
1478     auto *session = new TestDebugSession;
1479 
1480     QTemporaryFile shellScript(QDir::currentPath()+"/shellscript");
1481     shellScript.open();
1482     shellScript.write("gdbserver localhost:2345 " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n");
1483     shellScript.close();
1484     shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser);
1485     QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?)
1486 
1487     QTemporaryFile runScript(QDir::currentPath()+"/runscript");
1488     runScript.open();
1489     runScript.write("file " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n");
1490     runScript.write("target remote localhost:2345\n");
1491     runScript.write("break debugee.cpp:30\n");
1492     runScript.write("continue\n");
1493     runScript.close();
1494 
1495     TestLaunchConfiguration cfg;
1496     KConfigGroup grp = cfg.config();
1497     grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile((shellScript.fileName()+"-copy")));
1498     grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName()));
1499 
1500     QVERIFY(session->startDebugging(&cfg, m_iface));
1501 
1502     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1503 
1504     QCOMPARE(session->line(), 29);
1505 
1506     session->run();
1507     WAIT_FOR_STATE(session, DebugSession::EndedState);
1508 
1509     QFile::remove(shellScript.fileName()+"-copy");
1510 }
1511 
1512 void GdbTest::testRemoteDebugInsertBreakpoint()
1513 {
1514     const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver"));
1515     if (gdbserverExecutable.isEmpty()) {
1516         QSKIP("Skipping, gdbserver not available");
1517     }
1518 
1519     auto *session = new TestDebugSession;
1520 
1521     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29);
1522     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 35);
1523 
1524     QTemporaryFile shellScript(QDir::currentPath()+"/shellscript");
1525     shellScript.open();
1526     shellScript.write("gdbserver localhost:2345 " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n");
1527     shellScript.close();
1528     shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser);
1529     QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?)
1530 
1531     QTemporaryFile runScript(QDir::currentPath()+"/runscript");
1532     runScript.open();
1533     runScript.write("file " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + '\n');
1534     runScript.write("target remote localhost:2345\n");
1535     runScript.write("break debugee.cpp:30\n");
1536     runScript.write("continue\n");
1537     runScript.close();
1538 
1539     TestLaunchConfiguration cfg;
1540     KConfigGroup grp = cfg.config();
1541     grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile(shellScript.fileName()+"-copy"));
1542     grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName()));
1543 
1544     QVERIFY(session->startDebugging(&cfg, m_iface));
1545 
1546     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1547 
1548     QCOMPARE(session->line(), 29);
1549 
1550     QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript
1551 
1552     session->run();
1553     WAIT_FOR_STATE(session, DebugSession::PausedState);
1554 
1555     QCOMPARE(session->line(), 36);
1556 
1557     session->run();
1558     WAIT_FOR_STATE(session, DebugSession::EndedState);
1559 
1560     QFile::remove(shellScript.fileName()+"-copy");
1561 }
1562 
1563 
1564 void GdbTest::testRemoteDebugInsertBreakpointPickupOnlyOnce()
1565 {
1566     const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver"));
1567     if (gdbserverExecutable.isEmpty()) {
1568         QSKIP("Skipping, gdbserver not available");
1569     }
1570 
1571     auto *session = new TestDebugSession;
1572 
1573     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 36);
1574 
1575     QTemporaryFile shellScript(QDir::currentPath()+"/shellscript");
1576     shellScript.open();
1577     shellScript.write("gdbserver localhost:2345 "+findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toLatin1()+"\n");
1578     shellScript.close();
1579     shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser);
1580     QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?)
1581 
1582     QTemporaryFile runScript(QDir::currentPath()+"/runscript");
1583     runScript.open();
1584     runScript.write("file "+findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toLatin1()+"\n");
1585     runScript.write("target remote localhost:2345\n");
1586     runScript.write("break debugee.cpp:31\n");
1587     runScript.write("continue\n");
1588     runScript.close();
1589 
1590     TestLaunchConfiguration cfg;
1591     KConfigGroup grp = cfg.config();
1592     grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile((shellScript.fileName()+"-copy")));
1593     grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName()));
1594 
1595     QVERIFY(session->startDebugging(&cfg, m_iface));
1596 
1597     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1598 
1599     QCOMPARE(session->line(), 30);
1600 
1601     QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript
1602 
1603     session->run();
1604     WAIT_FOR_STATE(session, DebugSession::PausedState);
1605 
1606     QCOMPARE(session->line(), 36);
1607 
1608     session->run();
1609     WAIT_FOR_STATE(session, DebugSession::EndedState);
1610 
1611     //************************** second session
1612     session = new TestDebugSession;
1613     QVERIFY(session->startDebugging(&cfg, m_iface));
1614 
1615     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1616 
1617     QCOMPARE(session->line(), 30);
1618 
1619     QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript
1620 
1621     session->run();
1622     WAIT_FOR_STATE(session, DebugSession::PausedState);
1623 
1624     QCOMPARE(session->line(), 36);
1625 
1626     session->run();
1627     WAIT_FOR_STATE(session, DebugSession::EndedState);
1628 
1629     QFile::remove(shellScript.fileName()+"-copy");
1630 }
1631 
1632 void GdbTest::testBreakpointWithSpaceInPath()
1633 {
1634     auto *session = new TestDebugSession;
1635 
1636     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeespace"));
1637     KConfigGroup grp = cfg.config();
1638     QString fileName = findSourceFile(QStringLiteral("debugee space.cpp"));
1639 
1640     KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 20);
1641     QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState);
1642 
1643     session->startDebugging(&cfg, m_iface);
1644     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1645     QCOMPARE(session->line(), 20);
1646     session->run();
1647     WAIT_FOR_STATE(session, DebugSession::EndedState);
1648 }
1649 
1650 void GdbTest::testBreakpointDisabledOnStart()
1651 {
1652     auto *session = new TestDebugSession;
1653 
1654     TestLaunchConfiguration cfg;
1655 
1656     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28)
1657         ->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
1658     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29);
1659     KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 31);
1660     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
1661 
1662     session->startDebugging(&cfg, m_iface);
1663     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1664     QCOMPARE(session->line(), 29);
1665     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Checked);
1666     session->run();
1667     WAIT_FOR_STATE(session, DebugSession::PausedState);
1668     QCOMPARE(session->line(), 32);
1669     session->run();
1670     WAIT_FOR_STATE(session, DebugSession::EndedState);
1671 }
1672 
1673 void GdbTest::testCatchpoint()
1674 {
1675     auto *session = new TestDebugSession;
1676     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
1677 
1678     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeexception"));
1679 
1680     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile(QStringLiteral("debugeeexception.cpp"))), 29);
1681 
1682     session->startDebugging(&cfg, m_iface);
1683     WAIT_FOR_STATE(session, DebugSession::PausedState);
1684     QTest::qWait(1000);
1685     TestFrameStackModel* fsModel = session->frameStackModel();
1686     QCOMPARE(fsModel->currentFrame(), 0);
1687     QCOMPARE(session->line(), 29);
1688 
1689     session->addCommand(MI::NonMI, QStringLiteral("catch throw"));
1690     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1691     session->run();
1692     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1693     QTest::qWait(1000);
1694 
1695     const QVector<KDevelop::FrameStackModel::FrameItem> frames = fsModel->frames(fsModel->currentThread());
1696     QVERIFY(frames.size() >= 2);
1697     // frame 0 is somewhere inside libstdc++
1698     QCOMPARE(frames[1].file, QUrl::fromLocalFile(findSourceFile("debugeeexception.cpp")));
1699     QCOMPARE(frames[1].line, 22);
1700 
1701     QCOMPARE(breakpoints()->rowCount(),2);
1702     QVERIFY(!breakpoints()->breakpoint(0)->location().isEmpty());
1703     QVERIFY(!breakpoints()->breakpoint(1)->location().isEmpty());
1704 
1705     session->run();
1706     WAIT_FOR_STATE(session, DebugSession::EndedState);
1707 }
1708 
1709 void GdbTest::testThreadAndFrameInfo()
1710 {
1711     // Check if --thread is added to user commands
1712 
1713     auto *session = new TestDebugSession;
1714     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeethreads"));
1715     QString fileName = findSourceFile(QStringLiteral("debugeethreads.cpp"));
1716 
1717     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 38);
1718     QVERIFY(session->startDebugging(&cfg, m_iface));
1719     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1720 
1721     QSignalSpy outputSpy(session, &TestDebugSession::debuggerUserCommandOutput);
1722 
1723     session->addCommand(std::make_unique<MI::UserCommand>(MI::ThreadInfo, QString()));
1724     session->addCommand(std::make_unique<MI::UserCommand>(MI::StackListLocals, QStringLiteral("0")));
1725     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // wait for command finish
1726 
1727     // outputs should be
1728     // 1. -thread-info
1729     // 2. ^done for thread-info
1730     // 3. -stack-list-locals
1731     // 4. ^done for -stack-list-locals
1732     QCOMPARE(outputSpy.count(), 4);
1733     QVERIFY(outputSpy.at(2).at(0).toString().contains(QLatin1String("--thread 1")));
1734 
1735     session->run();
1736     WAIT_FOR_STATE(session, DebugSession::EndedState);
1737 }
1738 
1739 void GdbTest::parseBug304730()
1740 {
1741     MI::FileSymbol file;
1742     file.contents = QByteArray("^done,bkpt={"
1743         "number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"<MULTIPLE>\",times=\"0\","
1744         "original-location=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp:231\"},"
1745         "{number=\"1.1\",enabled=\"y\",addr=\"0x081d84aa\","
1746         "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >"
1747         "::Propagation<ForwardPropagationNeighbors>(ForwardPropagationNeighbors)\","
1748         "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\","
1749         "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"},"
1750         "{number=\"1.2\",enabled=\"y\",addr=\"0x081d8ae2\","
1751         "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >"
1752         "::Propagation<BackwardPropagationNeighbors>(BackwardPropagationNeighbors)\","
1753         "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\","
1754         "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"},"
1755         "{number=\"1.3\",enabled=\"y\",addr=\"0x081d911a\","
1756         "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >"
1757         "::Propagation<AllowedPropagationNeighbors>(AllowedPropagationNeighbors)\","
1758         "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\","
1759         "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"}");
1760 
1761     MI::MIParser parser;
1762 
1763     std::unique_ptr<MI::Record> record(parser.parse(&file));
1764     QVERIFY(record.get() != nullptr);
1765 }
1766 
1767 void GdbTest::testMultipleLocationsBreakpoint()
1768 {
1769     auto *session = new TestDebugSession;
1770 
1771     TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeemultilocbreakpoint"));
1772 
1773     breakpoints()->addCodeBreakpoint(QStringLiteral("aPlusB"));
1774 
1775     //TODO check if the additional location breakpoint is added
1776 
1777     session->startDebugging(&cfg, m_iface);
1778     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1779     QCOMPARE(session->line(), 19);
1780 
1781     session->run();
1782     WAIT_FOR_STATE(session, DebugSession::PausedState);
1783     QCOMPARE(session->line(), 23);
1784 
1785     session->run();
1786     WAIT_FOR_STATE(session, DebugSession::EndedState);
1787 }
1788 
1789 void GdbTest::testBug301287()
1790 {
1791     auto *session = new TestDebugSession;
1792     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches);
1793 
1794     TestLaunchConfiguration cfg;
1795 
1796     breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28);
1797 
1798     session->startDebugging(&cfg, m_iface);
1799     WAIT_FOR_STATE(session, DebugSession::PausedState);
1800 
1801     variableCollection()->watches()->add(QStringLiteral("argc"));
1802     QTest::qWait(300);
1803 
1804     QModelIndex i = variableCollection()->index(0, 0);
1805     QCOMPARE(variableCollection()->rowCount(i), 1);
1806     COMPARE_DATA(variableCollection()->index(0, 0, i), "argc");
1807     COMPARE_DATA(variableCollection()->index(0, 1, i), "1");
1808 
1809     session->run();
1810     WAIT_FOR_STATE(session, DebugSession::EndedState);
1811 
1812     //start second debug session (same cfg)
1813     session = new TestDebugSession;
1814     session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches);
1815 
1816     session->startDebugging(&cfg, m_iface);
1817     WAIT_FOR_STATE(session, DebugSession::PausedState);
1818 
1819     QTest::qWait(300);
1820 
1821     i = variableCollection()->index(0, 0);
1822     QCOMPARE(variableCollection()->rowCount(i), 1);
1823     COMPARE_DATA(variableCollection()->index(0, 0, i), "argc");
1824     COMPARE_DATA(variableCollection()->index(0, 1, i), "1");
1825 
1826     session->run();
1827     WAIT_FOR_STATE(session, DebugSession::EndedState);
1828 }
1829 
1830 void GdbTest::testMultipleBreakpoint()
1831 {
1832         auto *session = new TestDebugSession;
1833 
1834         //there'll be about 3-4 breakpoints, but we treat it like one.
1835         TestLaunchConfiguration c(QStringLiteral("debuggee_debugeemultiplebreakpoint"));
1836         KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QStringLiteral("debugeemultiplebreakpoint.cpp:52"));
1837         session->startDebugging(&c, m_iface);
1838         WAIT_FOR_STATE(session, DebugSession::PausedState);
1839         QCOMPARE(breakpoints()->breakpoints().count(), 1);
1840 
1841         b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
1842         session->run();
1843         WAIT_FOR_STATE(session, DebugSession::EndedState);
1844 }
1845 
1846 void GdbTest::testRegularExpressionBreakpoint()
1847 {
1848         auto *session = new TestDebugSession;
1849 
1850         TestLaunchConfiguration c(QStringLiteral("debuggee_debugeemultilocbreakpoint"));
1851         breakpoints()->addCodeBreakpoint(QStringLiteral("main"));
1852         session->startDebugging(&c, m_iface);
1853         WAIT_FOR_STATE(session, DebugSession::PausedState);
1854         session->addCommand(MI::NonMI, QStringLiteral("rbreak .*aPl.*B"));
1855         QTest::qWait(100);
1856         session->run();
1857         WAIT_FOR_STATE(session, DebugSession::PausedState);
1858         QCOMPARE(breakpoints()->breakpoints().count(), 3);
1859 
1860         session->addCommand(MI::BreakDelete, QString());
1861         session->run();
1862         WAIT_FOR_STATE(session, DebugSession::EndedState);
1863 }
1864 
1865 void GdbTest::testChangeBreakpointWhileRunning()
1866 {
1867 #ifdef Q_OS_FREEBSD
1868     QSKIP("apparently this test doesn't work on FreeBSD");
1869 #endif
1870 
1871     auto *session = new TestDebugSession;
1872 
1873     TestLaunchConfiguration c(QStringLiteral("debuggee_debugeeslow"));
1874     KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QStringLiteral("debugeeslow.cpp:30"));
1875     session->startDebugging(&c, m_iface);
1876 
1877     WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1878     QVERIFY(session->currentLine() >= 29 && session->currentLine() <= 31 );
1879     session->run();
1880     WAIT_FOR_STATE(session, DebugSession::ActiveState);
1881     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
1882     //to make one loop
1883     QTest::qWait(2000);
1884     WAIT_FOR_STATE(session, DebugSession::ActiveState);
1885 
1886     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Checked);
1887     QTest::qWait(100);
1888     WAIT_FOR_STATE(session, DebugSession::PausedState);
1889     b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked);
1890     session->run();
1891     QTest::qWait(100);
1892     WAIT_FOR_STATE(session, DebugSession::EndedState);
1893 }
1894 
1895 void GdbTest::testDebugInExternalTerminal()
1896 {
1897     TestLaunchConfiguration cfg;
1898 
1899     const QStringList consoles { "konsole", "xterm", "xfce4-terminal", "gnome-terminal" };
1900     for (const QString& console : consoles) {
1901 
1902         TestDebugSession* session = nullptr;
1903         if (QStandardPaths::findExecutable(console).isEmpty()) {
1904             continue;
1905         }
1906 
1907         session = new TestDebugSession();
1908 
1909         cfg.config().writeEntry(IExecutePlugin::useTerminalEntry, true);
1910         cfg.config().writeEntry(IExecutePlugin::terminalEntry, console);
1911 
1912         KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28);
1913 
1914         session->startDebugging(&cfg, m_iface);
1915         WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
1916         QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState);
1917         session->stepInto();
1918         WAIT_FOR_STATE(session, DebugSession::PausedState);
1919         session->run();
1920         WAIT_FOR_STATE(session, DebugSession::EndedState);
1921     }
1922 }
1923 
1924 // see: https://bugs.kde.org/show_bug.cgi?id=339231
1925 void GdbTest::testPathWithSpace()
1926 {
1927     auto* session = new TestDebugSession;
1928 
1929     auto debugee = findExecutable(QStringLiteral("path with space/debuggee_spacedebugee"));
1930     TestLaunchConfiguration c(debugee, KIO::upUrl(debugee));
1931     KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QStringLiteral("spacedebugee.cpp:30"));
1932     QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState);
1933     session->startDebugging(&c, m_iface);
1934 
1935     WAIT_FOR_STATE(session, DebugSession::PausedState);
1936     QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState);
1937     session->run();
1938     WAIT_FOR_STATE(session, DebugSession::EndedState);
1939 }
1940 
1941 } // end of namespace GDB
1942 } // end of namespace KDevMI
1943 
1944 QTEST_MAIN(KDevMI::GDB::GdbTest)
1945 
1946 
1947 #include "test_gdb.moc"
1948 #include "moc_test_gdb.cpp"
1949