File indexing completed on 2024-05-12 04:38:21

0001 /*
0002     SPDX-FileCopyrightText: 2015 Laszlo Kis-Adam <laszlo.kis-adam@kdemail.net>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <QTest>
0008 
0009 #include <shell/problemmodel.h>
0010 #include <shell/problem.h>
0011 #include <shell/problemconstants.h>
0012 #include <language/editor/documentrange.h>
0013 
0014 #include <tests/testcore.h>
0015 #include <tests/autotestshell.h>
0016 
0017 #include <KLocalizedString>
0018 
0019 #define MYCOMPARE(actual, expected) \
0020     if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
0021     return false
0022 
0023 #define MYVERIFY(statement) \
0024     if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\
0025         return false
0026 
0027 using namespace KDevelop;
0028 
0029 class TestProblemModel : public QObject
0030 {
0031     Q_OBJECT
0032 private Q_SLOTS:
0033     void initTestCase();
0034     void cleanupTestCase();
0035 
0036     void testNoGrouping();
0037     void testPathGrouping();
0038     void testSeverityGrouping();
0039     void testPlaceholderText();
0040 
0041 private:
0042     QString prependPathRoot(QString const& currentPath) const;
0043     void generateProblems();
0044     bool checkIsSame(int row, const QModelIndex &parent, const IProblem::Ptr &problem);
0045     bool checkDiagnostics(int row, const QModelIndex &parent);
0046     bool checkDisplay(int row, const QModelIndex &parent, const IProblem::Ptr &problem);
0047     bool checkLabel(int row, const QModelIndex &parent, const QString &label);
0048     bool checkPathGroup(int row, const IProblem::Ptr &problem);
0049     bool checkSeverityGroup(int row, const IProblem::Ptr &problem);
0050 
0051     QScopedPointer<ProblemModel> m_model;
0052     QVector<IProblem::Ptr> m_problems;
0053     IProblem::Ptr m_diagnosticTestProblem;
0054 };
0055 
0056 void TestProblemModel::initTestCase()
0057 {
0058     AutoTestShell::init();
0059     TestCore::initialize(Core::NoUi);
0060 
0061     m_model.reset(new ProblemModel(nullptr));
0062     m_model->setScope(BypassScopeFilter);
0063 
0064     generateProblems();
0065 }
0066 
0067 void TestProblemModel::cleanupTestCase()
0068 {
0069     TestCore::shutdown();
0070 }
0071 
0072 void TestProblemModel::testNoGrouping()
0073 {
0074     m_model->setGrouping(NoGrouping);
0075     m_model->setSeverity(IProblem::Hint);
0076 
0077     QCOMPARE(m_model->rowCount(), 0);
0078 
0079     // Check if setting the problems works
0080     m_model->setProblems(m_problems);
0081     QCOMPARE(m_model->rowCount(), 3);
0082 
0083     for (int i = 0; i < m_model->rowCount(); i++) {
0084         QVERIFY(checkIsSame(i, QModelIndex(), m_problems[i]));
0085     }
0086 
0087     // Check if displaying various data parts works
0088     QVERIFY(checkDisplay(0, QModelIndex(), m_problems[0]));
0089 
0090     // Check if clearing the problems works
0091     m_model->clearProblems();
0092     QCOMPARE(m_model->rowCount(), 0);
0093 
0094     // Check if adding the problems works
0095     int c = 0;
0096     for (const IProblem::Ptr& p : qAsConst(m_problems)) {
0097         m_model->addProblem(p);
0098         c++;
0099 
0100         QCOMPARE(m_model->rowCount(), c);
0101     }
0102 
0103     for (int i = 0; i < m_model->rowCount(); i++) {
0104         QVERIFY(checkIsSame(i, QModelIndex(), m_problems[i]));
0105     }
0106 
0107 
0108     // Check if filtering works
0109     // old-style setSeverity
0110     // Error filter
0111     m_model->setSeverity(IProblem::Error);
0112     QCOMPARE(m_model->rowCount(), 1);
0113     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0114 
0115     // Warning filter
0116     m_model->setSeverity(IProblem::Warning);
0117     QCOMPARE(m_model->rowCount(), 2);
0118     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0119     QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1]));
0120 
0121     // Hint filter
0122     m_model->setSeverity(IProblem::Hint);
0123     QCOMPARE(m_model->rowCount(), 3);
0124     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0125     QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1]));
0126     QVERIFY(checkIsSame(2, QModelIndex(), m_problems[2]));
0127 
0128     // Check if filtering works
0129     // new style
0130     // Error filter
0131     m_model->setSeverities(IProblem::Error);
0132     QCOMPARE(m_model->rowCount(), 1);
0133     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0134 
0135     // Warning filter
0136     m_model->setSeverities(IProblem::Warning);
0137     QCOMPARE(m_model->rowCount(), 1);
0138     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[1]));
0139 
0140     // Hint filter
0141     m_model->setSeverities(IProblem::Hint);
0142     QCOMPARE(m_model->rowCount(), 1);
0143     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[2]));
0144 
0145     // Error + Hint filter
0146     m_model->setSeverities(IProblem::Error | IProblem::Hint);
0147     QCOMPARE(m_model->rowCount(), 2);
0148     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0149     QVERIFY(checkIsSame(1, QModelIndex(), m_problems[2]));
0150 
0151     m_model->setSeverities(IProblem::Error | IProblem::Warning | IProblem::Hint);
0152 
0153     // Check if diagnostics are added properly
0154     m_model->clearProblems();
0155     m_model->addProblem(m_diagnosticTestProblem);
0156     QVERIFY(checkDiagnostics(0, QModelIndex()));
0157 
0158     m_model->clearProblems();
0159 }
0160 
0161 void TestProblemModel::testPathGrouping()
0162 {
0163     m_model->setGrouping(PathGrouping);
0164     m_model->setSeverity(IProblem::Hint);
0165     QCOMPARE(m_model->rowCount(), 0);
0166 
0167     // Check if setting problems works
0168     m_model->setProblems(m_problems);
0169     QCOMPARE(m_model->rowCount(), 3);
0170 
0171     for (int i = 0; i < m_model->rowCount(); i++) {
0172         QVERIFY(checkLabel(i, QModelIndex(), m_problems[i]->finalLocation().document.str()));
0173 
0174         QModelIndex idx = m_model->index(i, 0);
0175         QVERIFY(idx.isValid());
0176         QVERIFY(checkIsSame(0, idx, m_problems[i]));
0177     }
0178 
0179     // Check if displaying various data parts works
0180     {
0181         QModelIndex idx = m_model->index(0, 0);
0182         QVERIFY(idx.isValid());
0183         QVERIFY(checkDisplay(0, idx, m_problems[0]));
0184     }
0185 
0186     // Check if clearing works
0187     m_model->clearProblems();
0188     QCOMPARE(m_model->rowCount(), 0);
0189 
0190     // Check if add problems works
0191     int c = 0;
0192     for (const IProblem::Ptr& p : qAsConst(m_problems)) {
0193         m_model->addProblem(p);
0194         c++;
0195 
0196         QCOMPARE(m_model->rowCount(), c);
0197     }
0198 
0199     for (int i = 0; i < m_model->rowCount(); i++) {
0200         QVERIFY(checkLabel(i, QModelIndex(), m_problems[i]->finalLocation().document.str()));
0201 
0202         QModelIndex idx = m_model->index(i, 0);
0203         QVERIFY(idx.isValid());
0204         QVERIFY(checkIsSame(0, idx, m_problems[i]));
0205     }
0206 
0207     // Check if filtering works
0208     // old-style setSeverity
0209     // Error filtering
0210     m_model->setSeverity(IProblem::Error);
0211     QCOMPARE(m_model->rowCount(), 1);
0212     QVERIFY(checkPathGroup(0, m_problems[0]));
0213 
0214     // Warning filtering
0215     m_model->setSeverity(IProblem::Warning);
0216     QCOMPARE(m_model->rowCount(), 2);
0217     QVERIFY(checkPathGroup(0, m_problems[0]));
0218     QVERIFY(checkPathGroup(1, m_problems[1]));
0219 
0220     // Hint filtering
0221     m_model->setSeverity(IProblem::Hint);
0222     QCOMPARE(m_model->rowCount(), 3);
0223     QVERIFY(checkPathGroup(0, m_problems[0]));
0224     QVERIFY(checkPathGroup(1, m_problems[1]));
0225     QVERIFY(checkPathGroup(2, m_problems[2]));
0226 
0227     // Check if filtering works
0228     // new style
0229     // Error filtering
0230     m_model->setSeverities(IProblem::Error);
0231     QCOMPARE(m_model->rowCount(), 1);
0232     QVERIFY(checkPathGroup(0, m_problems[0]));
0233 
0234     // Warning filtering
0235     m_model->setSeverities(IProblem::Warning);
0236     QCOMPARE(m_model->rowCount(), 1);
0237     QVERIFY(checkPathGroup(0, m_problems[1]));
0238 
0239     // Hint filtering
0240     m_model->setSeverities(IProblem::Hint);
0241     QCOMPARE(m_model->rowCount(), 1);
0242     QVERIFY(checkPathGroup(0, m_problems[2]));
0243 
0244     // Error + Hint filtering
0245     m_model->setSeverities(IProblem::Error | IProblem::Hint);
0246     QCOMPARE(m_model->rowCount(), 2);
0247     QVERIFY(checkPathGroup(0, m_problems[0]));
0248     QVERIFY(checkPathGroup(1, m_problems[2]));
0249 
0250     m_model->setSeverities(IProblem::Error | IProblem::Warning | IProblem::Hint);
0251 
0252     // Check if diagnostics get to the right place
0253     m_model->clearProblems();
0254     m_model->addProblem(m_diagnosticTestProblem);
0255     {
0256         QModelIndex parent = m_model->index(0, 0);
0257         QVERIFY(parent.isValid());
0258         checkDiagnostics(0, parent);
0259     }
0260 
0261     m_model->clearProblems();
0262 }
0263 
0264 void TestProblemModel::testSeverityGrouping()
0265 {
0266     m_model->setGrouping(SeverityGrouping);
0267     m_model->setSeverity(IProblem::Hint);
0268     QCOMPARE(m_model->rowCount(), 3);
0269 
0270     // Check if setting problems works
0271     m_model->setProblems(m_problems);
0272     QCOMPARE(m_model->rowCount(), 3);
0273     for (int i = 0; i < m_model->rowCount(); i++) {
0274         QVERIFY(checkSeverityGroup(i, m_problems[i]));
0275     }
0276 
0277     // Check if displaying works
0278     for (int i = 0; i < m_model->rowCount(); i++) {
0279         QModelIndex parent = m_model->index(i, 0);
0280         QVERIFY(parent.isValid());
0281 
0282         QVERIFY(checkDisplay(0, parent, m_problems[i]));
0283     }
0284 
0285     // Check if clearing works
0286     m_model->clearProblems();
0287     QCOMPARE(m_model->rowCount(), 3);
0288 
0289     // Check if adding problems works
0290     int c = 0;
0291     for (const IProblem::Ptr& p : qAsConst(m_problems)) {
0292         m_model->addProblem(p);
0293         QVERIFY(checkSeverityGroup(c, m_problems[c]));
0294         c++;
0295     }
0296 
0297     // Check if filtering works
0298     // old-style setSeverity
0299     // Error filtering
0300     m_model->setSeverity(IProblem::Error);
0301     QCOMPARE(m_model->rowCount(), 3);
0302     checkSeverityGroup(0, m_problems[0]);
0303 
0304     // Warning filtering
0305     m_model->setSeverity(IProblem::Warning);
0306     QCOMPARE(m_model->rowCount(), 3);
0307     checkSeverityGroup(0, m_problems[0]);
0308     checkSeverityGroup(1, m_problems[1]);
0309 
0310     // Hint filtering
0311     m_model->setSeverity(IProblem::Hint);
0312     QCOMPARE(m_model->rowCount(), 3);
0313     checkSeverityGroup(0, m_problems[0]);
0314     checkSeverityGroup(1, m_problems[1]);
0315     checkSeverityGroup(2, m_problems[2]);
0316 
0317     // Check if filtering works
0318     // Error filtering
0319     m_model->setSeverities(IProblem::Error);
0320     QCOMPARE(m_model->rowCount(), 3);
0321     checkSeverityGroup(0, m_problems[0]);
0322 
0323     // Warning filtering
0324     m_model->setSeverities(IProblem::Warning);
0325     QCOMPARE(m_model->rowCount(), 3);
0326     checkSeverityGroup(1, m_problems[1]);
0327 
0328     // Hint filtering
0329     m_model->setSeverities(IProblem::Hint);
0330     QCOMPARE(m_model->rowCount(), 3);
0331     checkSeverityGroup(2, m_problems[2]);
0332 
0333     // Error + Hint filtering
0334     m_model->setSeverities(IProblem::Error | IProblem::Hint);
0335     QCOMPARE(m_model->rowCount(), 3);
0336     checkSeverityGroup(0, m_problems[0]);
0337     checkSeverityGroup(2, m_problems[2]);
0338 
0339     m_model->setSeverities(IProblem::Error | IProblem::Warning | IProblem::Hint);
0340 
0341     // Check if diagnostics get to the right place
0342     m_model->clearProblems();
0343     m_model->addProblem(m_diagnosticTestProblem);
0344     {
0345         QModelIndex parent = m_model->index(0, 0);
0346         QVERIFY(parent.isValid());
0347 
0348         checkDiagnostics(0, parent);
0349     }
0350 
0351     m_model->clearProblems();
0352 }
0353 
0354 void TestProblemModel::testPlaceholderText()
0355 {
0356     const QString text1 = QStringLiteral("testPlaceholderText1");
0357     const QString text2 = QStringLiteral("testPlaceholderText2");
0358     const QString empty;
0359 
0360     m_model->setGrouping(NoGrouping);
0361 
0362     // Test model with empty placeholder text
0363 
0364     QCOMPARE(m_model->rowCount(), 0);
0365     m_model->setPlaceholderText(empty);
0366     QCOMPARE(m_model->rowCount(), 0);
0367     m_model->setProblems(m_problems);
0368     QCOMPARE(m_model->rowCount(), 3);
0369     m_model->clearProblems();
0370     QCOMPARE(m_model->rowCount(), 0);
0371 
0372     // Test empty model with non-empty placeholder text
0373 
0374     m_model->setPlaceholderText(text1);
0375     QCOMPARE(m_model->rowCount(), 1);
0376     QVERIFY(checkLabel(0, QModelIndex(), text1));
0377 
0378     m_model->setPlaceholderText(text2);
0379     QCOMPARE(m_model->rowCount(), 1);
0380     QVERIFY(checkLabel(0, QModelIndex(), text2));
0381 
0382     // Test non-empty model with non-empty placeholder text
0383 
0384     m_model->setProblems(m_problems);
0385     QCOMPARE(m_model->rowCount(), 3);
0386 
0387     m_model->clearProblems();
0388     QCOMPARE(m_model->rowCount(), 1);
0389     QVERIFY(checkLabel(0, QModelIndex(), text2));
0390 
0391     m_model->addProblem(m_problems[0]);
0392     QCOMPARE(m_model->rowCount(), 1);
0393     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0394 
0395     m_model->addProblem(m_problems[1]);
0396     QCOMPARE(m_model->rowCount(), 2);
0397     QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1]));
0398 
0399     m_model->setPlaceholderText(text1);
0400     QCOMPARE(m_model->rowCount(), 2);
0401     QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0]));
0402     QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1]));
0403 
0404     m_model->setProblems({});
0405     QCOMPARE(m_model->rowCount(), 1);
0406     QVERIFY(checkLabel(0, QModelIndex(), text1));
0407 }
0408 
0409 // Needed because util/Path.cpp asserts e.g. C: on Windows
0410 QString TestProblemModel::prependPathRoot(QString const& currentPath) const
0411 {
0412 #ifdef Q_OS_WIN
0413     QString pathRoot = QStringLiteral("x:/");
0414 #else
0415     QString pathRoot = QStringLiteral("/");
0416 #endif
0417     return pathRoot + currentPath;
0418 }
0419 
0420 // Generate 3 problems, all with different paths, different severity
0421 // Also generates a problem with diagnostics
0422 void TestProblemModel::generateProblems()
0423 {
0424     IProblem::Ptr p1(new DetectedProblem());
0425     IProblem::Ptr p2(new DetectedProblem());
0426     IProblem::Ptr p3(new DetectedProblem());
0427 
0428     DocumentRange r1;
0429     r1.document = IndexedString( prependPathRoot("just/a/random/path") );
0430 
0431     p1->setDescription(QStringLiteral("PROBLEM1"));
0432     p1->setSeverity(IProblem::Error);
0433     p1->setFinalLocation(r1);
0434 
0435     DocumentRange r2;
0436     r2.document = IndexedString( prependPathRoot("just/another/path") );
0437 
0438     p2->setDescription(QStringLiteral("PROBLEM2"));
0439     p2->setSeverity(IProblem::Warning);
0440     p2->setFinalLocation(r2);
0441 
0442     DocumentRange r3;
0443     r3.document = IndexedString( prependPathRoot("yet/another/test/path") );
0444 
0445     p2->setDescription(QStringLiteral("PROBLEM3"));
0446     p3->setSeverity(IProblem::Hint);
0447     p3->setFinalLocation(r3);
0448 
0449     m_problems.push_back(p1);
0450     m_problems.push_back(p2);
0451     m_problems.push_back(p3);
0452 
0453     // Problem for diagnostic testing
0454     IProblem::Ptr p(new DetectedProblem());
0455     DocumentRange r;
0456     r.document = IndexedString("DIAGTEST");
0457     p->setFinalLocation(r);
0458     p->setDescription(QStringLiteral("PROBLEM"));
0459     p->setSeverity(IProblem::Error);
0460 
0461     IProblem::Ptr d(new DetectedProblem());
0462     d->setDescription(QStringLiteral("DIAG"));
0463 
0464     IProblem::Ptr dd(new DetectedProblem());
0465     dd->setDescription(QStringLiteral("DIAGDIAG"));
0466     d->addDiagnostic(dd);
0467     p->addDiagnostic(d);
0468     m_diagnosticTestProblem = p;
0469 }
0470 
0471 bool TestProblemModel::checkIsSame(int row, const QModelIndex &parent, const IProblem::Ptr &problem)
0472 {
0473     QModelIndex idx;
0474 
0475     idx = m_model->index(row, 0, parent);
0476     MYVERIFY(idx.isValid());
0477     MYCOMPARE(m_model->data(idx).toString(), problem->description());
0478 
0479     return true;
0480 }
0481 
0482 bool TestProblemModel::checkDiagnostics(int row, const QModelIndex &parent)
0483 {
0484     MYCOMPARE(m_model->rowCount(parent), 1);
0485 
0486     QModelIndex idx;
0487     idx = m_model->index(row, 0, parent);
0488     MYVERIFY(idx.isValid());
0489     MYCOMPARE(m_model->data(idx).toString(), m_diagnosticTestProblem->description());
0490 
0491     QModelIndex diagidx;
0492     IProblem::Ptr diag = m_diagnosticTestProblem->diagnostics().at(0);
0493     diagidx = m_model->index(0, 0, idx);
0494     MYVERIFY(diagidx.isValid());
0495     MYCOMPARE(m_model->data(diagidx).toString(), diag->description());
0496 
0497     QModelIndex diagdiagidx;
0498     IProblem::Ptr diagdiag = diag->diagnostics().at(0);
0499     diagdiagidx = m_model->index(0, 0, diagidx);
0500     MYVERIFY(diagdiagidx.isValid());
0501     MYCOMPARE(m_model->data(diagdiagidx).toString(), diagdiag->description());
0502 
0503     return true;
0504 }
0505 
0506 bool TestProblemModel::checkDisplay(int row, const QModelIndex &parent, const IProblem::Ptr &problem)
0507 {
0508     QModelIndex idx;
0509 
0510     idx = m_model->index(row, 0, parent);
0511     MYVERIFY(idx.isValid());
0512     MYCOMPARE(m_model->data(idx).toString(), problem->description());
0513 
0514     idx = m_model->index(row, 1, parent);
0515     MYVERIFY(idx.isValid());
0516     MYCOMPARE(m_model->data(idx).toString(), problem->sourceString());
0517 
0518     idx = m_model->index(row, 2, parent);
0519     MYVERIFY(idx.isValid());
0520     MYCOMPARE(m_model->data(idx).toString(), problem->finalLocation().document.str());
0521 
0522     idx = m_model->index(row, 3, parent);
0523     MYVERIFY(idx.isValid());
0524     MYCOMPARE(m_model->data(idx).toString(), QString::number(problem->finalLocation().start().line() + 1));
0525 
0526     idx = m_model->index(row, 4, parent);
0527     MYVERIFY(idx.isValid());
0528     MYCOMPARE(m_model->data(idx).toString(), QString::number(problem->finalLocation().start().column() + 1));
0529 
0530     return true;
0531 }
0532 
0533 bool TestProblemModel::checkLabel(int row, const QModelIndex &parent, const QString &label)
0534 {
0535     QModelIndex idx = m_model->index(row, 0, parent);
0536     MYVERIFY(idx.isValid());
0537     MYCOMPARE(m_model->data(idx).toString(), label);
0538 
0539     return true;
0540 }
0541 
0542 bool TestProblemModel::checkPathGroup(int row, const IProblem::Ptr &problem)
0543 {
0544     QModelIndex parent = m_model->index(row, 0);
0545     MYVERIFY(parent.isValid());
0546     MYCOMPARE(m_model->data(parent).toString(), problem->finalLocation().document.str());
0547 
0548     QModelIndex idx = m_model->index(0, 0, parent);
0549     MYVERIFY(idx.isValid());
0550     MYCOMPARE(m_model->data(idx).toString(), problem->description());
0551 
0552     return true;
0553 }
0554 
0555 bool TestProblemModel::checkSeverityGroup(int row, const IProblem::Ptr &problem)
0556 {
0557     QModelIndex parent = m_model->index(row, 0);
0558     MYVERIFY(parent.isValid());
0559     MYCOMPARE(m_model->data(parent).toString(), problem->severityString());
0560 
0561     QModelIndex idx = m_model->index(0, 0, parent);
0562     MYVERIFY(idx.isValid());
0563     MYCOMPARE(m_model->data(idx).toString(), problem->description());
0564 
0565     return true;
0566 }
0567 
0568 QTEST_MAIN(TestProblemModel)
0569 
0570 #include "test_problemmodel.moc"