File indexing completed on 2024-05-12 04:39:29
0001 /* 0002 SPDX-FileCopyrightText: 2010 Esben Mose Hansen <kde@mosehansen.dk> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "test_cmakemanager.h" 0008 #include "testhelpers.h" 0009 #include "cmakemodelitems.h" 0010 #include "cmakeutils.h" 0011 #include "cmakeimportjsonjob.h" 0012 0013 #include <QLoggingCategory> 0014 #include <QTemporaryFile> 0015 0016 #include <interfaces/icore.h> 0017 #include <interfaces/itestsuite.h> 0018 #include <interfaces/itestcontroller.h> 0019 #include <project/interfaces/ibuildsystemmanager.h> 0020 #include <project/abstractfilemanagerplugin.h> 0021 #include <tests/autotestshell.h> 0022 #include <tests/testproject.h> 0023 #include <tests/testcore.h> 0024 #include <testing/ctestsuite.h> 0025 0026 QTEST_MAIN(TestCMakeManager) 0027 0028 using namespace KDevelop; 0029 0030 void TestCMakeManager::initTestCase() 0031 { 0032 QLoggingCategory::setFilterRules("*.debug=false\nkdevplatform.outputview.debug=true\n" 0033 "kdevelop.plugins.cmake.debug=true\ndefault.debug=true\n"); 0034 0035 AutoTestShell::init({"KDevCMakeManager", "KDevCMakeBuilder", "KDevMakeBuilder", "KDevStandardOutputView"}); 0036 TestCore::initialize(); 0037 0038 cleanup(); 0039 } 0040 0041 void TestCMakeManager::cleanupTestCase() 0042 { 0043 TestCore::shutdown(); 0044 } 0045 0046 void TestCMakeManager::cleanup() 0047 { 0048 const auto projects = ICore::self()->projectController()->projects(); 0049 for (IProject* p : projects) { 0050 ICore::self()->projectController()->closeProject(p); 0051 } 0052 QVERIFY(ICore::self()->projectController()->projects().isEmpty()); 0053 } 0054 0055 void TestCMakeManager::testWithBuildDirProject() 0056 { 0057 loadProject(QStringLiteral("with_build_dir")); 0058 } 0059 0060 void TestCMakeManager::testIncludePaths() 0061 { 0062 IProject* project = loadProject(QStringLiteral("single_subdirectory")); 0063 Path sourceDir = project->path(); 0064 0065 Path fooCpp(sourceDir, QStringLiteral("subdir/foo.cpp")); 0066 QVERIFY(QFile::exists(fooCpp.toLocalFile())); 0067 QList< ProjectBaseItem* > items = project->itemsForPath(IndexedString(fooCpp.pathOrUrl())); 0068 ProjectBaseItem* fooCppItem = items.first(); 0069 0070 Path::List includeDirs = project->buildSystemManager()->includeDirectories(fooCppItem); 0071 QVERIFY(includeDirs.size() >= 3); 0072 0073 Path buildDir(project->buildSystemManager()->buildDirectory(fooCppItem)); 0074 QVERIFY(includeDirs.contains(buildDir)); 0075 0076 Path subBuildDir(buildDir, QStringLiteral("subdir/")); 0077 QVERIFY(includeDirs.contains(subBuildDir)); 0078 0079 Path subDir(sourceDir, QStringLiteral("subdir/")); 0080 QVERIFY(includeDirs.contains(subDir)); 0081 } 0082 0083 void TestCMakeManager::testRelativePaths() 0084 { 0085 IProject* project = loadProject(QStringLiteral("relative_paths"), QStringLiteral("/out")); 0086 0087 Path codeCpp(project->path(), QStringLiteral("../src/code.cpp")); 0088 QVERIFY(QFile::exists( codeCpp.toLocalFile())); 0089 QList< ProjectBaseItem* > items = project->itemsForPath(IndexedString(codeCpp.pathOrUrl())); 0090 QCOMPARE(items.size(), 1); // once in the target 0091 ProjectBaseItem* fooCppItem = items.first(); 0092 0093 Path::List includeDirs = project->buildSystemManager()->includeDirectories(fooCppItem); 0094 0095 Path incDir(project->path(), QStringLiteral("../inc/")); 0096 QVERIFY(includeDirs.contains( incDir )); 0097 } 0098 0099 void TestCMakeManager::testTargetIncludePaths() 0100 { 0101 IProject* project = loadProject(QStringLiteral("target_includes")); 0102 0103 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0104 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0105 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0106 QCOMPARE(items.size(), 2); // once the plain file, once the target 0107 0108 bool foundInTarget = false; 0109 for (ProjectBaseItem* mainCppItem : items) { 0110 ProjectBaseItem* mainContainer = mainCppItem->parent(); 0111 0112 Path::List includeDirs = project->buildSystemManager()->includeDirectories(mainCppItem); 0113 0114 if (mainContainer->target()) { 0115 foundInTarget = true; 0116 Path targetIncludesDir(project->path(), QStringLiteral("includes/")); 0117 QVERIFY(includeDirs.contains(targetIncludesDir)); 0118 } 0119 } 0120 QVERIFY(foundInTarget); 0121 } 0122 0123 void TestCMakeManager::testTargetIncludeDirectories() 0124 { 0125 IProject* project = loadProject(QStringLiteral("target_include_directories")); 0126 0127 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0128 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0129 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0130 QCOMPARE(items.size(), 2); // once the plain file, once the target 0131 0132 bool foundInTarget = false; 0133 for (ProjectBaseItem* mainCppItem : items) { 0134 ProjectBaseItem* mainContainer = mainCppItem->parent(); 0135 0136 Path::List includeDirs = project->buildSystemManager()->includeDirectories(mainCppItem); 0137 0138 if (mainContainer->target()) { 0139 foundInTarget = true; 0140 QVERIFY(includeDirs.contains(Path(project->path(), "includes/"))); 0141 QVERIFY(includeDirs.contains(Path(project->path(), "libincludes/"))); 0142 } 0143 } 0144 QVERIFY(foundInTarget); 0145 } 0146 0147 void TestCMakeManager::testQt5App() 0148 { 0149 IProject* project = loadProject(QStringLiteral("qt5_app")); 0150 0151 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0152 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0153 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0154 QCOMPARE(items.size(), 2); // once the plain file, once the target 0155 0156 bool foundCore = false, foundGui = false, foundWidgets = false; 0157 for (ProjectBaseItem* mainCppItem : items) { 0158 const Path::List includeDirs = project->buildSystemManager()->includeDirectories(mainCppItem); 0159 for (const Path& include : includeDirs) { 0160 QString filename = include.lastPathSegment(); 0161 foundCore |= filename == QLatin1String("QtCore"); 0162 foundGui |= filename == QLatin1String("QtGui"); 0163 foundWidgets |= filename == QLatin1String("QtWidgets"); 0164 } 0165 } 0166 QVERIFY(foundCore); 0167 QVERIFY(foundGui); 0168 QVERIFY(foundWidgets); 0169 } 0170 0171 void TestCMakeManager::testQt5AppOld() 0172 { 0173 IProject* project = loadProject(QStringLiteral("qt5_app_old")); 0174 0175 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0176 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0177 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0178 QCOMPARE(items.size(), 2); // once the plain file, once the target 0179 0180 bool foundCore = false, foundGui = false, foundWidgets = false; 0181 for (ProjectBaseItem* mainCppItem : items) { 0182 const Path::List includeDirs = project->buildSystemManager()->includeDirectories(mainCppItem); 0183 for (const Path& include : includeDirs) { 0184 QString filename = include.lastPathSegment(); 0185 foundCore |= filename == QLatin1String("QtCore"); 0186 foundGui |= filename == QLatin1String("QtGui"); 0187 foundWidgets |= filename == QLatin1String("QtWidgets"); 0188 } 0189 } 0190 QVERIFY(foundCore); 0191 QVERIFY(foundGui); 0192 QVERIFY(foundWidgets); 0193 } 0194 0195 void TestCMakeManager::testKF5App() 0196 { 0197 IProject* project = loadProject(QStringLiteral("kf5_app")); 0198 0199 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0200 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0201 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0202 QCOMPARE(items.size(), 2); // once the plain file, once the target 0203 0204 bool foundCore = false, foundGui = false, foundWidgets = false, foundWidgetsAddons = false; 0205 for (ProjectBaseItem* mainCppItem : items) { 0206 const Path::List includeDirs = project->buildSystemManager()->includeDirectories(mainCppItem); 0207 qDebug() << "xxxxxxxxx" << includeDirs; 0208 for (const Path& include : includeDirs) { 0209 QString filename = include.lastPathSegment(); 0210 foundCore |= filename == QLatin1String("QtCore"); 0211 foundGui |= filename == QLatin1String("QtGui"); 0212 foundWidgets |= filename == QLatin1String("QtWidgets"); 0213 foundWidgetsAddons |= filename == QLatin1String("KWidgetsAddons"); 0214 } 0215 } 0216 QVERIFY(foundCore); 0217 QVERIFY(foundGui); 0218 QVERIFY(foundWidgets); 0219 QVERIFY(foundWidgetsAddons); 0220 } 0221 0222 void TestCMakeManager::testDefines() 0223 { 0224 IProject* project = loadProject(QStringLiteral("defines")); 0225 0226 Path mainCpp(project->path(), QStringLiteral("main.cpp")); 0227 QVERIFY(QFile::exists(mainCpp.toLocalFile())); 0228 const QList<ProjectBaseItem*> items = project->itemsForPath(IndexedString(mainCpp.pathOrUrl())); 0229 QCOMPARE(items.size(), 2); // once the plain file, once the target 0230 0231 bool foundInTarget = false; 0232 for (ProjectBaseItem* mainCppItem : items) { 0233 QHash<QString, QString> defines = project->buildSystemManager()->defines(mainCppItem); 0234 0235 QCOMPARE(defines.value("B", QStringLiteral("not found")), QString()); 0236 QCOMPARE(defines.value("BV", QStringLiteral("not found")), QStringLiteral("1")); 0237 QCOMPARE(defines.value("BV2", QStringLiteral("not found")), QStringLiteral("2")); 0238 0239 // QCOMPARE(defines.value("BAR", QStringLiteral("not found")), QStringLiteral("foo")); 0240 // QCOMPARE(defines.value("FOO", QStringLiteral("not found")), QStringLiteral("bar")); 0241 // QCOMPARE(defines.value("BLA", QStringLiteral("not found")), QStringLiteral("blub")); 0242 QCOMPARE(defines.value("ASDF", QStringLiteral("not found")), QStringLiteral("asdf")); 0243 QCOMPARE(defines.value("XYZ", QStringLiteral("not found")), QString()); 0244 QCOMPARE(defines.value("A", QStringLiteral("not found")), QString()); 0245 QCOMPARE(defines.value("AV", QStringLiteral("not found")), QStringLiteral("1")); 0246 QCOMPARE(defines.value("AV2", QStringLiteral("not found")), QStringLiteral("2")); 0247 QCOMPARE(defines.value("C", QStringLiteral("not found")), QString()); 0248 QCOMPARE(defines.value("CV", QStringLiteral("not found")), QStringLiteral("1")); 0249 QCOMPARE(defines.value("CV2", QStringLiteral("not found")), QStringLiteral("2")); 0250 QCOMPARE(defines.size(), 13); 0251 foundInTarget = true; 0252 } 0253 QVERIFY(foundInTarget); 0254 } 0255 0256 void TestCMakeManager::testCustomTargetSources() 0257 { 0258 IProject* project = loadProject(QStringLiteral("custom_target_sources")); 0259 0260 QList<ProjectTargetItem*> targets = project->buildSystemManager()->targets(project->projectItem()); 0261 QVERIFY(targets.size() == 1); 0262 0263 ProjectTargetItem *target = targets.first(); 0264 QCOMPARE(target->fileList().size(), 1); 0265 QCOMPARE(target->fileList().first()->baseName(), QStringLiteral("foo.cpp")); 0266 } 0267 0268 void TestCMakeManager::testConditionsInSubdirectoryBasedOnRootVariables() 0269 { 0270 IProject* project = loadProject(QStringLiteral("conditions_in_subdirectory_based_on_root_variables")); 0271 0272 Path rootFooCpp(project->path(), QStringLiteral("foo.cpp")); 0273 QVERIFY(QFile::exists(rootFooCpp.toLocalFile())); 0274 QList< ProjectBaseItem* > rootFooItems = project->itemsForPath(IndexedString(rootFooCpp.pathOrUrl())); 0275 QCOMPARE(rootFooItems.size(), 4); // three items for the targets, one item for the plain file 0276 0277 Path subdirectoryFooCpp(project->path(), QStringLiteral("subdirectory/foo.cpp")); 0278 QVERIFY(QFile::exists(subdirectoryFooCpp.toLocalFile())); 0279 QList< ProjectBaseItem* > subdirectoryFooItems = project->itemsForPath(IndexedString(subdirectoryFooCpp.pathOrUrl())); 0280 0281 QCOMPARE(subdirectoryFooItems.size(), 4); // three items for the targets, one item for the plain file 0282 } 0283 0284 void TestCMakeManager::testEnumerateTargets() 0285 { 0286 QString tempDir = QDir::tempPath(); 0287 0288 QTemporaryFile targetDirectoriesFile; 0289 QTemporaryDir subdir; 0290 0291 auto opened = targetDirectoriesFile.open(); 0292 QVERIFY(opened); 0293 QVERIFY(subdir.isValid()); 0294 0295 const QString targetDirectoriesContent = tempDir + "/CMakeFiles/first_target.dir\n" + 0296 tempDir + "/CMakeFiles/second_target.dir\r\n" + 0297 tempDir + "/" + subdir.path() + "/CMakeFiles/third_target.dir"; 0298 0299 targetDirectoriesFile.write(targetDirectoriesContent.toLatin1()); 0300 targetDirectoriesFile.close(); 0301 0302 QHash<KDevelop::Path, QStringList> targets = 0303 CMake::enumerateTargets(Path(targetDirectoriesFile.fileName()), 0304 tempDir, Path(tempDir)); 0305 0306 QCOMPARE(targets.value(Path(tempDir)).value(0), QStringLiteral("first_target")); 0307 QCOMPARE(targets.value(Path(tempDir)).value(1), QStringLiteral("second_target")); 0308 QCOMPARE(targets.value(Path(tempDir + "/" + subdir.path())).value(0), QStringLiteral("third_target")); 0309 } 0310 0311 void TestCMakeManager::testReload() 0312 { 0313 IProject* project = loadProject(QStringLiteral("tiny_project")); 0314 const Path sourceDir = project->path(); 0315 0316 auto fmp = dynamic_cast<AbstractFileManagerPlugin*>(project->projectFileManager()); 0317 QVERIFY(fmp); 0318 0319 auto projectItem = project->projectItem(); 0320 0321 auto targets = projectItem->targetList(); 0322 QCOMPARE(targets.size(), 1); 0323 auto target = dynamic_cast<CMakeTargetItem*>(targets.first()); 0324 QVERIFY(target); 0325 QCOMPARE(target->text(), QStringLiteral("foo")); 0326 0327 auto job = fmp->createImportJob(project->projectItem()); 0328 project->setReloadJob(job); 0329 0330 QSignalSpy spy(job, &KJob::finished); 0331 job->start(); 0332 QVERIFY(spy.wait()); 0333 QCOMPARE(spy.count(), 1); 0334 0335 QCOMPARE(projectItem, project->projectItem()); 0336 targets = projectItem->targetList(); 0337 QCOMPARE(targets.size(), 1); 0338 target = dynamic_cast<CMakeTargetItem*>(targets.first()); 0339 QVERIFY(target); 0340 QCOMPARE(target->text(), QStringLiteral("foo")); 0341 } 0342 0343 void TestCMakeManager::testFaultyTarget() 0344 { 0345 loadProject(QStringLiteral("faulty_target")); 0346 } 0347 0348 void TestCMakeManager::testParenthesesInTestArguments() 0349 { 0350 IProject* project = loadProject(QStringLiteral("parentheses_in_test_arguments")); 0351 0352 auto job = new CMakeImportJsonJob(project, this); 0353 QVERIFY(job->exec()); 0354 } 0355 0356 void TestCMakeManager::testExecutableOutputPath() 0357 { 0358 const auto prevSuitesCount = ICore::self()->testController()->testSuites().count(); 0359 qRegisterMetaType<KDevelop::ITestSuite*>("KDevelop::ITestSuite*"); 0360 QSignalSpy spy(ICore::self()->testController(), &ITestController::testSuiteAdded); 0361 0362 IProject* project = loadProject(QStringLiteral("randomexe")); 0363 const auto targets = project->projectItem()->targetList(); 0364 QCOMPARE(targets.count(), 1); 0365 0366 const auto target = targets.first()->executable(); 0367 QVERIFY(target); 0368 const KDevelop::Path exePath(target->executable()->builtUrl()); 0369 QString executableSuffix; 0370 #ifdef Q_OS_WIN 0371 executableSuffix = ".exe"; 0372 #endif 0373 QCOMPARE(exePath, 0374 Path(project->buildSystemManager()->buildDirectory(project->projectItem()), 0375 "randomplace/mytest" + executableSuffix)); 0376 0377 QVERIFY(spy.count() || spy.wait(100000)); 0378 0379 auto suites = ICore::self()->testController()->testSuites(); 0380 QCOMPARE(suites.count(), prevSuitesCount + 1); 0381 const CTestSuite* suite = static_cast<CTestSuite*>(ICore::self()->testController()->findTestSuite(project, "mytest")); 0382 QCOMPARE(suite->executable(), exePath); 0383 } 0384 0385 #include "moc_test_cmakemanager.cpp"