File indexing completed on 2024-05-12 04:40:09
0001 /* 0002 SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "test_lldbformatters.h" 0008 0009 #include "controllers/variable.h" 0010 #include "controllers/variablecontroller.h" 0011 #include "debugsession.h" 0012 #include "stringhelpers.h" 0013 #include "tests/debuggers-tests-config.h" 0014 #include "tests/testhelper.h" 0015 0016 #include <execute/iexecuteplugin.h> 0017 #include <interfaces/icore.h> 0018 #include <interfaces/iplugincontroller.h> 0019 #include <tests/autotestshell.h> 0020 #include <tests/testcore.h> 0021 0022 #include <KConfigGroup> 0023 #include <KSharedConfig> 0024 0025 #include <QDebug> 0026 #include <QString> 0027 #include <QTest> 0028 #include <QUrl> 0029 0030 #include <algorithm> 0031 #include <vector> 0032 0033 #define WAIT_FOR_A_WHILE_AND_IDLE(session, ms) \ 0034 do { if (!KDevMI::waitForAWhile((session), (ms), __FILE__, __LINE__)) return; \ 0035 if (!KDevMI::waitForState((session), DebugSession::PausedState, __FILE__, __LINE__, true)) \ 0036 return; \ 0037 } while (0) 0038 0039 #define VERIFY_LOCAL(row, name, summary, children) \ 0040 do { \ 0041 if (!verifyVariable((row), (name), (summary), (children), __FILE__, __LINE__)) \ 0042 return; \ 0043 } while (0) 0044 0045 #define VERIFY_WATCH(row, name, summary, children) \ 0046 do { \ 0047 if (!verifyVariable((row), (name), (summary), (children), __FILE__, __LINE__, false)) \ 0048 return; \ 0049 } while (0) 0050 0051 using namespace KDevelop; 0052 using namespace KDevMI::LLDB; 0053 using KDevMI::findExecutable; 0054 using KDevMI::findSourceFile; 0055 using KDevMI::findFile; 0056 using KDevMI::compareData; 0057 using KDevMI::TestLaunchConfiguration; 0058 0059 class TestDebugSession : public DebugSession 0060 { 0061 Q_OBJECT 0062 public: 0063 TestDebugSession() : DebugSession() 0064 { 0065 setSourceInitFile(false); 0066 // explicit set formatter path to force use in-tree formatters, not the one installed in system. 0067 auto formatter = findFile(LLDB_SRC_DIR, "formatters/all.py"); 0068 setFormatterPath(formatter); 0069 0070 KDevelop::ICore::self()->debugController()->addSession(this); 0071 0072 variableController()->setAutoUpdate(IVariableController::UpdateLocals); 0073 } 0074 }; 0075 0076 VariableCollection *LldbFormattersTest::variableCollection() 0077 { 0078 return m_core->debugController()->variableCollection(); 0079 } 0080 0081 QModelIndex LldbFormattersTest::watchVariableIndexAt(int i, int col) 0082 { 0083 auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0); 0084 return variableCollection()->index(i, col, watchRoot); 0085 } 0086 0087 QModelIndex LldbFormattersTest::localVariableIndexAt(int i, int col) 0088 { 0089 auto localRoot = variableCollection()->indexForItem(variableCollection()->locals(), 0); 0090 return variableCollection()->index(i, col, localRoot); 0091 } 0092 0093 // Note: line is zero-based 0094 KDevelop::Breakpoint* LldbFormattersTest::addCodeBreakpoint(const QUrl& location, int line) 0095 { 0096 return m_core->debugController()->breakpointModel()->addCodeBreakpoint(location, line); 0097 } 0098 0099 // Called before the first testfunction is executed 0100 void LldbFormattersTest::initTestCase() 0101 { 0102 AutoTestShell::init({QStringLiteral("kdevlldb"), QStringLiteral("kdevexecute")}); 0103 m_core = TestCore::initialize(Core::NoUi); 0104 0105 m_iface = m_core->pluginController() 0106 ->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute")) 0107 ->extension<IExecutePlugin>(); 0108 Q_ASSERT(m_iface); 0109 0110 const QString lldbMiExecutable = QStandardPaths::findExecutable(QStringLiteral("lldb-mi")); 0111 if (lldbMiExecutable.isEmpty()) { 0112 QSKIP("Skipping, lldb-mi not available"); 0113 } 0114 } 0115 0116 // Called after the last testfunction was executed 0117 void LldbFormattersTest::cleanupTestCase() 0118 { 0119 TestCore::shutdown(); 0120 } 0121 0122 // Called before each testfunction is executed 0123 void LldbFormattersTest::init() 0124 { 0125 //remove all breakpoints - so we can set our own in the test 0126 KConfigGroup bpCfg = KSharedConfig::openConfig()->group("breakpoints"); 0127 bpCfg.writeEntry("number", 0); 0128 bpCfg.sync(); 0129 0130 auto count = m_core->debugController()->breakpointModel()->rowCount(); 0131 m_core->debugController()->breakpointModel()->removeRows(0, count); 0132 0133 while (variableCollection()->watches()->childCount() > 0) { 0134 auto idx = watchVariableIndexAt(0); 0135 auto var = qobject_cast<LldbVariable*>(variableCollection()->itemForIndex(idx)); 0136 if (!var) break; 0137 var->die(); 0138 } 0139 0140 m_session = new TestDebugSession; 0141 } 0142 0143 void LldbFormattersTest::cleanup() 0144 { 0145 // Called after every testfunction 0146 if (m_session) 0147 m_session->stopDebugger(); 0148 WAIT_FOR_STATE(m_session, DebugSession::EndedState); 0149 m_session.clear(); 0150 } 0151 0152 bool LldbFormattersTest::verifyVariable(int index, const QString &name, 0153 const QString &expectedSummary, 0154 QStringList expectedChildren, 0155 const char *file, int line, 0156 bool isLocal, bool useRE, bool unordered) 0157 { 0158 QList<QPair<QString, QString>> childrenPairs; 0159 childrenPairs.reserve(expectedChildren.size()); 0160 if (unordered) { 0161 qDebug() << "useRE set to true when unordered = true"; 0162 useRE = true; 0163 expectedChildren.sort(); 0164 for (auto& c : expectedChildren) { 0165 childrenPairs << qMakePair(QStringLiteral(R"(^\[\d+\]$)"), c); 0166 } 0167 } else { 0168 for (int i = 0; i != expectedChildren.size(); ++i) { 0169 childrenPairs << qMakePair(QStringLiteral("[%0]").arg(i), expectedChildren[i]); 0170 } 0171 } 0172 return verifyVariable(index, name, expectedSummary, childrenPairs, file, line, isLocal, useRE, unordered); 0173 } 0174 0175 bool LldbFormattersTest::verifyVariable(int index, const QString &name, 0176 const QString &expectedSummary, 0177 QList<QPair<QString, QString>> expectedChildren, 0178 const char *file, int line, 0179 bool isLocal, bool useRE, bool unordered) 0180 { 0181 QModelIndex varIdx, summaryIdx; 0182 if (isLocal) { 0183 varIdx = localVariableIndexAt(index, 0); 0184 summaryIdx = localVariableIndexAt(index, 1); 0185 } else { 0186 varIdx = watchVariableIndexAt(index, 0); 0187 summaryIdx = watchVariableIndexAt(index, 1); 0188 } 0189 0190 if (!compareData(varIdx, name, file, line)) { 0191 return false; 0192 } 0193 if (!compareData(summaryIdx, expectedSummary, file, line, useRE)) { 0194 return false; 0195 } 0196 0197 // fetch all children 0198 auto var = variableCollection()->itemForIndex(varIdx); 0199 auto childCount = 0; 0200 while (childCount != variableCollection()->rowCount(varIdx)) { 0201 childCount = variableCollection()->rowCount(varIdx); 0202 var->fetchMoreChildren(); 0203 if (!waitForAWhile(m_session, 50, file, line)) 0204 return false; 0205 } 0206 if (childCount != expectedChildren.length()) { 0207 QTest::qFail(qPrintable(QString("'%0' didn't match expected '%1' in %2:%3") 0208 .arg(childCount).arg(expectedChildren.length()).arg(file).arg(line)), 0209 file, line); 0210 return false; 0211 } 0212 0213 QVector<int> theOrder; 0214 theOrder.reserve(childCount); 0215 for (int i = 0; i != childCount; ++i) { 0216 theOrder.push_back(i); 0217 } 0218 if (unordered) { 0219 qDebug() << "actual list sorted for unordered compare"; 0220 std::sort(theOrder.begin(), theOrder.end(), [&](int a, int b){ 0221 auto indexA = variableCollection()->index(a, 1, varIdx); 0222 auto indexB = variableCollection()->index(b, 1, varIdx); 0223 return indexA.model()->data(indexA, Qt::DisplayRole).toString() 0224 < indexB.model()->data(indexB, Qt::DisplayRole).toString(); 0225 }); 0226 std::sort(expectedChildren.begin(), expectedChildren.end(), 0227 [](const QPair<QString, QString> &a, const QPair<QString, QString> &b){ 0228 return a.second < b.second; 0229 }); 0230 qDebug() << "sorted actual order" << theOrder; 0231 qDebug() << "sorted expectedChildren" << expectedChildren; 0232 } 0233 0234 for (int i = 0; i != childCount; ++i) { 0235 if (!compareData(variableCollection()->index(theOrder[i], 0, varIdx), 0236 expectedChildren[i].first, file, line, useRE)) { 0237 return false; 0238 } 0239 0240 if (!compareData(variableCollection()->index(theOrder[i], 1, varIdx), 0241 expectedChildren[i].second, file, line, useRE)) { 0242 return false; 0243 } 0244 } 0245 return true; 0246 } 0247 0248 void LldbFormattersTest::testQChar() 0249 { 0250 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qchar")); 0251 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qchar.cpp")), 4); 0252 0253 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0254 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0255 0256 // Should be two rows ('auto', 'local') 0257 QCOMPARE(variableCollection()->rowCount(), 2); 0258 0259 variableCollection()->expanded(localVariableIndexAt(0)); 0260 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0261 0262 QList<QPair<QString, QString>> children; 0263 children << qMakePair(QStringLiteral("ucs"), QStringLiteral("107")); 0264 0265 VERIFY_LOCAL(0, "c", "'k'", children); 0266 } 0267 0268 void LldbFormattersTest::testQString() 0269 { 0270 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qstring")); 0271 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qstring.cpp")), 4); 0272 0273 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0274 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0275 0276 // Should be two rows ('auto', 'local') 0277 QCOMPARE(variableCollection()->rowCount(), 2); 0278 0279 variableCollection()->expanded(localVariableIndexAt(0)); 0280 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0281 0282 QString expected = QStringLiteral("test最后一个不是特殊字符'\"\\u6211"); 0283 QStringList children; 0284 for (auto ch : qAsConst(expected)) { 0285 children << Utils::quote(ch, '\''); 0286 } 0287 0288 VERIFY_LOCAL(0, "s", Utils::quote(expected), children); 0289 0290 m_session->stepOver(); 0291 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0292 QCOMPARE(m_session->currentLine(), 5); 0293 0294 expected.append("x"); 0295 children << QStringLiteral("'x'"); 0296 0297 VERIFY_LOCAL(0, "s", Utils::quote(expected), children); 0298 0299 m_session->run(); 0300 WAIT_FOR_STATE(m_session, DebugSession::EndedState); 0301 } 0302 0303 void LldbFormattersTest::testQByteArray() 0304 { 0305 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qbytearray")); 0306 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qbytearray.cpp")), 4); 0307 0308 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0309 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0310 0311 // Should be two rows ('auto', 'local') 0312 QCOMPARE(variableCollection()->rowCount(), 2); 0313 0314 variableCollection()->expanded(localVariableIndexAt(0)); 0315 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0316 0317 QStringList charlist { 0318 R"(-26 '\xe6')", 0319 R"(-104 '\x98')", 0320 R"(-81 '\xaf')", 0321 R"(39 ''')", 0322 R"(34 '"')", 0323 R"(92 '\')", 0324 R"(117 'u')", 0325 R"(54 '6')", 0326 R"(50 '2')", 0327 R"(49 '1')", 0328 R"(49 '1')", 0329 }; 0330 0331 VERIFY_LOCAL(0, "ba", R"("\xe6\x98\xaf'\"\\u6211")", charlist); 0332 0333 m_session->stepOver(); 0334 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0335 QCOMPARE(m_session->currentLine(), 5); 0336 0337 charlist << QStringLiteral("120 'x'"); 0338 VERIFY_LOCAL(0, "ba", R"("\xe6\x98\xaf'\"\\u6211x")", charlist); 0339 0340 m_session->run(); 0341 WAIT_FOR_STATE(m_session, DebugSession::EndedState); 0342 } 0343 0344 0345 void LldbFormattersTest::testQListContainer_data() 0346 { 0347 QTest::addColumn<QString>("container"); 0348 QTest::addColumn<bool>("unordered"); 0349 0350 QTest::newRow("QList") << "QList" << false; 0351 QTest::newRow("QQueue") << "QQueue" << false; 0352 QTest::newRow("QVector") << "QVector" << false; 0353 QTest::newRow("QStack") << "QStack" << false; 0354 QTest::newRow("QLinkedList") << "QLinkedList" << false; 0355 QTest::newRow("QSet") << "QSet" << true; 0356 } 0357 0358 void LldbFormattersTest::testQListContainer() 0359 { 0360 QFETCH(QString, container); 0361 QFETCH(bool, unordered); 0362 0363 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qlistcontainer")); 0364 cfg.config().writeEntry(KDevMI::Config::BreakOnStartEntry, true); 0365 0366 auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0); 0367 variableCollection()->expanded(watchRoot); 0368 variableCollection()->variableWidgetShown(); 0369 0370 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0371 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0372 0373 m_session->addUserCommand(QStringLiteral("break set --func doStuff<%1>()").arg(container)); 0374 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0375 0376 m_session->run(); 0377 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0378 0379 // <int> 0380 m_session->stepOver(); 0381 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0382 QCOMPARE(m_session->currentLine(), 33); // line 34: intList << 10 << 20; 0383 0384 auto var = variableCollection()->watches()->add(QStringLiteral("intList")); 0385 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0386 0387 if (!verifyVariable(0, QStringLiteral("intList"), QStringLiteral("<size=0>"), QStringList{}, 0388 __FILE__, __LINE__, false, false, unordered)) { 0389 return; 0390 } 0391 0392 m_session->stepOver(); 0393 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0394 QCOMPARE(m_session->currentLine(), 34); // line 35: intList << 30; 0395 0396 variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update. 0397 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0398 0399 if (!verifyVariable(0, QStringLiteral("intList"), QStringLiteral("<size=2>"), QStringList{"10", "20"}, 0400 __FILE__, __LINE__, false, false, unordered)) { 0401 return; 0402 } 0403 0404 m_session->stepOver(); 0405 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0406 QCOMPARE(m_session->currentLine(), 36); // line 37: Container<QString> stringList; 0407 0408 if (!verifyVariable(0, QStringLiteral("intList"), QStringLiteral("<size=3>"), QStringList{"10", "20", "30"}, 0409 __FILE__, __LINE__, false, false, unordered)) { 0410 return; 0411 } 0412 var->die(); 0413 0414 // <QString> 0415 m_session->stepOver(); 0416 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0417 QCOMPARE(m_session->currentLine(), 37); // line 38: stringList << "a" << "bc"; 0418 0419 var = variableCollection()->watches()->add(QStringLiteral("stringList")); 0420 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0421 0422 if (!verifyVariable(0, QStringLiteral("stringList"), QStringLiteral("<size=0>"), QStringList{}, 0423 __FILE__, __LINE__, false, false, unordered)) { 0424 return; 0425 } 0426 0427 m_session->stepOver(); 0428 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0429 QCOMPARE(m_session->currentLine(), 38); // line 39: stringList << "d"; 0430 0431 variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update. 0432 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0433 0434 0435 if (!verifyVariable(0, QStringLiteral("stringList"), QStringLiteral("<size=2>"), QStringList{"\"a\"", "\"bc\""}, 0436 __FILE__, __LINE__, false, false, unordered)) { 0437 return; 0438 } 0439 0440 m_session->stepOver(); 0441 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0442 QCOMPARE(m_session->currentLine(), 40); // line 41: Container<A> structList; 0443 0444 if (!verifyVariable(0, QStringLiteral("stringList"), QStringLiteral("<size=3>"), QStringList{"\"a\"", "\"bc\"", "\"d\""}, 0445 __FILE__, __LINE__, false, false, unordered)) { 0446 return; 0447 } 0448 var->die(); 0449 0450 // <struct A> 0451 m_session->stepOver(); 0452 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0453 QCOMPARE(m_session->currentLine(), 41); // line 42: structList << A(QStringLiteral("a"), QStringLiteral("b"), 100, -200); 0454 0455 var = variableCollection()->watches()->add(QStringLiteral("structList")); 0456 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0457 0458 if (!verifyVariable(0, QStringLiteral("structList"), QStringLiteral("<size=0>"), QStringList{}, 0459 __FILE__, __LINE__, false, false, unordered)) { 0460 return; 0461 } 0462 0463 m_session->runUntil({}, 43); 0464 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0465 QCOMPARE(m_session->currentLine(), 42); // line 43: structList << A(); 0466 0467 variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update. 0468 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0469 0470 if (!verifyVariable(0, QStringLiteral("structList"), QStringLiteral("<size=1>"), QStringList{"{...}"}, 0471 __FILE__, __LINE__, false, false, unordered)) { 0472 return; 0473 } 0474 0475 m_session->stepOver(); 0476 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0477 QCOMPARE(m_session->currentLine(), 44); // line 45: Container<int*> pointerList; 0478 0479 if (!verifyVariable(0, QStringLiteral("structList"), QStringLiteral("<size=2>"), QStringList{"{...}", "{...}"}, 0480 __FILE__, __LINE__, false, false, unordered)) { 0481 return; 0482 } 0483 var->die(); 0484 0485 // <int*> 0486 m_session->stepOver(); 0487 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0488 QCOMPARE(m_session->currentLine(), 45); // line 46: pointerList << new int(1) << new int(2); 0489 0490 var = variableCollection()->watches()->add(QStringLiteral("pointerList")); 0491 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0492 0493 if (!verifyVariable(0, QStringLiteral("pointerList"), QStringLiteral("<size=0>"), QStringList{}, 0494 __FILE__, __LINE__, false, false, unordered)) { 0495 return; 0496 } 0497 0498 m_session->stepOver(); 0499 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0500 QCOMPARE(m_session->currentLine(), 46); // line 47: pointerList << new int(3); 0501 0502 variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update. 0503 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0504 0505 if (!verifyVariable(0, QStringLiteral("pointerList"), QStringLiteral("<size=2>"), QStringList{"^0x[0-9A-Fa-f]+$", "^0x[0-9A-Fa-f]+$"}, 0506 __FILE__, __LINE__, false, true, unordered)) { 0507 return; 0508 } 0509 0510 m_session->stepOver(); 0511 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0512 QCOMPARE(m_session->currentLine(), 47); // line 48: qDeleteAll(pointerList); 0513 0514 if (!verifyVariable(0, QStringLiteral("pointerList"), QStringLiteral("<size=3>"), QStringList{"^0x[0-9A-Fa-f]+$", "^0x[0-9A-Fa-f]+$", 0515 "^0x[0-9A-Fa-f]+$"}, 0516 __FILE__, __LINE__, false, true, unordered)) { 0517 return; 0518 } 0519 var->die(); 0520 m_session->stepOver(); // step over qDeleteAll 0521 0522 // <QPair<int, int>> 0523 m_session->stepOver(); 0524 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0525 QCOMPARE(m_session->currentLine(), 50); // line 51: pairList << QPair<int, int>(1, 2) << qMakePair(2, 3); 0526 0527 var = variableCollection()->watches()->add(QStringLiteral("pairList")); 0528 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0529 0530 VERIFY_WATCH(0, "pairList", "<size=0>", QStringList{}); 0531 0532 m_session->stepOver(); 0533 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0534 QCOMPARE(m_session->currentLine(), 51); // line 52: pairList << qMakePair(4, 5); 0535 0536 variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update. 0537 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0538 0539 if (!verifyVariable(0, QStringLiteral("pairList"), QStringLiteral("<size=2>"), QStringList{"{...}", "{...}"}, 0540 __FILE__, __LINE__, false, false, unordered)) { 0541 return; 0542 } 0543 0544 m_session->stepOver(); 0545 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0546 QCOMPARE(m_session->currentLine(), 54); // line 55: int i = 0; 0547 0548 if (!verifyVariable(0, QStringLiteral("pairList"), QStringLiteral("<size=3>"), QStringList{"{...}", "{...}", "{...}"}, 0549 __FILE__, __LINE__, false, false, unordered)) { 0550 return; 0551 } 0552 var->die(); 0553 } 0554 0555 void LldbFormattersTest::testQListPOD() 0556 { 0557 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qlistpod")); 0558 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qlistpod.cpp")), 30); 0559 0560 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0561 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0562 0563 // Should be two rows ('auto', 'local') 0564 QCOMPARE(variableCollection()->rowCount(), 2); 0565 0566 auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0); 0567 variableCollection()->expanded(watchRoot); 0568 variableCollection()->variableWidgetShown(); 0569 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0570 0571 variableCollection()->watches()->add(QStringLiteral("b")); 0572 variableCollection()->watches()->add(QStringLiteral("c")); 0573 variableCollection()->watches()->add(QStringLiteral("uc")); 0574 variableCollection()->watches()->add(QStringLiteral("s")); 0575 variableCollection()->watches()->add(QStringLiteral("us")); 0576 variableCollection()->watches()->add(QStringLiteral("i")); 0577 variableCollection()->watches()->add(QStringLiteral("ui")); 0578 variableCollection()->watches()->add(QStringLiteral("l")); 0579 variableCollection()->watches()->add(QStringLiteral("ul")); 0580 variableCollection()->watches()->add(QStringLiteral("i64")); 0581 variableCollection()->watches()->add(QStringLiteral("ui64")); 0582 variableCollection()->watches()->add(QStringLiteral("f")); 0583 variableCollection()->watches()->add(QStringLiteral("d")); 0584 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0585 0586 VERIFY_WATCH(0, "b", "<size=1>", (QStringList{"false"})); 0587 VERIFY_WATCH(1, "c", "<size=1>", (QStringList{"50 '2'"})); 0588 VERIFY_WATCH(2, "uc", "<size=1>", (QStringList{"50 '2'"})); 0589 0590 VERIFY_WATCH(3, "s", "<size=1>", (QStringList{"50"})); 0591 VERIFY_WATCH(4, "us", "<size=1>", (QStringList{"50"})); 0592 0593 VERIFY_WATCH(5, "i", "<size=1>", (QStringList{"50"})); 0594 VERIFY_WATCH(6, "ui", "<size=1>", (QStringList{"50"})); 0595 0596 VERIFY_WATCH(7, "l", "<size=1>", (QStringList{"50"})); 0597 VERIFY_WATCH(8, "ul", "<size=1>", (QStringList{"50"})); 0598 0599 VERIFY_WATCH(9, "i64", "<size=1>", (QStringList{"50"})); 0600 VERIFY_WATCH(10, "ui64", "<size=1>", (QStringList{"50"})); 0601 0602 VERIFY_WATCH(11, "f", "<size=1>", (QStringList{"50"})); 0603 VERIFY_WATCH(12, "d", "<size=1>", (QStringList{"50"})); 0604 } 0605 0606 void LldbFormattersTest::testQMapInt() 0607 { 0608 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qmapint")); 0609 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapint.cpp")), 6); 0610 0611 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0612 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0613 0614 // Should be two rows ('auto', 'local') 0615 QCOMPARE(variableCollection()->rowCount(), 2); 0616 0617 variableCollection()->expanded(localVariableIndexAt(0)); 0618 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0619 0620 VERIFY_LOCAL(0, "m", "<size=2>", (QStringList{"(10, 100)", "(20, 200)"})); 0621 0622 m_session->stepOver(); 0623 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0624 QCOMPARE(m_session->currentLine(), 7); 0625 0626 VERIFY_LOCAL(0, "m", "<size=3>", (QStringList{"(10, 100)", "(20, 200)", "(30, 300)"})); 0627 } 0628 0629 void LldbFormattersTest::testQMapString() 0630 { 0631 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qmapstring")); 0632 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapstring.cpp")), 7); 0633 0634 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0635 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0636 QCOMPARE(m_session->currentLine(), 7); // line 8: m[QStringLiteral("30")] = QStringLiteral("300"); 0637 0638 // Should be two rows ('auto', 'local') 0639 QCOMPARE(variableCollection()->rowCount(), 2); 0640 0641 variableCollection()->expanded(localVariableIndexAt(0)); 0642 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0643 0644 VERIFY_LOCAL(0, "m", "<size=2>", (QStringList{"(\"10\", \"100\")", "(\"20\", \"200\")"})); 0645 0646 m_session->stepOver(); 0647 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0648 QCOMPARE(m_session->currentLine(), 8); // line 9: return 0; 0649 0650 VERIFY_LOCAL(0, "m", "<size=3>", 0651 (QStringList{"(\"10\", \"100\")", "(\"20\", \"200\")", "(\"30\", \"300\")"})); 0652 } 0653 0654 void LldbFormattersTest::testQMapStringBool() 0655 { 0656 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qmapstringbool")); 0657 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapstringbool.cpp")), 7); 0658 0659 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0660 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0661 0662 // Should be two rows ('auto', 'local') 0663 QCOMPARE(variableCollection()->rowCount(), 2); 0664 0665 variableCollection()->expanded(localVariableIndexAt(0)); 0666 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0667 0668 VERIFY_LOCAL(0, "m", "<size=2>", (QStringList{"(\"10\", true)", "(\"20\", false)"})); 0669 0670 m_session->stepOver(); 0671 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0672 QCOMPARE(m_session->currentLine(), 8); 0673 0674 VERIFY_LOCAL(0, "m", "<size=3>", (QStringList{"(\"10\", true)", "(\"20\", false)", "(\"30\", true)"})); 0675 } 0676 0677 0678 void LldbFormattersTest::testQHashInt() 0679 { 0680 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qhashint")); 0681 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qhashint.cpp")), 6); 0682 0683 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0684 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0685 0686 // Should be two rows ('auto', 'local') 0687 QCOMPARE(variableCollection()->rowCount(), 2); 0688 0689 variableCollection()->expanded(localVariableIndexAt(0)); 0690 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0691 0692 if (!verifyVariable(0, QStringLiteral("h"), QStringLiteral("<size=2>"), QStringList{"(10, 100)", "(20, 200)"}, 0693 __FILE__, __LINE__, true, false, true)) { 0694 return; 0695 } 0696 0697 m_session->stepOver(); 0698 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0699 QCOMPARE(m_session->currentLine(), 7); 0700 0701 if (!verifyVariable(0, QStringLiteral("h"), QStringLiteral("<size=3>"), QStringList{"(10, 100)", "(20, 200)", "(30, 300)"}, 0702 __FILE__, __LINE__, true, false, true)) { 0703 return; 0704 } 0705 } 0706 0707 void LldbFormattersTest::testQHashString() 0708 { 0709 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qhashstring")); 0710 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qhashstring.cpp")), 7); 0711 0712 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0713 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0714 0715 // Should be two rows ('auto', 'local') 0716 QCOMPARE(variableCollection()->rowCount(), 2); 0717 0718 variableCollection()->expanded(localVariableIndexAt(0)); 0719 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0720 0721 if (!verifyVariable(0, QStringLiteral("h"), QStringLiteral("<size=2>"), QStringList{"(\"10\", \"100\")", "(\"20\", \"200\")"}, 0722 __FILE__, __LINE__, true, false, true)) { 0723 return; 0724 } 0725 0726 m_session->stepOver(); 0727 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0728 QCOMPARE(m_session->currentLine(), 8); 0729 0730 if (!verifyVariable(0, QStringLiteral("h"), QStringLiteral("<size=3>"), 0731 {"(\"10\", \"100\")", "(\"20\", \"200\")", "(\"30\", \"300\")"}, 0732 __FILE__, __LINE__, true, false, true)) { 0733 return; 0734 } 0735 } 0736 0737 void LldbFormattersTest::testQSetInt() 0738 { 0739 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qsetint")); 0740 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qsetint.cpp")), 6); 0741 0742 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0743 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0744 0745 // Should be two rows ('auto', 'local') 0746 QCOMPARE(variableCollection()->rowCount(), 2); 0747 0748 variableCollection()->expanded(localVariableIndexAt(0)); 0749 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0750 0751 if (!verifyVariable(0, QStringLiteral("s"), QStringLiteral("<size=2>"), QStringList{"10", "20"}, 0752 __FILE__, __LINE__, true, false, true)) { 0753 return; 0754 } 0755 0756 m_session->stepOver(); 0757 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0758 QCOMPARE(m_session->currentLine(), 7); 0759 0760 if (!verifyVariable(0, QStringLiteral("s"), QStringLiteral("<size=3>"), QStringList{"10", "20", "30"}, 0761 __FILE__, __LINE__, true, false, true)) { 0762 return; 0763 } 0764 } 0765 0766 void LldbFormattersTest::testQSetString() 0767 { 0768 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qsetstring")); 0769 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qsetstring.cpp")), 7); 0770 0771 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0772 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0773 0774 // Should be two rows ('auto', 'local') 0775 QCOMPARE(variableCollection()->rowCount(), 2); 0776 0777 variableCollection()->expanded(localVariableIndexAt(0)); 0778 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0779 0780 if (!verifyVariable(0, QStringLiteral("s"), QStringLiteral("<size=2>"), QStringList{"\"10\"", "\"20\""}, 0781 __FILE__, __LINE__, true, false, true)) { 0782 return; 0783 } 0784 0785 m_session->stepOver(); 0786 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0787 QCOMPARE(m_session->currentLine(), 8); 0788 0789 if (!verifyVariable(0, QStringLiteral("s"), QStringLiteral("<size=3>"), 0790 {"\"10\"", "\"20\"", "\"30\""}, 0791 __FILE__, __LINE__, true, false, true)) { 0792 return; 0793 } 0794 } 0795 0796 void LldbFormattersTest::testQDate() 0797 { 0798 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qdate")); 0799 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qdate.cpp")), 5); 0800 0801 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0802 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0803 0804 // Should be two rows ('auto', 'local') 0805 QCOMPARE(variableCollection()->rowCount(), 2); 0806 0807 variableCollection()->expanded(localVariableIndexAt(0)); 0808 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0809 0810 QList<QPair<QString, QString>> children; 0811 children.append({QStringLiteral("jd"), QStringLiteral("2455217")}); 0812 children.append({QStringLiteral("(ISO)"), QStringLiteral("\"2010-01-20\"")}); 0813 children.append({QStringLiteral("(Locale)"), QStringLiteral("\".+\"")}); // (Locale) and summary are locale dependent 0814 if (!verifyVariable(0, QStringLiteral("d"), QStringLiteral(".+"), children, 0815 __FILE__, __LINE__, true, true, false)) { 0816 return; 0817 } 0818 } 0819 0820 void LldbFormattersTest::testQTime() 0821 { 0822 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qtime")); 0823 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qtime.cpp")), 5); 0824 0825 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0826 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0827 0828 // Should be two rows ('auto', 'local') 0829 QCOMPARE(variableCollection()->rowCount(), 2); 0830 0831 variableCollection()->expanded(localVariableIndexAt(0)); 0832 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0833 0834 QList<QPair<QString, QString>> children; 0835 children.append({QStringLiteral("mds"), QStringLiteral("55810123")}); 0836 children.append({QStringLiteral("(ISO)"), QStringLiteral("\"15:30:10.000123\"")}); 0837 children.append({QStringLiteral("(Locale)"), QStringLiteral("\".+\"")}); // (Locale) and summary are locale dependent 0838 if (!verifyVariable(0, QStringLiteral("t"), QStringLiteral(".+"), children, 0839 __FILE__, __LINE__, true, true, false)) { 0840 return; 0841 } 0842 } 0843 0844 void LldbFormattersTest::testQDateTime() 0845 { 0846 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qdatetime")); 0847 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qdatetime.cpp")), 5); 0848 0849 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0850 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0851 0852 // Should be two rows ('auto', 'local') 0853 QCOMPARE(variableCollection()->rowCount(), 2); 0854 0855 variableCollection()->expanded(localVariableIndexAt(0)); 0856 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0857 0858 QList<QPair<QString, QString>> children; 0859 children.append({QStringLiteral("toSecsSinceEpoch"), QStringLiteral("1264019473")}); 0860 children.append({QStringLiteral("(ISO)"), QStringLiteral("\"2010-01-20 20:31:13\"")}); 0861 children.append({QStringLiteral("(Locale)"), QStringLiteral("\".+\"")}); // (Locale), (UTC) and summary are locale dependent 0862 children.append({QStringLiteral("(UTC)"), QStringLiteral("\".+\"")}); 0863 if (!verifyVariable(0, QStringLiteral("dt"), QStringLiteral(".+"), children, 0864 __FILE__, __LINE__, true, true, false)) { 0865 return; 0866 } 0867 } 0868 0869 void LldbFormattersTest::testQUrl() 0870 { 0871 TestLaunchConfiguration cfg(QStringLiteral("debuggee_qurl")); 0872 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qurl.cpp")), 4); 0873 0874 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0875 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0876 0877 // Should be two rows ('auto', 'local') 0878 QCOMPARE(variableCollection()->rowCount(), 2); 0879 0880 variableCollection()->expanded(localVariableIndexAt(0)); 0881 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0882 0883 QList<QPair<QString, QString>> children; 0884 children.append({QStringLiteral("(port)"), QStringLiteral("12345")}); 0885 children.append({QStringLiteral("(scheme)"), QStringLiteral("\"http\"")}); 0886 children.append({QStringLiteral("(userName)"), QStringLiteral("\"user\"")}); 0887 children.append({QStringLiteral("(password)"), QStringLiteral("<Invalid>")}); 0888 children.append({QStringLiteral("(host)"), QStringLiteral("\"www.kdevelop.org\"")}); 0889 children.append({QStringLiteral("(path)"), QStringLiteral("\"/foo\"")}); 0890 children.append({QStringLiteral("(query)"), QStringLiteral("\"xyz=bar\"")}); 0891 children.append({QStringLiteral("(fragment)"), QStringLiteral("\"asdf\"")}); 0892 VERIFY_LOCAL(0, "u", "http://user@www.kdevelop.org:12345/foo?xyz=bar#asdf", children); 0893 } 0894 0895 void LldbFormattersTest::testQUuid() 0896 { 0897 TestLaunchConfiguration cfg(QStringLiteral("debuggee_quuid")); 0898 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("quuid.cpp")), 4); 0899 0900 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0901 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0902 0903 // Should be two rows ('auto', 'local') 0904 QCOMPARE(variableCollection()->rowCount(), 2); 0905 0906 variableCollection()->expanded(localVariableIndexAt(0)); 0907 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0908 0909 VERIFY_LOCAL(0, "id", "QUuid({9ec3b70b-d105-42bf-b3b4-656e44d2e223})", (QStringList{})); 0910 } 0911 0912 void LldbFormattersTest::testKTextEditorTypes() 0913 { 0914 TestLaunchConfiguration cfg(QStringLiteral("debuggee_ktexteditortypes")); 0915 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("ktexteditortypes.cpp")), 8); 0916 0917 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0918 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0919 0920 // Should be two rows ('auto', 'local') 0921 QCOMPARE(variableCollection()->rowCount(), 2); 0922 0923 auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0); 0924 variableCollection()->expanded(watchRoot); 0925 variableCollection()->variableWidgetShown(); 0926 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0927 0928 variableCollection()->watches()->add(QStringLiteral("cursor")); 0929 variableCollection()->watches()->add(QStringLiteral("range")); 0930 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0931 0932 QList<QPair<QString, QString>> cursorChildren; 0933 cursorChildren.append({QStringLiteral("m_line"), QStringLiteral("1")}); 0934 cursorChildren.append({QStringLiteral("m_column"), QStringLiteral("1")}); 0935 0936 QList<QPair<QString, QString>> rangeChildren; 0937 rangeChildren.append({QStringLiteral("m_start"), QStringLiteral("(1, 1)")}); 0938 rangeChildren.append({QStringLiteral("m_end"), QStringLiteral("(2, 2)")}); 0939 0940 VERIFY_WATCH(0, "cursor", "(1, 1)", cursorChildren); 0941 VERIFY_WATCH(1, "range", "[(1, 1) -> (2, 2)]", rangeChildren); 0942 } 0943 0944 void LldbFormattersTest::testKDevelopTypes() 0945 { 0946 TestLaunchConfiguration cfg(QStringLiteral("debuggee_kdeveloptypes")); 0947 addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("kdeveloptypes.cpp")), 11); 0948 0949 QVERIFY(m_session->startDebugging(&cfg, m_iface)); 0950 WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState); 0951 0952 // Should be two rows ('auto', 'local') 0953 QCOMPARE(variableCollection()->rowCount(), 2); 0954 0955 auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0); 0956 variableCollection()->expanded(watchRoot); 0957 variableCollection()->variableWidgetShown(); 0958 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0959 0960 variableCollection()->watches()->add(QStringLiteral("path1")); 0961 variableCollection()->watches()->add(QStringLiteral("path2")); 0962 WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50); 0963 0964 QList<QPair<QString, QString>> path1Children; 0965 path1Children.append({QStringLiteral("m_data"), QStringLiteral("<size=2>")}); 0966 0967 QList<QPair<QString, QString>> path2Children; 0968 path2Children.append({QStringLiteral("m_data"), QStringLiteral("<size=3>")}); 0969 0970 VERIFY_WATCH(0, "path1", "(\"tmp\", \"foo\")", path1Children); 0971 VERIFY_WATCH(1, "path2", "(\"http://www.test.com\", \"tmp\", \"asdf.txt\")", path2Children); 0972 } 0973 0974 QTEST_MAIN(LldbFormattersTest) 0975 0976 #include "test_lldbformatters.moc" 0977 #include "moc_test_lldbformatters.cpp"