File indexing completed on 2024-05-12 04:40:08

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