File indexing completed on 2024-05-05 04:35:27
0001 /* 0002 * This file is part of KDevelop Krazy2 Plugin. 0003 * 0004 * Copyright 2012 Daniel Calviño Sánchez <danxuliu@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License 0008 * as published by the Free Software Foundation; either version 2 0009 * of the License, or (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include <QtTest> 0021 0022 #include <KConfigGroup> 0023 #include <KSharedConfig> 0024 #include <KLocalizedString> 0025 0026 #include <tests/autotestshell.h> 0027 #include <tests/testcore.h> 0028 0029 #include "../analysisjob.h" 0030 #include "../analysisparameters.h" 0031 #include "../analysisprogressparser.h" 0032 #include "../analysisresults.h" 0033 #include "../checker.h" 0034 #include "../checkerlistjob.h" 0035 #include "../issue.h" 0036 0037 //Needed for qRegisterMetaType 0038 Q_DECLARE_METATYPE(KJob*) 0039 0040 /** 0041 * Modified version of private KSignalSpy found in 0042 * kdelibs/kdecore/util/qtest_kde.cpp. 0043 * Original KDESignalSpy, accessed through 0044 * QTest::kWaitForSignal(QObject*, const char*, int), can miss a signal if it is 0045 * emitted too quickly (that is, before the connect is reached). This modified 0046 * version, instead of starting the wait in the constructor, has a specific 0047 * method for it. So the object can be created before executing the call that 0048 * emits the signal, enabling it to register the signal before starting to wait 0049 * and thus ensuring that no signal will be missed. 0050 */ 0051 class SignalSpy: public QObject { 0052 Q_OBJECT 0053 public: 0054 SignalSpy(QObject* object, const char* signal): QObject(nullptr), 0055 m_signalSpy(object, signal) { 0056 connect(object, signal, this, SLOT(signalEmitted())); 0057 } 0058 0059 bool waitForSignal(int timeout = 0) { 0060 if (m_signalSpy.count() == 0) { 0061 if (timeout > 0) { 0062 QObject::connect(&m_timer, SIGNAL(timeout()), &m_loop, SLOT(quit())); 0063 m_timer.setSingleShot(true); 0064 m_timer.start(timeout); 0065 } 0066 m_loop.exec(); //krazy:exclude=crashy 0067 } 0068 0069 if (m_signalSpy.count() >= 0) { 0070 return true; 0071 } 0072 return false; 0073 } 0074 private Q_SLOTS: 0075 void signalEmitted() { 0076 m_timer.stop(); 0077 m_loop.quit(); 0078 } 0079 private: 0080 QSignalSpy m_signalSpy; 0081 QEventLoop m_loop; 0082 QTimer m_timer; 0083 }; 0084 0085 class AnalysisJobTest: public QObject { 0086 Q_OBJECT 0087 private slots: 0088 0089 void initTestCase(); 0090 void init(); 0091 void cleanupTestCase(); 0092 0093 void testConstructor(); 0094 0095 void testRunCheckers(); 0096 void testRunExtraCheckers(); 0097 void testRunExtraCheckersAndSubsetOfCheckers(); 0098 void testRunCheckerWithDuplicatedNamesAndSpecificFileTypes(); 0099 void testRunCheckersWithNoFiles(); 0100 void testRunSeveralAnalysisParameters(); 0101 void testRunSeveralAnalysisParametersSomeOfThemWithoutFiles(); 0102 void testRunWithInvalidKrazy2ExecutablePath(); 0103 0104 void testKill(); 0105 0106 private: 0107 0108 QString m_examplesPath; 0109 0110 bool examplesInSubdirectory() const; 0111 bool krazy2InPath() const; 0112 0113 QList<const Checker*> getAvailableCheckers() const; 0114 0115 const Issue* findIssue(const AnalysisResults* analysisResults, 0116 const QString& checkerName, 0117 const QString& exampleFileName, int line) const; 0118 0119 }; 0120 0121 void AnalysisJobTest::initTestCase() { 0122 m_examplesPath = QStringLiteral(EXAMPLETESTDATA_PATH); 0123 0124 //Needed for SignalSpy 0125 qRegisterMetaType<KJob*>(); 0126 qRegisterMetaType<KDevelop::IStatus*>(); 0127 0128 KDevelop::AutoTestShell::init({"kdevkrazy2"}); 0129 KDevelop::TestCore::initialize(KDevelop::Core::NoUi); 0130 } 0131 0132 void AnalysisJobTest::init() { 0133 if (!examplesInSubdirectory()) { 0134 QString message = "The examples were not found in the 'examples' directory (" + m_examplesPath + ')'; 0135 QSKIP(message.toLatin1(), SkipAll); 0136 } 0137 0138 if (!krazy2InPath()) { 0139 QSKIP("krazy2 is not in the execution path", SkipAll); 0140 } 0141 0142 KConfigGroup krazy2Configuration = KSharedConfig::openConfig()->group("Krazy2"); 0143 krazy2Configuration.writeEntry("krazy2 Path", "krazy2"); 0144 } 0145 0146 void AnalysisJobTest::cleanupTestCase() { 0147 KDevelop::TestCore::shutdown(); 0148 } 0149 0150 void AnalysisJobTest::testConstructor() { 0151 QObject parent; 0152 auto analysisJob = new AnalysisJob(&parent); 0153 0154 QCOMPARE(analysisJob->parent(), &parent); 0155 QCOMPARE(analysisJob->capabilities(), KJob::Killable); 0156 QCOMPARE(analysisJob->objectName(), 0157 xi18nc("@action:inmenu", "<command>krazy2</command> analysis")); 0158 } 0159 0160 void AnalysisJobTest::testRunCheckers() { 0161 AnalysisJob analysisJob; 0162 analysisJob.setAutoDelete(false); 0163 0164 QList<const Checker*> availableCheckers; 0165 0166 auto doubleQuoteCharsChecker = new Checker(); 0167 doubleQuoteCharsChecker->setFileType("c++"); 0168 doubleQuoteCharsChecker->setName("doublequote_chars"); 0169 doubleQuoteCharsChecker->setDescription("Check single-char QString operations for efficiency"); 0170 doubleQuoteCharsChecker->setExplanation("Adding single characters to a QString " 0171 "is faster if the characters are QChars..."); 0172 availableCheckers.append(doubleQuoteCharsChecker); 0173 0174 auto licenseChecker = new Checker(); 0175 licenseChecker->setFileType("c++"); 0176 licenseChecker->setName("license"); 0177 licenseChecker->setDescription("Check for an acceptable license"); 0178 licenseChecker->setExplanation("Each source file must contain a license " 0179 "or a reference to a license which states..."); 0180 availableCheckers.append(licenseChecker); 0181 0182 auto spellingChecker = new Checker(); 0183 spellingChecker->setFileType("c++"); 0184 spellingChecker->setName("spelling"); 0185 spellingChecker->setDescription("Check for spelling errors"); 0186 spellingChecker->setExplanation("Spelling errors in comments and strings " 0187 "should be fixed as they may show up later..."); 0188 availableCheckers.append(spellingChecker); 0189 0190 auto validateChecker = new Checker(); 0191 validateChecker->setFileType("desktop"); 0192 validateChecker->setName("validate"); 0193 validateChecker->setDescription("Validates desktop files using 'desktop-file-validate'"); 0194 validateChecker->setExplanation("Please make sure your .desktop files conform " 0195 "to the freedesktop.org standard. See the spec..."); 0196 availableCheckers.append(validateChecker); 0197 0198 auto qmlLicenseChecker = new Checker(); 0199 qmlLicenseChecker->setFileType("qml"); 0200 qmlLicenseChecker->setName("license"); 0201 qmlLicenseChecker->setDescription("Check for an acceptable license"); 0202 qmlLicenseChecker->setExplanation("Each source file must contain a license " 0203 "or a reference to a license which states..."); 0204 availableCheckers.append(qmlLicenseChecker); 0205 0206 //Do not set spelling checker 0207 QList<const Checker*> checkersToRun; 0208 checkersToRun.append(doubleQuoteCharsChecker); 0209 checkersToRun.append(licenseChecker); 0210 checkersToRun.append(validateChecker); 0211 checkersToRun.append(qmlLicenseChecker); 0212 0213 AnalysisParameters analysisParameters; 0214 analysisParameters.initializeCheckers(availableCheckers); 0215 analysisParameters.setCheckersToRun(checkersToRun); 0216 analysisParameters.setFilesAndDirectories(QStringList() << m_examplesPath); 0217 analysisJob.addAnalysisParameters(&analysisParameters); 0218 0219 AnalysisResults analysisResults; 0220 analysisJob.setAnalysisResults(&analysisResults); 0221 0222 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0223 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0224 0225 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0226 0227 analysisJob.start(); 0228 0229 resultSpy.waitForSignal(); 0230 0231 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0232 QCOMPARE(analysisResults.issues().count(), 10); 0233 0234 //To prevent test failures due to the order of the issues, each issue is 0235 //searched in the results instead of using a specific index 0236 const Issue* issue = findIssue(&analysisResults, "doublequote_chars", 0237 "singleIssue.cpp", 8); 0238 QVERIFY(issue); 0239 QCOMPARE(issue->message(), QString("")); 0240 QCOMPARE(issue->checker()->description(), 0241 QString("Check single-char QString operations for efficiency")); 0242 QVERIFY(issue->checker()->explanation().startsWith( 0243 "Adding single characters to a QString is faster")); 0244 QCOMPARE(issue->checker()->fileType(), QString("c++")); 0245 QVERIFY(!issue->checker()->isExtra()); 0246 0247 const Issue* issue2 = findIssue(&analysisResults, "doublequote_chars", 0248 "severalIssuesSingleChecker.cpp", 8); 0249 QVERIFY(issue2); 0250 QCOMPARE(issue2->message(), QString("")); 0251 QCOMPARE(issue2->checker(), issue->checker()); 0252 0253 const Issue* issue3 = findIssue(&analysisResults, "doublequote_chars", 0254 "severalIssuesSingleChecker.cpp", 10); 0255 QVERIFY(issue3); 0256 QCOMPARE(issue3->message(), QString("")); 0257 QCOMPARE(issue3->checker(), issue->checker()); 0258 0259 const Issue* issue4 = findIssue(&analysisResults, "doublequote_chars", 0260 "severalIssuesSeveralCheckers.cpp", 8); 0261 QVERIFY(issue4); 0262 QCOMPARE(issue4->message(), QString("")); 0263 QCOMPARE(issue4->checker(), issue->checker()); 0264 0265 const Issue* issue5 = findIssue(&analysisResults, "doublequote_chars", 0266 "severalIssuesSeveralCheckers.cpp", 12); 0267 QVERIFY(issue5); 0268 QCOMPARE(issue5->message(), QString("")); 0269 QCOMPARE(issue5->checker(), issue->checker()); 0270 0271 const Issue* issue6 = findIssue(&analysisResults, "license", 0272 "severalIssuesSeveralCheckers.cpp", -1); 0273 QVERIFY(issue6); 0274 QCOMPARE(issue6->message(), QString("missing license")); 0275 QCOMPARE(issue6->checker()->description(), 0276 QString("Check for an acceptable license")); 0277 QVERIFY(issue6->checker()->explanation().startsWith( 0278 "Each source file must contain a license")); 0279 QCOMPARE(issue6->checker()->fileType(), QString("c++")); 0280 QVERIFY(!issue6->checker()->isExtra()); 0281 0282 const Issue* issue7 = findIssue(&analysisResults, "validate", 0283 "subdirectory/singleIssue.desktop", -1); 0284 QVERIFY(issue7); 0285 QCOMPARE(issue7->message(), QString("required key \"Type\" in group \"Desktop Entry\" is not present")); 0286 QCOMPARE(issue7->checker()->description(), 0287 QString("Validates desktop files using 'desktop-file-validate'")); 0288 QVERIFY(issue7->checker()->explanation().startsWith( 0289 "Please make sure your .desktop files conform to the freedesktop.org")); 0290 QCOMPARE(issue7->checker()->fileType(), QString("desktop")); 0291 QVERIFY(!issue7->checker()->isExtra()); 0292 0293 const Issue* issue8 = findIssue(&analysisResults, "doublequote_chars", 0294 QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"), 8); 0295 QVERIFY(issue8); 0296 QCOMPARE(issue8->message(), QString("")); 0297 QCOMPARE(issue8->checker(), issue->checker()); 0298 0299 const Issue* issue9 = findIssue(&analysisResults, "doublequote_chars", 0300 ".singleIssueHiddenUnixFileName.cpp", 8); 0301 QVERIFY(issue9); 0302 QCOMPARE(issue9->message(), QString("")); 0303 QCOMPARE(issue9->checker(), issue->checker()); 0304 0305 const Issue* issue10 = findIssue(&analysisResults, "license", 0306 "subdirectory/severalIssuesSeveralCheckers.qml", -1); 0307 QVERIFY(issue10); 0308 QCOMPARE(issue10->message(), QString("missing license")); 0309 QCOMPARE(issue10->checker()->description(), 0310 QString("Check for an acceptable license")); 0311 QVERIFY(issue10->checker()->explanation().startsWith( 0312 "Each source file must contain a license")); 0313 QCOMPARE(issue10->checker()->fileType(), QString("qml")); 0314 QVERIFY(!issue10->checker()->isExtra()); 0315 0316 //Six signals should have been emitted: one for the start, one for the 0317 //finish, and one for each checker run. 0318 QCOMPARE(showProgressSpy.count(), 6); 0319 0320 //First signal is the 0% 0321 //First parameter is the AnalysisProgressParser itself 0322 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 0323 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 0324 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 0325 0326 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 25); 0327 QCOMPARE(showProgressSpy.at(2).at(3).toInt(), 50); 0328 QCOMPARE(showProgressSpy.at(3).at(3).toInt(), 75); 0329 QCOMPARE(showProgressSpy.at(4).at(3).toInt(), 99); 0330 QCOMPARE(showProgressSpy.at(5).at(3).toInt(), 100); 0331 } 0332 0333 void AnalysisJobTest::testRunExtraCheckers() { 0334 AnalysisJob analysisJob; 0335 analysisJob.setAutoDelete(false); 0336 0337 QList<const Checker*> availableCheckers = getAvailableCheckers(); 0338 0339 AnalysisParameters analysisParameters; 0340 analysisParameters.initializeCheckers(availableCheckers); 0341 0342 QList<const Checker*> checkersToRun = analysisParameters.checkersToRun(); 0343 foreach (const Checker* checker, availableCheckers) { 0344 if (checker->fileType() == "c++" && checker->name() == "style" && checker->isExtra()) { 0345 checkersToRun.append(checker); 0346 } 0347 } 0348 0349 analysisParameters.setCheckersToRun(checkersToRun); 0350 analysisParameters.setFilesAndDirectories(QStringList() << m_examplesPath); 0351 analysisJob.addAnalysisParameters(&analysisParameters); 0352 0353 AnalysisResults analysisResults; 0354 analysisJob.setAnalysisResults(&analysisResults); 0355 0356 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0357 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0358 0359 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0360 0361 analysisJob.start(); 0362 0363 resultSpy.waitForSignal(); 0364 0365 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0366 QCOMPARE(analysisResults.issues().count(), 15); 0367 0368 //To prevent test failures due to the order of the issues, each issue is 0369 //searched in the results instead of using a specific index 0370 const Issue* issue = findIssue(&analysisResults, "doublequote_chars", 0371 "singleIssue.cpp", 8); 0372 QVERIFY(issue); 0373 QCOMPARE(issue->message(), QString("")); 0374 QCOMPARE(issue->checker()->description(), 0375 QString("Check single-char QString operations for efficiency")); 0376 QVERIFY(issue->checker()->explanation().startsWith( 0377 "Adding single characters to a QString is faster")); 0378 QCOMPARE(issue->checker()->fileType(), QString("c++")); 0379 QVERIFY(!issue->checker()->isExtra()); 0380 0381 const Issue* issue2 = findIssue(&analysisResults, "doublequote_chars", 0382 "severalIssuesSingleChecker.cpp", 8); 0383 QVERIFY(issue2); 0384 QCOMPARE(issue2->message(), QString("")); 0385 QCOMPARE(issue2->checker(), issue->checker()); 0386 0387 const Issue* issue3 = findIssue(&analysisResults, "doublequote_chars", 0388 "severalIssuesSingleChecker.cpp", 10); 0389 QVERIFY(issue3); 0390 QCOMPARE(issue3->message(), QString("")); 0391 QCOMPARE(issue3->checker(), issue->checker()); 0392 0393 const Issue* issue4 = findIssue(&analysisResults, "doublequote_chars", 0394 "severalIssuesSeveralCheckers.cpp", 8); 0395 QVERIFY(issue4); 0396 QCOMPARE(issue4->message(), QString("")); 0397 QCOMPARE(issue4->checker(), issue->checker()); 0398 0399 const Issue* issue5 = findIssue(&analysisResults, "doublequote_chars", 0400 "severalIssuesSeveralCheckers.cpp", 12); 0401 QVERIFY(issue5); 0402 QCOMPARE(issue5->message(), QString("")); 0403 QCOMPARE(issue5->checker(), issue->checker()); 0404 0405 const Issue* issue6 = findIssue(&analysisResults, "license", 0406 "severalIssuesSeveralCheckers.cpp", -1); 0407 QVERIFY(issue6); 0408 QCOMPARE(issue6->message(), QString("missing license")); 0409 QCOMPARE(issue6->checker()->description(), 0410 QString("Check for an acceptable license")); 0411 QVERIFY(issue6->checker()->explanation().startsWith( 0412 "Each source file must contain a license")); 0413 QCOMPARE(issue6->checker()->fileType(), QString("c++")); 0414 QVERIFY(!issue6->checker()->isExtra()); 0415 0416 const Issue* issue7 = findIssue(&analysisResults, "spelling", 0417 "severalIssuesSeveralCheckers.cpp", 6); 0418 QVERIFY(issue7); 0419 QCOMPARE(issue7->message(), QString("begining")); //krazy:exclude=spelling 0420 QCOMPARE(issue7->checker()->description(), 0421 QString("Check for spelling errors")); 0422 QVERIFY(issue7->checker()->explanation().startsWith( 0423 "Spelling errors in comments and strings should be fixed")); 0424 QCOMPARE(issue7->checker()->fileType(), QString("c++")); 0425 QVERIFY(!issue7->checker()->isExtra()); 0426 0427 const Issue* issue8 = findIssue(&analysisResults, "spelling", 0428 "severalIssuesSeveralCheckers.cpp", 10); 0429 QVERIFY(issue8); 0430 QCOMPARE(issue8->message(), QString("commiting")); //krazy:exclude=spelling 0431 QCOMPARE(issue8->checker(), issue7->checker()); 0432 0433 const Issue* issue9 = findIssue(&analysisResults, "spelling", 0434 "severalIssuesSeveralCheckers.cpp", 14); 0435 QVERIFY(issue9); 0436 QCOMPARE(issue9->message(), QString("labelling")); //krazy:exclude=spelling 0437 QCOMPARE(issue9->checker(), issue7->checker()); 0438 0439 const Issue* issue10 = findIssue(&analysisResults, "validate", 0440 "subdirectory/singleIssue.desktop", -1); 0441 QVERIFY(issue10); 0442 QCOMPARE(issue10->message(), QString("required key \"Type\" in group \"Desktop Entry\" is not present")); 0443 QCOMPARE(issue10->checker()->description(), 0444 QString("Validates desktop files using 'desktop-file-validate'")); 0445 QVERIFY(issue10->checker()->explanation().startsWith( 0446 "Please make sure your .desktop files conform to the freedesktop.org")); 0447 QCOMPARE(issue10->checker()->fileType(), QString("desktop")); 0448 QVERIFY(!issue10->checker()->isExtra()); 0449 0450 const Issue* issue11 = findIssue(&analysisResults, "doublequote_chars", 0451 QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"), 8); 0452 QVERIFY(issue11); 0453 QCOMPARE(issue11->message(), QString("")); 0454 QCOMPARE(issue11->checker(), issue->checker()); 0455 0456 const Issue* issue12 = findIssue(&analysisResults, "doublequote_chars", 0457 ".singleIssueHiddenUnixFileName.cpp", 8); 0458 QVERIFY(issue12); 0459 QCOMPARE(issue12->message(), QString("")); 0460 QCOMPARE(issue12->checker(), issue->checker()); 0461 0462 const Issue* issue13 = findIssue(&analysisResults, "style", 0463 "singleExtraIssue.cpp", 7); 0464 QVERIFY(issue13); 0465 QCOMPARE(issue13->message(), QString("Put 1 space before an asterisk or ampersand")); 0466 QCOMPARE(issue13->checker()->description(), 0467 QString("Check for adherence to a coding style")); 0468 QVERIFY(issue13->checker()->explanation().startsWith( 0469 "Please follow the coding style guidelines")); 0470 QCOMPARE(issue13->checker()->fileType(), QString("c++")); 0471 QVERIFY(issue13->checker()->isExtra()); 0472 0473 const Issue* issue14 = findIssue(&analysisResults, "license", 0474 "subdirectory/severalIssuesSeveralCheckers.qml", -1); 0475 QVERIFY(issue14); 0476 QCOMPARE(issue14->message(), QString("missing license")); 0477 QCOMPARE(issue14->checker()->description(), 0478 QString("Check for an acceptable license")); 0479 QVERIFY(issue14->checker()->explanation().startsWith( 0480 "Each source file must contain a license")); 0481 QCOMPARE(issue14->checker()->fileType(), QString("qml")); 0482 QVERIFY(!issue14->checker()->isExtra()); 0483 0484 const Issue* issue15 = findIssue(&analysisResults, "spelling", 0485 "subdirectory/severalIssuesSeveralCheckers.qml", 3); 0486 QVERIFY(issue15); 0487 QCOMPARE(issue15->message(), QString("occured")); //krazy:exclude=spelling 0488 QCOMPARE(issue15->checker()->description(), 0489 QString("Check for spelling errors")); 0490 QVERIFY(issue15->checker()->explanation().startsWith( 0491 "Spelling errors in comments and strings should be fixed")); 0492 QCOMPARE(issue15->checker()->fileType(), QString("qml")); 0493 QVERIFY(!issue15->checker()->isExtra()); 0494 0495 //At least nine signals should have been emitted: one for the start, one for 0496 //the finish, and one for each checker with issues. 0497 QVERIFY(showProgressSpy.count() >= 9); 0498 0499 //First signal is the 0% 0500 //First parameter is the AnalysisProgressParser itself 0501 QCOMPARE(showProgressSpy.first().at(1).toInt(), 0); 0502 QCOMPARE(showProgressSpy.first().at(2).toInt(), 100); 0503 QCOMPARE(showProgressSpy.first().at(3).toInt(), 0); 0504 0505 //Last signal is the 100% 0506 QCOMPARE(showProgressSpy.last().at(1).toInt(), 0); 0507 QCOMPARE(showProgressSpy.last().at(2).toInt(), 100); 0508 QCOMPARE(showProgressSpy.last().at(3).toInt(), 100); 0509 0510 //The second signal progress should be bigger than the start progress 0511 QVERIFY(showProgressSpy.at(1).at(3).toInt() > 0); 0512 0513 //The second to last signal shows a 99% progress, as it is emitted once all 0514 //the checkers have run. It is not a 100% progress, though, because parsing 0515 //progress is limited to 99%; 100% is only emitted when krazy2 has finished. 0516 QCOMPARE(showProgressSpy.at(showProgressSpy.count()-2).at(3).toInt(), 99); 0517 QVERIFY(showProgressSpy.at(showProgressSpy.count()-3).at(3).toInt() <= 99); 0518 } 0519 0520 void AnalysisJobTest::testRunExtraCheckersAndSubsetOfCheckers() { 0521 AnalysisJob analysisJob; 0522 analysisJob.setAutoDelete(false); 0523 0524 QList<const Checker*> availableCheckers = getAvailableCheckers(); 0525 0526 QList<const Checker*> checkersToRun; 0527 foreach (const Checker* checker, availableCheckers) { 0528 if ((checker->fileType() == "c++" && checker->name() == "license" && !checker->isExtra()) || 0529 (checker->fileType() == "qml" && checker->name() == "license" && !checker->isExtra()) || 0530 (checker->fileType() == "c++" && checker->name() == "style" && checker->isExtra())) { 0531 checkersToRun.append(checker); 0532 } 0533 } 0534 0535 AnalysisParameters analysisParameters; 0536 analysisParameters.initializeCheckers(availableCheckers); 0537 analysisParameters.setCheckersToRun(checkersToRun); 0538 analysisParameters.setFilesAndDirectories(QStringList() << m_examplesPath); 0539 analysisJob.addAnalysisParameters(&analysisParameters); 0540 0541 AnalysisResults analysisResults; 0542 analysisJob.setAnalysisResults(&analysisResults); 0543 0544 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0545 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0546 0547 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0548 0549 analysisJob.start(); 0550 0551 resultSpy.waitForSignal(); 0552 0553 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0554 QCOMPARE(analysisResults.issues().count(), 3); 0555 0556 //To prevent test failures due to the order of the issues, each issue is 0557 //searched in the results instead of using a specific index 0558 const Issue* issue1 = findIssue(&analysisResults, "license", 0559 "severalIssuesSeveralCheckers.cpp", -1); 0560 QVERIFY(issue1); 0561 QCOMPARE(issue1->message(), QString("missing license")); 0562 QCOMPARE(issue1->checker()->description(), 0563 QString("Check for an acceptable license")); 0564 QVERIFY(issue1->checker()->explanation().startsWith( 0565 "Each source file must contain a license")); 0566 QCOMPARE(issue1->checker()->fileType(), QString("c++")); 0567 QVERIFY(!issue1->checker()->isExtra()); 0568 0569 const Issue* issue2 = findIssue(&analysisResults, "style", 0570 "singleExtraIssue.cpp", 7); 0571 QVERIFY(issue2); 0572 QCOMPARE(issue2->message(), QString("Put 1 space before an asterisk or ampersand")); 0573 QCOMPARE(issue2->checker()->description(), 0574 QString("Check for adherence to a coding style")); 0575 QVERIFY(issue2->checker()->explanation().startsWith( 0576 "Please follow the coding style guidelines")); 0577 QCOMPARE(issue2->checker()->fileType(), QString("c++")); 0578 QVERIFY(issue2->checker()->isExtra()); 0579 0580 const Issue* issue3 = findIssue(&analysisResults, "license", 0581 "subdirectory/severalIssuesSeveralCheckers.qml", -1); 0582 QVERIFY(issue3); 0583 QCOMPARE(issue3->message(), QString("missing license")); 0584 QCOMPARE(issue3->checker()->description(), 0585 QString("Check for an acceptable license")); 0586 QVERIFY(issue3->checker()->explanation().startsWith( 0587 "Each source file must contain a license")); 0588 QCOMPARE(issue3->checker()->fileType(), QString("qml")); 0589 QVERIFY(!issue3->checker()->isExtra()); 0590 0591 //Five signals should have been emitted: one for the start, one for the 0592 //finish, and one for each checker run. 0593 QCOMPARE(showProgressSpy.count(), 5); 0594 0595 //First signal is the 0% 0596 //First parameter is the AnalysisProgressParser itself 0597 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 0598 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 0599 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 0600 0601 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 33); 0602 QCOMPARE(showProgressSpy.at(2).at(3).toInt(), 66); 0603 QCOMPARE(showProgressSpy.at(3).at(3).toInt(), 99); 0604 QCOMPARE(showProgressSpy.at(4).at(3).toInt(), 100); 0605 } 0606 0607 void AnalysisJobTest::testRunCheckerWithDuplicatedNamesAndSpecificFileTypes() { 0608 AnalysisJob analysisJob; 0609 analysisJob.setAutoDelete(false); 0610 0611 QList<const Checker*> availableCheckers; 0612 0613 auto cppLicenseChecker = new Checker(); 0614 cppLicenseChecker->setFileType("c++"); 0615 cppLicenseChecker->setName("license"); 0616 cppLicenseChecker->setDescription("Check for an acceptable license"); 0617 cppLicenseChecker->setExplanation("Each source file must contain a license " 0618 "or a reference to a license which states..."); 0619 availableCheckers.append(cppLicenseChecker); 0620 0621 auto qmlSpellingChecker = new Checker(); 0622 qmlSpellingChecker->setFileType("qml"); 0623 qmlSpellingChecker->setName("spelling"); 0624 qmlSpellingChecker->setDescription("Check for spelling errors"); 0625 qmlSpellingChecker->setExplanation("Spelling errors in comments and strings " 0626 "should be fixed as they may show up later..."); 0627 availableCheckers.append(qmlSpellingChecker); 0628 0629 QList<const Checker*> checkersToRun; 0630 checkersToRun.append(cppLicenseChecker); 0631 checkersToRun.append(qmlSpellingChecker); 0632 0633 //Both files have spelling and license issues, although different file types 0634 QStringList filesToAnalyze; 0635 filesToAnalyze << m_examplesPath + "severalIssuesSeveralCheckers.cpp"; 0636 filesToAnalyze << m_examplesPath + "subdirectory/severalIssuesSeveralCheckers.qml"; 0637 0638 AnalysisParameters analysisParameters; 0639 analysisParameters.initializeCheckers(availableCheckers); 0640 analysisParameters.setCheckersToRun(checkersToRun); 0641 analysisParameters.setFilesAndDirectories(filesToAnalyze); 0642 analysisJob.addAnalysisParameters(&analysisParameters); 0643 0644 AnalysisResults analysisResults; 0645 analysisJob.setAnalysisResults(&analysisResults); 0646 0647 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0648 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0649 0650 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0651 0652 analysisJob.start(); 0653 0654 resultSpy.waitForSignal(); 0655 0656 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0657 QCOMPARE(analysisResults.issues().count(), 2); 0658 0659 //To prevent test failures due to the order of the issues, each issue is 0660 //searched in the results instead of using a specific index 0661 const Issue* issue = findIssue(&analysisResults, "license", 0662 "severalIssuesSeveralCheckers.cpp", -1); 0663 QVERIFY(issue); 0664 QCOMPARE(issue->message(), QString("missing license")); 0665 QCOMPARE(issue->checker()->description(), 0666 QString("Check for an acceptable license")); 0667 QVERIFY(issue->checker()->explanation().startsWith( 0668 "Each source file must contain a license")); 0669 QCOMPARE(issue->checker()->fileType(), QString("c++")); 0670 QVERIFY(!issue->checker()->isExtra()); 0671 0672 const Issue* issue2 = findIssue(&analysisResults, "spelling", 0673 "subdirectory/severalIssuesSeveralCheckers.qml", 3); 0674 QVERIFY(issue2); 0675 QCOMPARE(issue2->message(), QString("occured")); //krazy:exclude=spelling 0676 QCOMPARE(issue2->checker()->description(), 0677 QString("Check for spelling errors")); 0678 QVERIFY(issue2->checker()->explanation().startsWith( 0679 "Spelling errors in comments and strings should be fixed")); 0680 QCOMPARE(issue2->checker()->fileType(), QString("qml")); 0681 QVERIFY(!issue2->checker()->isExtra()); 0682 0683 //Four signals should have been emitted: one for the start, one for the 0684 //finish, and one for each checker run. 0685 QCOMPARE(showProgressSpy.count(), 4); 0686 0687 //First signal is the 0% 0688 //First parameter is the AnalysisProgressParser itself 0689 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 0690 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 0691 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 0692 0693 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 50); 0694 QCOMPARE(showProgressSpy.at(2).at(3).toInt(), 99); 0695 QCOMPARE(showProgressSpy.at(3).at(3).toInt(), 100); 0696 } 0697 0698 void AnalysisJobTest::testRunCheckersWithNoFiles() { 0699 AnalysisJob analysisJob; 0700 analysisJob.setAutoDelete(false); 0701 0702 QList<const Checker*> availableCheckers; 0703 0704 auto doubleQuoteCharsChecker = new Checker(); 0705 doubleQuoteCharsChecker->setFileType("c++"); 0706 doubleQuoteCharsChecker->setName("doublequote_chars"); 0707 doubleQuoteCharsChecker->setDescription("Check single-char QString operations for efficiency"); 0708 doubleQuoteCharsChecker->setExplanation("Adding single characters to a QString " 0709 "is faster if the characters are QChars..."); 0710 availableCheckers.append(doubleQuoteCharsChecker); 0711 0712 auto licenseChecker = new Checker(); 0713 licenseChecker->setFileType("c++"); 0714 licenseChecker->setName("license"); 0715 licenseChecker->setDescription("Check for an acceptable license"); 0716 licenseChecker->setExplanation("Each source file must contain a license " 0717 "or a reference to a license which states..."); 0718 availableCheckers.append(licenseChecker); 0719 0720 auto spellingChecker = new Checker(); 0721 spellingChecker->setFileType("c++"); 0722 spellingChecker->setName("spelling"); 0723 spellingChecker->setDescription("Check for spelling errors"); 0724 spellingChecker->setExplanation("Spelling errors in comments and strings " 0725 "should be fixed as they may show up later..."); 0726 availableCheckers.append(spellingChecker); 0727 0728 auto validateChecker = new Checker(); 0729 validateChecker->setFileType("desktop"); 0730 validateChecker->setName("validate"); 0731 validateChecker->setDescription("Validates desktop files using 'desktop-file-validate'"); 0732 validateChecker->setExplanation("Please make sure your .desktop files conform " 0733 "to the freedesktop.org standard. See the spec..."); 0734 availableCheckers.append(validateChecker); 0735 0736 auto qmlLicenseChecker = new Checker(); 0737 qmlLicenseChecker->setFileType("qml"); 0738 qmlLicenseChecker->setName("license"); 0739 qmlLicenseChecker->setDescription("Check for an acceptable license"); 0740 qmlLicenseChecker->setExplanation("Each source file must contain a license " 0741 "or a reference to a license which states..."); 0742 availableCheckers.append(qmlLicenseChecker); 0743 0744 //Do not set spelling checker 0745 QList<const Checker*> checkersToRun; 0746 checkersToRun.append(doubleQuoteCharsChecker); 0747 checkersToRun.append(licenseChecker); 0748 checkersToRun.append(validateChecker); 0749 checkersToRun.append(qmlLicenseChecker); 0750 0751 AnalysisParameters analysisParameters; 0752 analysisParameters.initializeCheckers(availableCheckers); 0753 analysisParameters.setCheckersToRun(checkersToRun); 0754 analysisJob.addAnalysisParameters(&analysisParameters); 0755 0756 AnalysisResults analysisResults; 0757 analysisJob.setAnalysisResults(&analysisResults); 0758 0759 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0760 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0761 0762 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0763 0764 analysisJob.start(); 0765 0766 resultSpy.waitForSignal(); 0767 0768 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0769 QCOMPARE(analysisResults.issues().count(), 0); 0770 0771 //Two signals should have been emitted: one for the start and one for the 0772 //finish. 0773 QCOMPARE(showProgressSpy.count(), 2); 0774 0775 //First signal is the 0% 0776 //First parameter is the AnalysisProgressParser itself 0777 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 0778 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 0779 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 0780 0781 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 100); 0782 } 0783 0784 void AnalysisJobTest::testRunSeveralAnalysisParameters() { 0785 AnalysisJob analysisJob; 0786 analysisJob.setAutoDelete(false); 0787 0788 //First analysis parameters should give one issue for each checker (the 0789 //first and second checker are named like other checkers with issues, 0790 //although they should not be run) 0791 QList<const Checker*> availableCheckers = getAvailableCheckers(); 0792 0793 QList<const Checker*> checkersToRun; 0794 foreach (const Checker* checker, availableCheckers) { 0795 if ((checker->fileType() == "c++" && checker->name() == "license" && !checker->isExtra()) || 0796 (checker->fileType() == "qml" && checker->name() == "spelling" && !checker->isExtra()) || 0797 (checker->fileType() == "c++" && checker->name() == "style" && checker->isExtra())) { 0798 checkersToRun.append(checker); 0799 } 0800 } 0801 0802 QStringList fileNames; 0803 fileNames << m_examplesPath; 0804 0805 AnalysisParameters analysisParameters1; 0806 analysisParameters1.initializeCheckers(availableCheckers); 0807 analysisParameters1.setCheckersToRun(checkersToRun); 0808 analysisParameters1.setFilesAndDirectories(fileNames); 0809 analysisJob.addAnalysisParameters(&analysisParameters1); 0810 0811 //Second analysis parameters should give one issue for the checker 0812 QMutableListIterator<const Checker*> it(availableCheckers); 0813 while (it.hasNext()) { 0814 it.setValue(new Checker(*it.next())); 0815 } 0816 0817 checkersToRun.clear(); 0818 foreach (const Checker* checker, availableCheckers) { 0819 if ((checker->fileType() == "c++" && checker->name() == "doublequote_chars" && !checker->isExtra())) { 0820 checkersToRun.append(checker); 0821 } 0822 } 0823 0824 fileNames.clear(); 0825 fileNames << m_examplesPath + "singleIssue.cpp"; 0826 0827 AnalysisParameters analysisParameters2; 0828 analysisParameters2.initializeCheckers(availableCheckers); 0829 analysisParameters2.setCheckersToRun(checkersToRun); 0830 analysisParameters2.setFilesAndDirectories(fileNames); 0831 analysisJob.addAnalysisParameters(&analysisParameters2); 0832 0833 //Third analysis parameters should give three issues for the first checker 0834 //(although one is repeated), no issues for the second checker, and the 0835 //third one should not be run, as it is not compatible with any analyzed 0836 //file 0837 it = QMutableListIterator<const Checker*>(availableCheckers); 0838 while (it.hasNext()) { 0839 it.setValue(new Checker(*it.next())); 0840 } 0841 0842 checkersToRun.clear(); 0843 foreach (const Checker* checker, availableCheckers) { 0844 if ((checker->fileType() == "c++" && checker->name() == "doublequote_chars" && !checker->isExtra()) || 0845 (checker->fileType() == "c++" && checker->name() == "license" && !checker->isExtra()) || 0846 (checker->fileType() == "desktop" && checker->name() == "validate" && !checker->isExtra())) { 0847 checkersToRun.append(checker); 0848 } 0849 } 0850 0851 fileNames.clear(); 0852 fileNames << m_examplesPath + "singleIssue.cpp"; 0853 fileNames << m_examplesPath + "severalIssuesSingleChecker.cpp"; 0854 fileNames << m_examplesPath + "subdirectory/severalIssuesSeveralCheckers.qml"; 0855 0856 AnalysisParameters analysisParameters3; 0857 analysisParameters3.initializeCheckers(availableCheckers); 0858 analysisParameters3.setCheckersToRun(checkersToRun); 0859 analysisParameters3.setFilesAndDirectories(fileNames); 0860 analysisJob.addAnalysisParameters(&analysisParameters3); 0861 0862 AnalysisResults analysisResults; 0863 analysisJob.setAnalysisResults(&analysisResults); 0864 0865 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 0866 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 0867 0868 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 0869 0870 analysisJob.start(); 0871 0872 resultSpy.waitForSignal(); 0873 0874 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 0875 QCOMPARE(analysisResults.issues().count(), 6); 0876 0877 //To prevent test failures due to the order of the issues, each issue is 0878 //searched in the results instead of using a specific index 0879 const Issue* issue1 = findIssue(&analysisResults, "license", 0880 "severalIssuesSeveralCheckers.cpp", -1); 0881 QVERIFY(issue1); 0882 QCOMPARE(issue1->message(), QString("missing license")); 0883 QCOMPARE(issue1->checker()->description(), 0884 QString("Check for an acceptable license")); 0885 QVERIFY(issue1->checker()->explanation().startsWith( 0886 "Each source file must contain a license")); 0887 QCOMPARE(issue1->checker()->fileType(), QString("c++")); 0888 QVERIFY(!issue1->checker()->isExtra()); 0889 0890 const Issue* issue2 = findIssue(&analysisResults, "spelling", 0891 "subdirectory/severalIssuesSeveralCheckers.qml", 3); 0892 QVERIFY(issue2); 0893 QCOMPARE(issue2->message(), QString("occured")); //krazy:exclude=spelling 0894 QCOMPARE(issue2->checker()->description(), 0895 QString("Check for spelling errors")); 0896 QVERIFY(issue2->checker()->explanation().startsWith( 0897 "Spelling errors in comments and strings should be fixed")); 0898 QCOMPARE(issue2->checker()->fileType(), QString("qml")); 0899 QVERIFY(!issue2->checker()->isExtra()); 0900 0901 const Issue* issue3 = findIssue(&analysisResults, "style", 0902 "singleExtraIssue.cpp", 7); 0903 QVERIFY(issue3); 0904 QCOMPARE(issue3->message(), QString("Put 1 space before an asterisk or ampersand")); 0905 QCOMPARE(issue3->checker()->description(), 0906 QString("Check for adherence to a coding style")); 0907 QVERIFY(issue3->checker()->explanation().startsWith( 0908 "Please follow the coding style guidelines")); 0909 QCOMPARE(issue3->checker()->fileType(), QString("c++")); 0910 QVERIFY(issue3->checker()->isExtra()); 0911 0912 const Issue* issue4 = findIssue(&analysisResults, "doublequote_chars", 0913 "singleIssue.cpp", 8); 0914 QVERIFY(issue4); 0915 QCOMPARE(issue4->message(), QString("")); 0916 QCOMPARE(issue4->checker()->description(), 0917 QString("Check single-char QString operations for efficiency")); 0918 QVERIFY(issue4->checker()->explanation().startsWith( 0919 "Adding single characters to a QString is faster")); 0920 QCOMPARE(issue4->checker()->fileType(), QString("c++")); 0921 QVERIFY(!issue4->checker()->isExtra()); 0922 0923 const Issue* issue5 = findIssue(&analysisResults, "doublequote_chars", 0924 "severalIssuesSingleChecker.cpp", 8); 0925 QVERIFY(issue5); 0926 QCOMPARE(issue5->message(), QString("")); 0927 QCOMPARE(issue5->checker(), issue4->checker()); 0928 0929 const Issue* issue6 = findIssue(&analysisResults, "doublequote_chars", 0930 "severalIssuesSingleChecker.cpp", 10); 0931 QVERIFY(issue6); 0932 QCOMPARE(issue6->message(), QString("")); 0933 QCOMPARE(issue6->checker(), issue4->checker()); 0934 0935 //Eight signals should have been emitted: one for the start, one for the 0936 //finish, and one for each checker run (desktop/validate was not run as it 0937 //was not compatible with the given files, and c++/doublequote_chars and 0938 //c++/license were both executed twice). 0939 QCOMPARE(showProgressSpy.count(), 8); 0940 0941 //First signal is the 0% 0942 //First parameter is the AnalysisProgressParser itself 0943 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 0944 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 0945 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 0946 0947 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 16); 0948 QCOMPARE(showProgressSpy.at(2).at(3).toInt(), 33); 0949 QCOMPARE(showProgressSpy.at(3).at(3).toInt(), 50); 0950 QCOMPARE(showProgressSpy.at(4).at(3).toInt(), 66); 0951 QCOMPARE(showProgressSpy.at(5).at(3).toInt(), 83); 0952 QCOMPARE(showProgressSpy.at(6).at(3).toInt(), 99); 0953 QCOMPARE(showProgressSpy.at(7).at(3).toInt(), 100); 0954 } 0955 0956 void AnalysisJobTest::testRunSeveralAnalysisParametersSomeOfThemWithoutFiles() { 0957 AnalysisJob analysisJob; 0958 analysisJob.setAutoDelete(false); 0959 0960 //First analysis parameters should give no issues (as there are no files) 0961 QList<const Checker*> availableCheckers = getAvailableCheckers(); 0962 0963 QList<const Checker*> checkersToRun; 0964 foreach (const Checker* checker, availableCheckers) { 0965 checkersToRun.append(checker); 0966 } 0967 0968 AnalysisParameters analysisParameters1; 0969 analysisParameters1.initializeCheckers(availableCheckers); 0970 analysisParameters1.setCheckersToRun(checkersToRun); 0971 analysisJob.addAnalysisParameters(&analysisParameters1); 0972 0973 //Second analysis parameters should give one issue for each checker (the 0974 //first and second checker are named like other checkers with issues, 0975 //although they should not be run) 0976 QMutableListIterator<const Checker*> it(availableCheckers); 0977 while (it.hasNext()) { 0978 it.setValue(new Checker(*it.next())); 0979 } 0980 0981 checkersToRun.clear(); 0982 foreach (const Checker* checker, availableCheckers) { 0983 if ((checker->fileType() == "c++" && checker->name() == "license" && !checker->isExtra()) || 0984 (checker->fileType() == "qml" && checker->name() == "spelling" && !checker->isExtra()) || 0985 (checker->fileType() == "c++" && checker->name() == "style" && checker->isExtra())) { 0986 checkersToRun.append(checker); 0987 } 0988 } 0989 0990 QStringList fileNames; 0991 fileNames << m_examplesPath; 0992 0993 AnalysisParameters analysisParameters2; 0994 analysisParameters2.initializeCheckers(availableCheckers); 0995 analysisParameters2.setCheckersToRun(checkersToRun); 0996 analysisParameters2.setFilesAndDirectories(fileNames); 0997 analysisJob.addAnalysisParameters(&analysisParameters2); 0998 0999 //Third analysis parameters should give one issue for the checker 1000 it = QMutableListIterator<const Checker*>(availableCheckers); 1001 while (it.hasNext()) { 1002 it.setValue(new Checker(*it.next())); 1003 } 1004 1005 checkersToRun.clear(); 1006 foreach (const Checker* checker, availableCheckers) { 1007 if ((checker->fileType() == "c++" && checker->name() == "doublequote_chars" && !checker->isExtra())) { 1008 checkersToRun.append(checker); 1009 } 1010 } 1011 1012 fileNames.clear(); 1013 fileNames << m_examplesPath + "singleIssue.cpp"; 1014 1015 AnalysisParameters analysisParameters3; 1016 analysisParameters3.initializeCheckers(availableCheckers); 1017 analysisParameters3.setCheckersToRun(checkersToRun); 1018 analysisParameters3.setFilesAndDirectories(fileNames); 1019 analysisJob.addAnalysisParameters(&analysisParameters3); 1020 1021 //Fourth analysis parameters should give no issues (as there are no files) 1022 it = QMutableListIterator<const Checker*>(availableCheckers); 1023 while (it.hasNext()) { 1024 it.setValue(new Checker(*it.next())); 1025 } 1026 1027 checkersToRun.clear(); 1028 foreach (const Checker* checker, availableCheckers) { 1029 checkersToRun.append(checker); 1030 } 1031 1032 AnalysisParameters analysisParameters4; 1033 analysisParameters4.initializeCheckers(availableCheckers); 1034 analysisParameters4.setCheckersToRun(checkersToRun); 1035 analysisJob.addAnalysisParameters(&analysisParameters4); 1036 1037 //Fifth analysis parameters should give no issues (as there are no files) 1038 it = QMutableListIterator<const Checker*>(availableCheckers); 1039 while (it.hasNext()) { 1040 it.setValue(new Checker(*it.next())); 1041 } 1042 1043 checkersToRun.clear(); 1044 foreach (const Checker* checker, availableCheckers) { 1045 checkersToRun.append(checker); 1046 } 1047 1048 AnalysisParameters analysisParameters5; 1049 analysisParameters5.initializeCheckers(availableCheckers); 1050 analysisParameters5.setCheckersToRun(checkersToRun); 1051 analysisJob.addAnalysisParameters(&analysisParameters5); 1052 1053 //Sixth analysis parameters should give three issues for the first checker 1054 //(although one is repeated), no issues for the second checker, and the 1055 //third one should not be run, as it is not compatible with any analyzed 1056 //file 1057 it = QMutableListIterator<const Checker*>(availableCheckers); 1058 while (it.hasNext()) { 1059 it.setValue(new Checker(*it.next())); 1060 } 1061 1062 checkersToRun.clear(); 1063 foreach (const Checker* checker, availableCheckers) { 1064 if ((checker->fileType() == "c++" && checker->name() == "doublequote_chars" && !checker->isExtra()) || 1065 (checker->fileType() == "c++" && checker->name() == "license" && !checker->isExtra()) || 1066 (checker->fileType() == "desktop" && checker->name() == "validate" && !checker->isExtra())) { 1067 checkersToRun.append(checker); 1068 } 1069 } 1070 1071 fileNames.clear(); 1072 fileNames << m_examplesPath + "singleIssue.cpp"; 1073 fileNames << m_examplesPath + "severalIssuesSingleChecker.cpp"; 1074 fileNames << m_examplesPath + "subdirectory/severalIssuesSeveralCheckers.qml"; 1075 1076 AnalysisParameters analysisParameters6; 1077 analysisParameters6.initializeCheckers(availableCheckers); 1078 analysisParameters6.setCheckersToRun(checkersToRun); 1079 analysisParameters6.setFilesAndDirectories(fileNames); 1080 analysisJob.addAnalysisParameters(&analysisParameters6); 1081 1082 //Seventh analysis parameters should give no issues (as there are no files) 1083 it = QMutableListIterator<const Checker*>(availableCheckers); 1084 while (it.hasNext()) { 1085 it.setValue(new Checker(*it.next())); 1086 } 1087 1088 checkersToRun.clear(); 1089 foreach (const Checker* checker, availableCheckers) { 1090 checkersToRun.append(checker); 1091 } 1092 1093 AnalysisParameters analysisParameters7; 1094 analysisParameters7.initializeCheckers(availableCheckers); 1095 analysisParameters7.setCheckersToRun(checkersToRun); 1096 analysisJob.addAnalysisParameters(&analysisParameters7); 1097 1098 AnalysisResults analysisResults; 1099 analysisJob.setAnalysisResults(&analysisResults); 1100 1101 QSignalSpy showProgressSpy(analysisJob.findChild<AnalysisProgressParser*>(), 1102 SIGNAL(showProgress(KDevelop::IStatus*,int,int,int))); 1103 1104 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 1105 1106 analysisJob.start(); 1107 1108 resultSpy.waitForSignal(); 1109 1110 QCOMPARE(analysisJob.error(), (int)KJob::NoError); 1111 QCOMPARE(analysisResults.issues().count(), 6); 1112 1113 //To prevent test failures due to the order of the issues, each issue is 1114 //searched in the results instead of using a specific index 1115 const Issue* issue1 = findIssue(&analysisResults, "license", 1116 "severalIssuesSeveralCheckers.cpp", -1); 1117 QVERIFY(issue1); 1118 QCOMPARE(issue1->message(), QString("missing license")); 1119 QCOMPARE(issue1->checker()->description(), 1120 QString("Check for an acceptable license")); 1121 QVERIFY(issue1->checker()->explanation().startsWith( 1122 "Each source file must contain a license")); 1123 QCOMPARE(issue1->checker()->fileType(), QString("c++")); 1124 QVERIFY(!issue1->checker()->isExtra()); 1125 1126 const Issue* issue2 = findIssue(&analysisResults, "spelling", 1127 "subdirectory/severalIssuesSeveralCheckers.qml", 3); 1128 QVERIFY(issue2); 1129 QCOMPARE(issue2->message(), QString("occured")); //krazy:exclude=spelling 1130 QCOMPARE(issue2->checker()->description(), 1131 QString("Check for spelling errors")); 1132 QVERIFY(issue2->checker()->explanation().startsWith( 1133 "Spelling errors in comments and strings should be fixed")); 1134 QCOMPARE(issue2->checker()->fileType(), QString("qml")); 1135 QVERIFY(!issue2->checker()->isExtra()); 1136 1137 const Issue* issue3 = findIssue(&analysisResults, "style", 1138 "singleExtraIssue.cpp", 7); 1139 QVERIFY(issue3); 1140 QCOMPARE(issue3->message(), QString("Put 1 space before an asterisk or ampersand")); 1141 QCOMPARE(issue3->checker()->description(), 1142 QString("Check for adherence to a coding style")); 1143 QVERIFY(issue3->checker()->explanation().startsWith( 1144 "Please follow the coding style guidelines")); 1145 QCOMPARE(issue3->checker()->fileType(), QString("c++")); 1146 QVERIFY(issue3->checker()->isExtra()); 1147 1148 const Issue* issue4 = findIssue(&analysisResults, "doublequote_chars", 1149 "singleIssue.cpp", 8); 1150 QVERIFY(issue4); 1151 QCOMPARE(issue4->message(), QString("")); 1152 QCOMPARE(issue4->checker()->description(), 1153 QString("Check single-char QString operations for efficiency")); 1154 QVERIFY(issue4->checker()->explanation().startsWith( 1155 "Adding single characters to a QString is faster")); 1156 QCOMPARE(issue4->checker()->fileType(), QString("c++")); 1157 QVERIFY(!issue4->checker()->isExtra()); 1158 1159 const Issue* issue5 = findIssue(&analysisResults, "doublequote_chars", 1160 "severalIssuesSingleChecker.cpp", 8); 1161 QVERIFY(issue5); 1162 QCOMPARE(issue5->message(), QString("")); 1163 QCOMPARE(issue5->checker(), issue4->checker()); 1164 1165 const Issue* issue6 = findIssue(&analysisResults, "doublequote_chars", 1166 "severalIssuesSingleChecker.cpp", 10); 1167 QVERIFY(issue6); 1168 QCOMPARE(issue6->message(), QString("")); 1169 QCOMPARE(issue6->checker(), issue4->checker()); 1170 1171 //Eight signals should have been emitted: one for the start, one for the 1172 //finish, and one for each checker run (desktop/validate was not run as it 1173 //was not compatible with the given files, and c++/doublequote_chars and 1174 //c++/license were both executed twice). 1175 QCOMPARE(showProgressSpy.count(), 8); 1176 1177 //First signal is the 0% 1178 //First parameter is the AnalysisProgressParser itself 1179 QCOMPARE(showProgressSpy.at(0).at(1).toInt(), 0); 1180 QCOMPARE(showProgressSpy.at(0).at(2).toInt(), 100); 1181 QCOMPARE(showProgressSpy.at(0).at(3).toInt(), 0); 1182 1183 QCOMPARE(showProgressSpy.at(1).at(3).toInt(), 16); 1184 QCOMPARE(showProgressSpy.at(2).at(3).toInt(), 33); 1185 QCOMPARE(showProgressSpy.at(3).at(3).toInt(), 50); 1186 QCOMPARE(showProgressSpy.at(4).at(3).toInt(), 66); 1187 QCOMPARE(showProgressSpy.at(5).at(3).toInt(), 83); 1188 QCOMPARE(showProgressSpy.at(6).at(3).toInt(), 99); 1189 QCOMPARE(showProgressSpy.at(7).at(3).toInt(), 100); 1190 } 1191 1192 void AnalysisJobTest::testRunWithInvalidKrazy2ExecutablePath() { 1193 AnalysisJob analysisJob; 1194 analysisJob.setAutoDelete(false); 1195 1196 QList<const Checker*> availableCheckers; 1197 1198 auto doubleQuoteCharsChecker = new Checker(); 1199 doubleQuoteCharsChecker->setFileType("c++"); 1200 doubleQuoteCharsChecker->setName("doublequote_chars"); 1201 availableCheckers.append(doubleQuoteCharsChecker); 1202 1203 AnalysisParameters analysisParameters; 1204 analysisParameters.initializeCheckers(availableCheckers); 1205 analysisParameters.setFilesAndDirectories(QStringList() << m_examplesPath); 1206 analysisJob.addAnalysisParameters(&analysisParameters); 1207 1208 AnalysisResults analysisResults; 1209 analysisJob.setAnalysisResults(&analysisResults); 1210 1211 KConfigGroup krazy2Configuration = KSharedConfig::openConfig()->group("Krazy2"); 1212 krazy2Configuration.writeEntry("krazy2 Path", "invalid/krazy2/path"); 1213 1214 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 1215 1216 analysisJob.start(); 1217 1218 resultSpy.waitForSignal(); 1219 1220 QCOMPARE(analysisJob.error(), (int)KJob::UserDefinedError); 1221 QCOMPARE(analysisJob.errorString(), 1222 xi18nc("@info", "<para><command>krazy2</command> failed to start " 1223 "using the path" 1224 "(<filename>%1</filename>).</para>", "invalid/krazy2/path")); 1225 QCOMPARE(analysisResults.issues().count(), 0); 1226 } 1227 1228 void AnalysisJobTest::testKill() { 1229 AnalysisJob analysisJob; 1230 analysisJob.setAutoDelete(false); 1231 1232 QList<const Checker*> availableCheckers = getAvailableCheckers(); 1233 1234 AnalysisParameters analysisParameters; 1235 analysisParameters.initializeCheckers(availableCheckers); 1236 analysisParameters.setFilesAndDirectories(QStringList() << m_examplesPath); 1237 analysisJob.addAnalysisParameters(&analysisParameters); 1238 1239 AnalysisResults analysisResults; 1240 analysisJob.setAnalysisResults(&analysisResults); 1241 1242 SignalSpy resultSpy(&analysisJob, SIGNAL(result(KJob*))); 1243 1244 analysisJob.start(); 1245 1246 QTest::qWait(1000); 1247 1248 analysisJob.kill(KJob::EmitResult); 1249 1250 resultSpy.waitForSignal(); 1251 1252 QCOMPARE(analysisJob.error(), (int)KJob::KilledJobError); 1253 QCOMPARE(analysisResults.issues().count(), 0); 1254 } 1255 1256 ///////////////////////////////// Helpers ////////////////////////////////////// 1257 1258 bool AnalysisJobTest::examplesInSubdirectory() const { 1259 if (QFile(m_examplesPath + "singleIssue.cpp").exists() && 1260 QFile(m_examplesPath + "singleExtraIssue.cpp").exists() && 1261 QFile(m_examplesPath + QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp")).exists() && 1262 QFile(m_examplesPath + ".singleIssueHiddenUnixFileName.cpp").exists() && 1263 QFile(m_examplesPath + "severalIssuesSingleChecker.cpp").exists() && 1264 QFile(m_examplesPath + "severalIssuesSeveralCheckers.cpp").exists() && 1265 QFile(m_examplesPath + "severalIssuesSeveralCheckersUnknownFileType.dqq").exists() && 1266 QFile(m_examplesPath + "subdirectory/singleIssue.desktop").exists() && 1267 QFile(m_examplesPath + "subdirectory/severalIssuesSeveralCheckers.qml").exists()) { 1268 return true; 1269 } 1270 1271 return false; 1272 } 1273 1274 bool AnalysisJobTest::krazy2InPath() const { 1275 //QProcess::exec is not used, as the static method uses ForwardedChannels 1276 QProcess process; 1277 process.start("krazy2 --version"); 1278 process.waitForFinished(); 1279 1280 if (process.error() == QProcess::FailedToStart) { 1281 return false; 1282 } 1283 1284 return true; 1285 } 1286 1287 QList< const Checker* > AnalysisJobTest::getAvailableCheckers() const { 1288 KConfigGroup krazy2Configuration = KSharedConfig::openConfig()->group("Krazy2"); 1289 krazy2Configuration.writeEntry("krazy2 Path", "krazy2"); 1290 1291 QList<const Checker*> availableCheckers; 1292 1293 CheckerListJob checkerListJob; 1294 checkerListJob.setAutoDelete(false); 1295 checkerListJob.setCheckerList(&availableCheckers); 1296 1297 SignalSpy checkerListResultSpy(&checkerListJob, SIGNAL(result(KJob*))); 1298 checkerListJob.start(); 1299 checkerListResultSpy.waitForSignal(); 1300 1301 return availableCheckers; 1302 } 1303 1304 const Issue* AnalysisJobTest::findIssue(const AnalysisResults* analysisResults, 1305 const QString& checkerName, 1306 const QString& exampleFileName, int line) const { 1307 QString fileName = m_examplesPath + exampleFileName; 1308 foreach (const Issue* issue, analysisResults->issues()) { 1309 if (issue->checker()->name() == checkerName && 1310 issue->fileName() == fileName && 1311 issue->line() == line) { 1312 return issue; 1313 } 1314 } 1315 1316 return nullptr; 1317 } 1318 1319 QTEST_GUILESS_MAIN(AnalysisJobTest) 1320 1321 #include "analysisjobtest.moc"