diff --git a/server/src/BordersFinder.cpp b/server/src/BordersFinder.cpp index 6a4f3165a..fee93667b 100644 --- a/server/src/BordersFinder.cpp +++ b/server/src/BordersFinder.cpp @@ -17,7 +17,6 @@ BordersFinder::BordersFinder(const fs::path &filePath, const std::shared_ptr &compilationDatabase, const fs::path &compileCommandsJsonPath) : line(line), classBorder(std::nullopt), clangToolRunner(compilationDatabase) { - buildRootPath = Paths::subtractPath(compileCommandsJsonPath.string(), CompilationUtils::UTBOT_BUILD_DIR_NAME); lineInfo.filePath = filePath; } diff --git a/server/src/BordersFinder.h b/server/src/BordersFinder.h index 46d523377..71fd76f61 100644 --- a/server/src/BordersFinder.h +++ b/server/src/BordersFinder.h @@ -31,7 +31,6 @@ class BordersFinder : public clang::ast_matchers::MatchFinder::MatchCallback { private: unsigned line; LineInfo lineInfo{}; - fs::path buildRootPath; struct Borders { struct Position { unsigned line; diff --git a/server/src/KleeGenerator.cpp b/server/src/KleeGenerator.cpp index b1e358f69..e8c805bb4 100644 --- a/server/src/KleeGenerator.cpp +++ b/server/src/KleeGenerator.cpp @@ -16,23 +16,16 @@ using namespace tests; -KleeGenerator::KleeGenerator( - utbot::ProjectContext projectContext, - utbot::SettingsContext settingsContext, - fs::path serverBuildDir, - std::shared_ptr compilationDatabase, - types::TypesHandler &typesHandler, - PathSubstitution filePathsSubstitution, - std::shared_ptr buildDatabase, - ProgressWriter const *progressWriter) - : projectContext(std::move(projectContext)), - settingsContext(std::move(settingsContext)), projectTmpPath(std::move(serverBuildDir)), - compilationDatabase(std::move(compilationDatabase)), - typesHandler(typesHandler), pathSubstitution(std::move(filePathsSubstitution)), - buildDatabase(std::move(buildDatabase)), progressWriter(progressWriter) { +static const std::string GENERATION_COMPILE_MAKEFILE = "GenerationCompileMakefile.mk"; +static const std::string GENERATION_KLEE_MAKEFILE = "GenerationKleeMakefile.mk"; + +KleeGenerator::KleeGenerator(BaseTestGen *testGen, types::TypesHandler &typesHandler, + PathSubstitution filePathsSubstitution) + : testGen(testGen), typesHandler(typesHandler), + pathSubstitution(std::move(filePathsSubstitution)) { try { - fs::create_directories(this->projectTmpPath); - fs::create_directories(Paths::getLogDir(this->projectContext.projectName)); + fs::create_directories(this->testGen->serverBuildDir); + fs::create_directories(Paths::getLogDir(this->testGen->projectContext.projectName)); } catch (const fs::filesystem_error &e) { throw FileSystemException("create_directories failed", e); } @@ -46,33 +39,34 @@ KleeGenerator::buildByCDb(const CollectionUtils::MapFileTo &filesToBui printer::DefaultMakefilePrinter makefilePrinter; std::vector outfilePaths; - for (const auto &compileCommand : compileCommands) { + for (const auto &compileCommand: compileCommands) { fs::path output = compileCommand.getOutput(); outfilePaths.emplace_back(output); utbot::CompileCommand compileCommandWithChangingDirectory{compileCommand, true}; - makefilePrinter.declareTarget(output, { compileCommandWithChangingDirectory.getSourcePath() }, - { compileCommandWithChangingDirectory.toStringWithChangingDirectory() }); + makefilePrinter.declareTarget(output, {compileCommandWithChangingDirectory.getSourcePath()}, + {compileCommandWithChangingDirectory.toStringWithChangingDirectory()}); } - makefilePrinter.declareTarget("all", outfilePaths, {}); - fs::path makefile = projectTmpPath / "GenerationCompileMakefile.mk"; + makefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_ALL, outfilePaths, {}); + const fs::path makefile = testGen->serverBuildDir / GENERATION_COMPILE_MAKEFILE; FileSystemUtils::writeToFile(makefile, makefilePrinter.ss.str()); - auto command = MakefileUtils::MakefileCommand(projectContext, makefile, "all"); + auto command = MakefileUtils::MakefileCommand(testGen->projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_ALL); ExecUtils::ExecutionResult res = command.run(); if (res.status != 0) { LOG_S(ERROR) << StringUtils::stringFormat("Make for \"%s\" failed.\nCommand: \"%s\"\n%s\n", makefile, command.getFailedCommand(), res.output); throw ExecutionProcessException( - command.getFailedCommand(), - res.outPath.value() + command.getFailedCommand(), + res.outPath.value() ); } auto outFiles = CollectionUtils::transform( - compileCommands, [](utbot::CompileCommand const &compileCommand) { - return BuildFileInfo{ compileCommand.getOutput(), compileCommand.getSourcePath() }; - }); + compileCommands, [](utbot::CompileCommand const &compileCommand) { + return BuildFileInfo{compileCommand.getOutput(), compileCommand.getSourcePath()}; + }); return outFiles; } @@ -80,8 +74,8 @@ std::vector KleeGenerator::buildByCDb(const CollectionUtils::FileSet &filesToBuild, const CollectionUtils::FileSet &stubSources) { CollectionUtils::MapFileTo filesMap; - for (fs::path const &file : filesToBuild) { - filesMap[file] = buildDatabase->getBitcodeFile(file); + for (fs::path const &file: filesToBuild) { + filesMap[file] = testGen->getTargetBuildDatabase()->getBitcodeFile(file); } return buildByCDb(filesMap, stubSources); } @@ -89,79 +83,81 @@ KleeGenerator::buildByCDb(const CollectionUtils::FileSet &filesToBuild, static std::string getUTBotClangCompilerPath(fs::path clientCompilerPath) { auto compilerName = CompilationUtils::getCompilerName(clientCompilerPath); switch (compilerName) { - case CompilationUtils::CompilerName::GCC: - return Paths::getUTBotClang(); - case CompilationUtils::CompilerName::GXX: - return Paths::getUTBotClangPP(); - case CompilationUtils::CompilerName::CLANG: - return Paths::getUTBotClang(); - case CompilationUtils::CompilerName::CLANGXX: - return Paths::getUTBotClangPP(); - default: - return clientCompilerPath; + case CompilationUtils::CompilerName::GCC: + return Paths::getUTBotClang(); + case CompilationUtils::CompilerName::GXX: + return Paths::getUTBotClangPP(); + case CompilationUtils::CompilerName::CLANG: + return Paths::getUTBotClang(); + case CompilationUtils::CompilerName::CLANGXX: + return Paths::getUTBotClangPP(); + default: + return clientCompilerPath; } } static const std::unordered_set UNSUPPORTED_FLAGS_AND_OPTIONS_KLEE = { - "--coverage", - "-fbranch-target-load-optimize", - "-fcx-fortran-rules", - "-fipa-cp-clone", - "-fipa-cp-cloneclang-10", - "-fira-loop-pressure", - "-fno-forward-propagate", - "-fno-if-conversion", - "-fno-sched-interblock", - "-fno-sched-spec-insn-heuristic", - "-fno-tree-dominator-opts", - "-fno-tree-sink", - "-fno-tree-sinkclang-10", - "-fpredictive-commoning", - "-fprofile-dir", - "-freschedule-modulo-scheduled-loops", - "-fsched2-use-superblocks", - "-fsel-sched-reschedule-pipelined", - "-ftree-loop-distribute-patterns", + "--coverage", + "-fbranch-target-load-optimize", + "-fcx-fortran-rules", + "-fipa-cp-clone", + "-fipa-cp-cloneclang-10", + "-fira-loop-pressure", + "-fno-forward-propagate", + "-fno-if-conversion", + "-fno-sched-interblock", + "-fno-sched-spec-insn-heuristic", + "-fno-tree-dominator-opts", + "-fno-tree-sink", + "-fno-tree-sinkclang-10", + "-fpredictive-commoning", + "-fprofile-dir", + "-freschedule-modulo-scheduled-loops", + "-fsched2-use-superblocks", + "-fsel-sched-reschedule-pipelined", + "-ftree-loop-distribute-patterns", }; std::optional KleeGenerator::getCompileCommandForKlee(const fs::path &hintPath, const CollectionUtils::FileSet &stubSources, - const std::vector &flags) const { - auto compilationUnitInfo = buildDatabase->getClientCompilationUnitInfo(hintPath); + const std::vector &flags, + bool forStub) const { + auto compilationUnitInfo = testGen->getClientCompilationUnitInfo(hintPath, forStub); auto command = compilationUnitInfo->command; auto srcFilePath = compilationUnitInfo->getSourcePath(); - std::string newCompilerPath = getUTBotClangCompilerPath(command.getCompiler()); - command.setCompiler(newCompilerPath); + std::string newCompilerPath = getUTBotClangCompilerPath(command.getBuildTool()); + command.setBuildTool(newCompilerPath); srcFilePath = pathSubstitution.substituteLineFlag(srcFilePath); if (CollectionUtils::contains(stubSources, srcFilePath)) { - srcFilePath = Paths::sourcePathToStubPath(projectContext, srcFilePath); + srcFilePath = Paths::sourcePathToStubPath(testGen->projectContext, srcFilePath); } command.setSourcePath(srcFilePath); - auto outFilePath = buildDatabase->getBitcodeFile(compilationUnitInfo->getOutputFile()); + auto outFilePath = (forStub ? testGen->getProjectBuildDatabase()->getBitcodeFile(compilationUnitInfo->getOutputFile()) + : testGen->getTargetBuildDatabase()->getBitcodeFile(compilationUnitInfo->getOutputFile())); fs::create_directories(outFilePath.parent_path()); command.setOutput(outFilePath); command.setOptimizationLevel("-O0"); command.removeCompilerFlagsAndOptions(UNSUPPORTED_FLAGS_AND_OPTIONS_KLEE); - std::vector extraFlags{ "-emit-llvm", - "-c", - "-Xclang", - "-disable-O0-optnone", - "-g", - "-fstandalone-debug", - "-fno-discard-value-names", - "-fno-elide-constructors", - "-D" + PrinterUtils::KLEE_MODE + "=1", - SanitizerUtils::CLANG_SANITIZER_CHECKS_FLAG }; + std::vector extraFlags{"-emit-llvm", + "-c", + "-Xclang", + "-disable-O0-optnone", + "-g", + "-fstandalone-debug", + "-fno-discard-value-names", + "-fno-elide-constructors", + "-D" + PrinterUtils::KLEE_MODE + "=1", + SanitizerUtils::CLANG_SANITIZER_CHECKS_FLAG}; if (Paths::isCXXFile(srcFilePath)) { - command.addFlagToBegin(StringUtils::stringFormat("-I%s", Paths::getAccessPrivateLibPath())); + command.addFlagToBegin(CompilationUtils::getIncludePath(Paths::getAccessPrivateLibPath())); } command.addFlagsToBegin(flags); command.addFlagsToBegin(extraFlags); command.addFlagToBegin( - StringUtils::stringFormat("-iquote%s", compilationUnitInfo->getSourcePath().parent_path())); + StringUtils::stringFormat("-iquote%s", compilationUnitInfo->getSourcePath().parent_path())); LOG_S(MAX) << "New compile command with klee required flags: " << command.toString(); return command; } @@ -171,8 +167,8 @@ KleeGenerator::getCompileCommandsForKlee(const CollectionUtils::MapFileTo compileCommands; compileCommands.reserve(filesToBuild.size()); - for (const auto &[fileToBuild, bitcode] : filesToBuild) { - auto optionalCommand = getCompileCommandForKlee(fileToBuild, stubSources, {}); + for (const auto &[fileToBuild, bitcode]: filesToBuild) { + auto optionalCommand = getCompileCommandForKlee(fileToBuild, stubSources, {}, false); if (optionalCommand.has_value()) { auto command = std::move(optionalCommand).value(); command.setOutput(bitcode); @@ -188,13 +184,13 @@ Result KleeGenerator::defaultBuild(const fs::path &hintPath, const fs::path &buildDirPath, const std::vector &flags) { LOG_SCOPE_FUNCTION(DEBUG); - auto bitcodeFilePath = buildDatabase->getBitcodeFile(sourceFilePath); - auto optionalCommand = getCompileCommandForKlee(hintPath, {}, flags); + auto bitcodeFilePath = testGen->getTargetBuildDatabase()->getBitcodeFile(sourceFilePath); + auto optionalCommand = getCompileCommandForKlee(hintPath, {}, flags, false); if (!optionalCommand.has_value()) { std::string message = StringUtils::stringFormat( - "Couldn't get command for klee file: %s\n" - "Please check if directory is in source directories in UTBot extension settings: %s", - sourceFilePath, hintPath.parent_path().string()); + "Couldn't get command for klee file: %s\n" + "Please check if directory is in source directories in UTBot extension settings: %s", + sourceFilePath, hintPath.parent_path().string()); throw BaseException(std::move(message)); } auto &command = optionalCommand.value(); @@ -203,12 +199,15 @@ Result KleeGenerator::defaultBuild(const fs::path &hintPath, printer::DefaultMakefilePrinter makefilePrinter; auto commandWithChangingDirectory = utbot::CompileCommand(command, true); - makefilePrinter.declareTarget("build", {commandWithChangingDirectory.getSourcePath()}, {commandWithChangingDirectory.toStringWithChangingDirectory()}); - fs::path makefile = projectTmpPath / "BCForKLEE.mk"; + makefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_BUILD, + {commandWithChangingDirectory.getSourcePath()}, + {commandWithChangingDirectory.toStringWithChangingDirectory()}); + fs::path makefile = testGen->serverBuildDir / GENERATION_KLEE_MAKEFILE; FileSystemUtils::writeToFile(makefile, makefilePrinter.ss.str()); - auto makefileCommand = MakefileUtils::MakefileCommand(projectContext, makefile, "build"); - auto [out, status, _] = makefileCommand.run(); + auto makefileCommand = MakefileUtils::MakefileCommand(testGen->projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_BUILD); + auto[out, status, _] = makefileCommand.run(); if (status != 0) { LOG_S(ERROR) << "Compilation for " << sourceFilePath << " failed.\n" << "Command: \"" << commandWithChangingDirectory.toString() << "\"\n" @@ -227,103 +226,104 @@ Result KleeGenerator::defaultBuild(const fs::path &sourceFilePath, fs::path KleeGenerator::writeKleeFile( - printer::KleePrinter &kleePrinter, - Tests const &tests, - const std::shared_ptr &lineInfo, - const std::function &methodFilter) { + printer::KleePrinter &kleePrinter, + Tests const &tests, + const std::shared_ptr &lineInfo, + const std::function &methodFilter) { if (lineInfo) { return kleePrinter.writeTmpKleeFile( - tests, projectTmpPath, pathSubstitution, lineInfo->predicateInfo, lineInfo->methodName, - lineInfo->scopeName, lineInfo->forMethod, lineInfo->forClass, methodFilter); + tests, testGen->serverBuildDir, pathSubstitution, lineInfo->predicateInfo, lineInfo->methodName, + lineInfo->scopeName, lineInfo->forMethod, lineInfo->forClass, methodFilter); } else { - return kleePrinter.writeTmpKleeFile(tests, projectTmpPath, pathSubstitution, std::nullopt, + return kleePrinter.writeTmpKleeFile(tests, testGen->serverBuildDir, pathSubstitution, std::nullopt, "", "", false, false, methodFilter); } } std::vector KleeGenerator::buildKleeFiles(const tests::TestsMap &testsMap, - const std::shared_ptr &lineInfo) { + const std::shared_ptr &lineInfo) { std::vector outFiles; LOG_S(DEBUG) << "Building generated klee files..."; - printer::KleePrinter kleePrinter(&typesHandler, buildDatabase, utbot::Language::UNKNOWN); + printer::KleePrinter kleePrinter(&typesHandler, testGen->getTargetBuildDatabase(), utbot::Language::UNKNOWN); ExecUtils::doWorkWithProgress( - testsMap, progressWriter, "Building generated klee files", - [&](auto const &it) { - const auto &[filename, tests] = it; - if (lineInfo != nullptr && filename != lineInfo->filePath) { - return; - } - kleePrinter.srcLanguage = Paths::getSourceLanguage(filename); - auto includeFlags = { StringUtils::stringFormat("-I%s", - Paths::getFlagsDir(projectContext)) }; - auto buildDirPath = - buildDatabase->getClientCompilationUnitInfo(filename)->getDirectory(); - - fs::path kleeFilePath = writeKleeFile(kleePrinter, tests, lineInfo); - auto kleeFilesInfo = - buildDatabase->getClientCompilationUnitInfo(tests.sourceFilePath)->kleeFilesInfo; - auto kleeBitcodeFile = defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags); - if (kleeBitcodeFile.isSuccess()) { - outFiles.emplace_back(kleeBitcodeFile.getOpt().value()); - kleeFilesInfo->setAllAreCorrect(true); - LOG_S(MAX) << "Klee filepath: " << outFiles.back(); - } else { - if (lineInfo) { - throw BaseException("Couldn't compile klee file for current line."); + testsMap, testGen->progressWriter, "Building generated klee files", + [&](auto const &it) { + const auto &[filename, tests] = it; + if (lineInfo != nullptr && filename != lineInfo->filePath) { + return; } - auto tempKleeFilePath = Paths::addSuffix(kleeFilePath, "_temp"); - fs::copy(kleeFilePath, tempKleeFilePath, fs::copy_options::overwrite_existing); - LOG_S(DEBUG) + kleePrinter.srcLanguage = Paths::getSourceLanguage(filename); + std::vector includeFlags = { + CompilationUtils::getIncludePath(Paths::getFlagsDir(testGen->projectContext))}; + auto buildDirPath = + testGen->getClientCompilationUnitInfo(filename)->getDirectory(); + + fs::path kleeFilePath = writeKleeFile(kleePrinter, tests, lineInfo); + auto kleeFilesInfo = + testGen->getClientCompilationUnitInfo( + tests.sourceFilePath)->kleeFilesInfo; + auto kleeBitcodeFile = defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags); + if (kleeBitcodeFile.isSuccess()) { + outFiles.emplace_back(kleeBitcodeFile.getOpt().value()); + kleeFilesInfo->setAllAreCorrect(true); + LOG_S(MAX) << "Klee filepath: " << outFiles.back(); + } else { + if (lineInfo) { + throw BaseException("Couldn't compile klee file for current line."); + } + auto tempKleeFilePath = Paths::addSuffix(kleeFilePath, "_temp"); + fs::copy(kleeFilePath, tempKleeFilePath, fs::copy_options::overwrite_existing); + LOG_S(DEBUG) << "File " << kleeFilePath << " couldn't be compiled so it's copy is backed up in " << tempKleeFilePath << ". Proceeding with generating klee file containing restricted number " "of functions"; - std::unordered_set correctMethods; - for (const auto &[methodName, methodDescription] : tests.methods) { - fs::path currentKleeFilePath = kleePrinter.writeTmpKleeFile( - tests, projectTmpPath, pathSubstitution, std::nullopt, - methodDescription.name, - methodDescription.getClassName(), - true, false); - auto currentKleeBitcodeFile = - defaultBuild(filename, currentKleeFilePath, buildDirPath, includeFlags); - if (currentKleeBitcodeFile.isSuccess()) { - correctMethods.insert(methodDescription.name); + std::unordered_set correctMethods; + for (const auto &[methodName, methodDescription]: tests.methods) { + fs::path currentKleeFilePath = kleePrinter.writeTmpKleeFile( + tests, testGen->serverBuildDir, pathSubstitution, std::nullopt, + methodDescription.name, + methodDescription.getClassName(), + true, false); + auto currentKleeBitcodeFile = + defaultBuild(filename, currentKleeFilePath, buildDirPath, includeFlags); + if (currentKleeBitcodeFile.isSuccess()) { + correctMethods.insert(methodDescription.name); + } else { + std::stringstream message; + message << "Function '" << methodName + << "' was skipped, as there was an error in compilation klee file " + "for it"; + LOG_S(WARNING) << message.str(); + failedFunctions[filename].emplace_back(message.str()); + } + } + kleeFilesInfo->setCorrectMethods(std::move(correctMethods)); + + auto kleeFilePath = writeKleeFile( + kleePrinter, tests, lineInfo, + [&kleeFilesInfo](tests::Tests::MethodDescription const &method) -> bool { + return kleeFilesInfo->isCorrectMethod(method.name); + }); + auto kleeBitcodeFile = + defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags); + if (kleeBitcodeFile.isSuccess()) { + outFiles.emplace_back(kleeBitcodeFile.getOpt().value()); } else { - std::stringstream message; - message << "Function '" << methodName - << "' was skipped, as there was an error in compilation klee file " - "for it"; - LOG_S(WARNING) << message.str(); - failedFunctions[filename].emplace_back(message.str()); + throw BaseException("Couldn't compile klee file from correct methods."); } } - kleeFilesInfo->setCorrectMethods(std::move(correctMethods)); - - auto kleeFilePath = writeKleeFile( - kleePrinter, tests, lineInfo, - [&kleeFilesInfo](tests::Tests::MethodDescription const &method) -> bool { - return kleeFilesInfo->isCorrectMethod(method.name); - }); - auto kleeBitcodeFile = - defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags); - if (kleeBitcodeFile.isSuccess()) { - outFiles.emplace_back(kleeBitcodeFile.getOpt().value()); - } else { - throw BaseException("Couldn't compile klee file from correct methods."); - } - } - }); + }); return outFiles; } void KleeGenerator::parseKTestsToFinalCode( - tests::Tests &tests, - const std::unordered_map &methodNameToReturnTypeMap, - const std::vector &kleeOutput, - const std::shared_ptr &lineInfo, - bool verbose) { - for (const auto &batch : kleeOutput) { + tests::Tests &tests, + const std::unordered_map &methodNameToReturnTypeMap, + const std::vector &kleeOutput, + const std::shared_ptr &lineInfo, + bool verbose) { + for (const auto &batch: kleeOutput) { bool filterByFlag = (lineInfo != nullptr && !lineInfo->forMethod && !lineInfo->forClass && !lineInfo->predicateInfo.has_value()); tests::KTestObjectParser KTestObjectParser(typesHandler); @@ -346,24 +346,25 @@ void KleeGenerator::parseKTestsToFinalCode( continue; } auto predicate = - lineInfo ? lineInfo->predicateInfo : std::optional{}; + lineInfo ? lineInfo->predicateInfo : std::optional{}; testsPrinter.genCode(methodDescription, predicate, verbose); } - printer::HeaderPrinter(Paths::getSourceLanguage(tests.sourceFilePath)).print(tests.testHeaderFilePath, tests.sourceFilePath, - tests.headerCode); + printer::HeaderPrinter(Paths::getSourceLanguage(tests.sourceFilePath)).print(tests.testHeaderFilePath, + tests.sourceFilePath, + tests.headerCode); testsPrinter.joinToFinalCode(tests, tests.testHeaderFilePath); LOG_S(DEBUG) << "Generated code for " << tests.methods.size() << " tests"; } -std::shared_ptr KleeGenerator::getBuildDatabase() const { - return buildDatabase; +fs::path KleeGenerator::getBitcodeFile(const fs::path &sourcePath) const { + return testGen->getTargetBuildDatabase()->getBitcodeFile(sourcePath); } void KleeGenerator::handleFailedFunctions(tests::TestsMap &testsMap) { - for (auto &[fileName, tests] : failedFunctions) { - for (const auto &commentBlock : tests) { + for (auto &[fileName, tests]: failedFunctions) { + for (const auto &commentBlock: tests) { testsMap[fileName].commentBlocks.emplace_back(commentBlock); } } diff --git a/server/src/KleeGenerator.h b/server/src/KleeGenerator.h index 8f91efeb3..3134ef8c0 100644 --- a/server/src/KleeGenerator.h +++ b/server/src/KleeGenerator.h @@ -15,12 +15,14 @@ #include "streams/tests/TestsWriter.h" #include "types/Types.h" #include "utils/ExecUtils.h" - #include "utils/path/FileSystemPath.h" +#include "testgens/BaseTestGen.h" + #include #include #include + using json = nlohmann::json; /** @@ -33,13 +35,7 @@ class KleeGenerator { public: /** * @brief Also creates tmp directories for build files. - * @param projectContext contains context about current project. - * @param settingsContext contains context about settings applied for current request. - * @param serverBuildDir Path to folder on server machine where project build dirs are located. - * @param sourcesFilePaths Paths to project files. Files which are listed in - * [compile_commands.json](https://clang.llvm.org/docs/JSONCompilationDatabase.html), filtered - * by them. - * @param compilationDatabase Pointer to compile_commands.json object. + * @param testGen contains request and build information. * @param typesHandler provides additional information about types. * @param filePathsSubstitution Mapping from source file path to modified file. Required for * line test generation requests. @@ -47,14 +43,8 @@ class KleeGenerator { * @throws fs::filesystem_error Thrown if it can't create tmp folder for some * reasons. */ - KleeGenerator(utbot::ProjectContext projectContext, - utbot::SettingsContext settingsContext, - fs::path serverBuildDir, - std::shared_ptr compilationDatabase, - types::TypesHandler &typesHandler, - PathSubstitution filePathsSubstitution, - std::shared_ptr buildDatabase = nullptr, - const ProgressWriter *progressWriter = DummyStreamWriter::getInstance()); + KleeGenerator(BaseTestGen *testGen, types::TypesHandler &typesHandler, + PathSubstitution filePathsSubstitution); struct BuildFileInfo { fs::path outFilePath; @@ -128,7 +118,7 @@ class KleeGenerator { const std::shared_ptr &lineInfo = nullptr, bool verbose = false); - [[nodiscard]] std::shared_ptr getBuildDatabase() const; + [[nodiscard]] fs::path getBitcodeFile(const fs::path &sourcePath) const; void handleFailedFunctions(tests::TestsMap &testsMap); @@ -146,29 +136,25 @@ class KleeGenerator { std::optional getCompileCommandForKlee(const fs::path &hintPath, const CollectionUtils::FileSet &stubSources, - const std::vector &flags) const; + const std::vector &flags, + bool forStub) const; std::vector getCompileCommandsForKlee(const CollectionUtils::MapFileTo &filesToBuild, const CollectionUtils::FileSet &stubSources) const; private: - const utbot::ProjectContext projectContext; - const utbot::SettingsContext settingsContext; - fs::path projectTmpPath; - std::shared_ptr compilationDatabase; + BaseTestGen *testGen; types::TypesHandler typesHandler; PathSubstitution pathSubstitution; - std::shared_ptr buildDatabase; - const ProgressWriter *progressWriter; CollectionUtils::MapFileTo> failedFunctions; fs::path writeKleeFile( - printer::KleePrinter &kleePrinter, - Tests const &tests, - const std::shared_ptr &lineInfo, - const std::function &methodFilter = + printer::KleePrinter &kleePrinter, + Tests const &tests, + const std::shared_ptr &lineInfo, + const std::function &methodFilter = [](tests::Tests::MethodDescription const &) { return true; }); }; diff --git a/server/src/Paths.cpp b/server/src/Paths.cpp index 1c824f463..481ded3ab 100644 --- a/server/src/Paths.cpp +++ b/server/src/Paths.cpp @@ -27,7 +27,7 @@ namespace Paths { CollectionUtils::FileSet filtered = CollectionUtils::filterOut(paths, [&dirPaths, &filter](const fs::path &path) { return !std::any_of(dirPaths.begin(), dirPaths.end(), [&](const fs::path &dirPath) { - return path.parent_path() == dirPath && fs::exists(path) && filter(path); + return isSubPathOf(dirPath, path) && fs::exists(path) && filter(path); }); }); return filtered; diff --git a/server/src/ProjectTarget.cpp b/server/src/ProjectTarget.cpp deleted file mode 100644 index 2e210095c..000000000 --- a/server/src/ProjectTarget.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "ProjectTarget.h" - -#include - -#include - -namespace utbot { - ProjectTarget::ProjectTarget(std::string name, fs::path path) - : name(std::move(name)), path(std::move(path)) { - } - ProjectTarget::ProjectTarget(const testsgen::ProjectTarget &projectTarget) - : ProjectTarget(projectTarget.name(), projectTarget.path()) { - } - - const std::string &ProjectTarget::getName() const { - return name; - } - const fs::path &ProjectTarget::getPath() const { - return path; - } -} diff --git a/server/src/ProjectTarget.h b/server/src/ProjectTarget.h deleted file mode 100644 index 3002c7b03..000000000 --- a/server/src/ProjectTarget.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef UNITTESTBOT_PROJECTTARGET_H -#define UNITTESTBOT_PROJECTTARGET_H - -#include "utils/path/FileSystemPath.h" - -#include - -namespace testsgen { - class ProjectTarget; -} - -namespace utbot { - class ProjectTarget { - public: - ProjectTarget(std::string name, fs::path path); - - explicit ProjectTarget(testsgen::ProjectTarget const &projectTarget); - - const std::string &getName() const; - const fs::path &getPath() const; - - private: - std::string name; - fs::path path; - }; -} - - -#endif // UNITTESTBOT_PROJECTTARGET_H diff --git a/server/src/ReturnTypesFetcher.cpp b/server/src/ReturnTypesFetcher.cpp index c3d138e71..9fa4dde67 100644 --- a/server/src/ReturnTypesFetcher.cpp +++ b/server/src/ReturnTypesFetcher.cpp @@ -10,7 +10,7 @@ void ReturnTypesFetcher::fetch(ProgressWriter *const progressWriter, testsMap[filePath]; } Fetcher(Fetcher::Options::Value::RETURN_TYPE_NAMES_ONLY, - testGen->compilationDatabase, testsMap, nullptr, nullptr, nullptr, + testGen->getTargetBuildDatabase()->compilationDatabase, testsMap, nullptr, nullptr, nullptr, testGen->compileCommandsJsonPath, false) .fetchWithProgress(progressWriter, "Fetching return types for functions", true); for (auto const &[sourceFilePath, test] : testsMap) { diff --git a/server/src/Server.cpp b/server/src/Server.cpp index af4ff23eb..8a5365f03 100644 --- a/server/src/Server.cpp +++ b/server/src/Server.cpp @@ -32,6 +32,7 @@ #include "utils/stats/TestsGenerationStats.h" #include "utils/stats/TestsExecutionStats.h" #include "utils/TypeUtils.h" +#include "building/ProjectBuildDatabase.h" #include #include @@ -147,7 +148,7 @@ Status Server::TestsGenServiceImpl::GenerateLineTests(ServerContext *context, } Status Server::TestsGenServiceImpl::GenerateAssertionFailTests( - ServerContext *context, const AssertionRequest *request, ServerWriter *writer) { + ServerContext *context, const AssertionRequest *request, ServerWriter *writer) { return BaseTestGenerate(context, *request, writer); } @@ -166,9 +167,9 @@ Status Server::TestsGenServiceImpl::Handshake(ServerContext *context, } Status Server::TestsGenServiceImpl::CreateTestsCoverageAndResult( - ServerContext *context, - const CoverageAndResultsRequest *request, - ServerWriter *writer) { + ServerContext *context, + const CoverageAndResultsRequest *request, + ServerWriter *writer) { LOG_S(INFO) << "CreateTestsCoverageAndResult receive:\n" << request->DebugString(); auto coverageAndResultsWriter = std::make_unique(writer); @@ -198,18 +199,18 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen, static std::string logMessage = "Traversing sources AST tree and fetching declarations."; LOG_S(DEBUG) << logMessage; Fetcher fetcher(Fetcher::Options::Value::ALL, - testGen.compilationDatabase, testGen.tests, &testGen.types, + testGen.getTargetBuildDatabase()->compilationDatabase, testGen.tests, &testGen.types, &sizeContext.pointerSize, &sizeContext.maximumAlignment, testGen.compileCommandsJsonPath, false); fetcher.fetchWithProgress(testGen.progressWriter, logMessage); - SourceToHeaderRewriter(testGen.projectContext, testGen.compilationDatabase, + SourceToHeaderRewriter(testGen.projectContext, testGen.getTargetBuildDatabase()->compilationDatabase, fetcher.getStructsToDeclare(), testGen.serverBuildDir) - .generateTestHeaders(testGen.tests, testGen.progressWriter); - types::TypesHandler typesHandler{ testGen.types, sizeContext }; + .generateTestHeaders(testGen.tests, testGen.progressWriter); + types::TypesHandler typesHandler{testGen.types, sizeContext}; testGen.progressWriter->writeProgress("Generating stub files", 0.0); StubGen stubGen(testGen); - Synchronizer synchronizer(&testGen, &stubGen, &sizeContext); + Synchronizer synchronizer(&testGen, &sizeContext); synchronizer.synchronize(typesHandler); std::shared_ptr lineInfo = nullptr; @@ -218,7 +219,7 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen, if (lineTestGen != nullptr) { if (isSameType(testGen) && Paths::isHeaderFile(lineTestGen->filePath)) { BordersFinder classFinder(lineTestGen->filePath, lineTestGen->line, - lineTestGen->compilationDatabase, + testGen.getTargetBuildDatabase()->compilationDatabase, lineTestGen->compileCommandsJsonPath); classFinder.findClass(); lineInfo = std::make_shared(classFinder.getLineInfo()); @@ -248,35 +249,34 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen, if (lineTestGen->needToAddPathFlag()) { LOG_S(DEBUG) << "Added test line flag for file " << lineInfo->filePath; fs::path flagFilePath = - printer::KleePrinter(&typesHandler, nullptr, Paths::getSourceLanguage(lineInfo->filePath)) - .addTestLineFlag(lineInfo, lineInfo->forAssert, testGen.projectContext); - pathSubstitution = { lineTestGen->filePath, flagFilePath }; + printer::KleePrinter(&typesHandler, nullptr, Paths::getSourceLanguage(lineInfo->filePath)) + .addTestLineFlag(lineInfo, lineInfo->forAssert, testGen.projectContext); + pathSubstitution = {lineTestGen->filePath, flagFilePath}; } } - auto generator = std::make_shared( - testGen.projectContext, testGen.settingsContext, - testGen.serverBuildDir, testGen.compilationDatabase, typesHandler, - pathSubstitution, testGen.buildDatabase, testGen.progressWriter); + auto generator = std::make_shared(&testGen, typesHandler, pathSubstitution); - ReturnTypesFetcher returnTypesFetcher{ &testGen }; - returnTypesFetcher.fetch(testGen.progressWriter, synchronizer.getAllFiles()); + ReturnTypesFetcher returnTypesFetcher{&testGen}; + returnTypesFetcher.fetch(testGen.progressWriter, synchronizer.getSourceFiles()); LOG_S(DEBUG) << "Temporary build directory path: " << testGen.serverBuildDir; generator->buildKleeFiles(testGen.tests, lineInfo); generator->handleFailedFunctions(testGen.tests); testGen.progressWriter->writeProgress("Building files", 0.0); - Linker linker{ testGen, stubGen, lineInfo, generator }; + Linker linker{testGen, stubGen, lineInfo, generator}; linker.prepareArtifacts(); auto testMethods = linker.getTestMethods(); - KleeRunner kleeRunner{ testGen.projectContext, testGen.settingsContext, - testGen.serverBuildDir }; + KleeRunner kleeRunner{testGen.projectContext, testGen.settingsContext, + testGen.serverBuildDir}; bool interactiveMode = (dynamic_cast(&testGen) != nullptr); auto generationStartTime = std::chrono::steady_clock::now(); StatsUtils::TestsGenerationStatsFileMap generationStatsMap(testGen.projectContext, - std::chrono::duration_cast(generationStartTime - preprocessingStartTime)); + std::chrono::duration_cast( + generationStartTime - + preprocessingStartTime)); kleeRunner.runKlee(testMethods, testGen.tests, generator, testGen.methodNameToReturnTypeMap, lineInfo, testsWriter, testGen.isBatched(), interactiveMode, generationStatsMap); LOG_S(INFO) << "KLEE time: " << std::chrono::duration_cast - (generationStatsMap.getTotal().kleeStats.getKleeTime()).count() << " ms\n"; + (generationStatsMap.getTotal().kleeStats.getKleeTime()).count() << " ms\n"; printer::CSVPrinter printer = generationStatsMap.toCSV(); FileSystemUtils::writeToFile(Paths::getGenerationStatsCSVPath(testGen.projectContext), printer.getStream().str()); @@ -286,7 +286,7 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen, std::string command = e.what(); return Status(StatusCode::FAILED_PRECONDITION, "Executing command\n" + command.substr(0, 100) + - "...\nfailed. See more info in console logs."); + "...\nfailed. See more info in console logs."); } catch (const NoTestGeneratedException &e) { return Status(StatusCode::FAILED_PRECONDITION, e.what()); } catch (const CancellationException &e) { @@ -311,12 +311,12 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen, std::shared_ptr Server::TestsGenServiceImpl::getLineInfo(LineTestGen &lineTestGen) { BordersFinder stmtFinder(lineTestGen.filePath, lineTestGen.line, - lineTestGen.compilationDatabase, + lineTestGen.getTargetBuildDatabase()->compilationDatabase, lineTestGen.compileCommandsJsonPath); stmtFinder.findFunction(); if (!stmtFinder.getLineInfo().initialized) { throw NoTestGeneratedException( - "Maybe you tried to generate tests placing cursor on invalid line."); + "Maybe you tried to generate tests placing cursor on invalid line."); } if (isSameType(lineTestGen) && !StringUtils::contains(stmtFinder.getLineInfo().stmtString, "assert")) { @@ -325,12 +325,13 @@ std::shared_ptr Server::TestsGenServiceImpl::getLineInfo(LineTestGen & auto lineInfo = std::make_shared(stmtFinder.getLineInfo()); if (auto predicateInfo = dynamic_cast(&lineTestGen)) { lineInfo->predicateInfo = LineInfo::PredicateInfo( - { predicateInfo->type, predicateInfo->predicate, predicateInfo->returnValue }); + {predicateInfo->type, predicateInfo->predicate, predicateInfo->returnValue}); } auto &methods = lineTestGen.tests.at(lineInfo->filePath).methods; CollectionUtils::erase_if(methods, [&lineInfo](auto const &method) { return (lineInfo->forMethod && method.name != lineInfo->methodName) || - (lineInfo->forClass && method.isClassMethod() && method.classObj->type.typeName() != lineInfo->scopeName); + (lineInfo->forClass && method.isClassMethod() && + method.classObj->type.typeName() != lineInfo->scopeName); }); return lineInfo; } @@ -374,7 +375,7 @@ void Server::gtestLog(void *channel, const loguru::Message &message) { } } -loguru::Verbosity MaxNameToVerbosityCallback(const char* name) { +loguru::Verbosity MaxNameToVerbosityCallback(const char *name) { if (strcmp(name, "TestLogLevel") == 0) { return loguru::Verbosity_INFO; } else if (strcmp(name, "ServerLogLevel") == 0) { @@ -384,17 +385,17 @@ loguru::Verbosity MaxNameToVerbosityCallback(const char* name) { } Status Server::TestsGenServiceImpl::provideLoggingCallbacks( - const std::string &callbackPrefix, - ServerWriter *writer, - const std::string &logLevel, - loguru::log_handler_t handler, - std::map &channelStorage, - bool openFiles) { + const std::string &callbackPrefix, + ServerWriter *writer, + const std::string &logLevel, + loguru::log_handler_t handler, + std::map &channelStorage, + bool openFiles) { const auto &client = RequestEnvironment::getClientId(); auto oldValue = channelStorage[client].load(std::memory_order_relaxed); if (!oldValue && channelStorage[client].compare_exchange_weak( - oldValue, true, std::memory_order_release, std::memory_order_relaxed)) { - WriterData data{ writer, std::mutex(), client }; + oldValue, true, std::memory_order_release, std::memory_order_relaxed)) { + WriterData data{writer, std::mutex(), client}; fs::path logFilePath = Paths::getLogDir(); if (!fs::exists(logFilePath)) { fs::create_directories(logFilePath); @@ -486,7 +487,7 @@ Status Server::TestsGenServiceImpl::Heartbeat(ServerContext *context, Status Server::TestsGenServiceImpl::RegisterClient(ServerContext *context, const RegisterClientRequest *request, DummyResponse *response) { - const std::string& name = request->clientid(); + const std::string &name = request->clientid(); ServerUtils::registerClient(clients, name); return Status::OK; } @@ -528,7 +529,7 @@ Status Server::TestsGenServiceImpl::GenerateProjectStubs(ServerContext *context, LOG_S(INFO) << "GenerateProjectStubs receive:\n" << request->DebugString(); auto stubsWriter = - std::make_unique(writer, GrpcUtils::synchronizeCode(*request)); + std::make_unique(writer, GrpcUtils::synchronizeCode(*request)); ServerUtils::setThreadOptions(context, testMode); auto lock = acquireLock(stubsWriter.get()); @@ -545,18 +546,17 @@ Status Server::TestsGenServiceImpl::GenerateProjectStubs(ServerContext *context, Status Server::TestsGenServiceImpl::ProcessProjectStubsRequest(BaseTestGen *testGen, StubsWriter *stubsWriter) { types::TypesHandler::SizeContext sizeContext; - types::TypesHandler typesHandler{ testGen->types, sizeContext }; - StubGen stubGen(*testGen); + types::TypesHandler typesHandler{testGen->types, sizeContext}; static std::string logMessage = "Traversing sources AST tree and fetching declarations."; LOG_S(DEBUG) << logMessage; Fetcher fetcher(Fetcher::Options::Value::TYPE | Fetcher::Options::Value::FUNCTION, - testGen->compilationDatabase, testGen->tests, &testGen->types, + testGen->getTargetBuildDatabase()->compilationDatabase, testGen->tests, &testGen->types, &sizeContext.pointerSize, &sizeContext.maximumAlignment, testGen->compileCommandsJsonPath, false); fetcher.fetchWithProgress(testGen->progressWriter, logMessage); - Synchronizer synchronizer(testGen, &stubGen, &sizeContext); + Synchronizer synchronizer(testGen, &sizeContext); synchronizer.synchronize(typesHandler); stubsWriter->writeResponse(testGen->synchronizedStubs, testGen->projectContext.testDirPath); return Status::OK; @@ -577,9 +577,9 @@ Status Server::TestsGenServiceImpl::PrintModulesContent(ServerContext *context, MEASURE_FUNCTION_EXECUTION_TIME - utbot::ProjectContext projectContext{ *request }; + utbot::ProjectContext projectContext{*request}; fs::path serverBuildDir = Paths::getUtbotBuildDir(projectContext); - std::shared_ptr buildDatabase = BuildDatabase::create(projectContext); + std::shared_ptr buildDatabase = std::make_shared(projectContext); StubSourcesFinder(buildDatabase).printAllModules(); return Status::OK; } @@ -595,12 +595,12 @@ Status Server::TestsGenServiceImpl::GetSourceCode(ServerContext *context, MEASURE_FUNCTION_EXECUTION_TIME const std::string &filePath = request->filepath(); - std::ifstream stream{ filePath }; + std::ifstream stream{filePath}; if (!stream) { return Status(StatusCode::INVALID_ARGUMENT, "Failed to find file:\n" + filePath); } auto code = std::make_unique(std::istreambuf_iterator(stream), - std::istreambuf_iterator()); + std::istreambuf_iterator()); response->set_allocated_code(code.release()); return Status::OK; } @@ -610,34 +610,34 @@ Server::TestsGenServiceImpl::ConfigureProject(ServerContext *context, const ProjectConfigRequest *request, ServerWriter *response) { LOG_S(INFO) << "CheckProjectConfiguration receive:\n" << request->DebugString(); - ProjectConfigWriter writer{ response }; + ProjectConfigWriter writer{response}; ServerUtils::setThreadOptions(context, testMode); auto lock = acquireLock(&writer); MEASURE_FUNCTION_EXECUTION_TIME - utbot::ProjectContext utbotProjectContext{ request->projectcontext() }; + utbot::ProjectContext utbotProjectContext{request->projectcontext()}; fs::path buildDirPath = - fs::path(utbotProjectContext.projectPath) / utbotProjectContext.buildDirRelativePath; + fs::path(utbotProjectContext.projectPath) / utbotProjectContext.buildDirRelativePath; switch (request->configmode()) { - case ConfigMode::CHECK: - return UserProjectConfiguration::CheckProjectConfiguration(buildDirPath, writer); - case ConfigMode::CREATE_BUILD_DIR: - return UserProjectConfiguration::RunBuildDirectoryCreation(buildDirPath, writer); - case ConfigMode::GENERATE_JSON_FILES: { - std::vector cmakeOptions(request->cmakeoptions().begin(), request->cmakeoptions().end()); - return UserProjectConfiguration::RunProjectConfigurationCommands( - buildDirPath, utbotProjectContext, cmakeOptions, writer); - } - case ConfigMode::ALL: { - std::vector cmakeOptions(request->cmakeoptions().begin(), request->cmakeoptions().end()); - return UserProjectConfiguration::RunProjectReConfigurationCommands( - buildDirPath, fs::path(utbotProjectContext.projectPath), - utbotProjectContext, cmakeOptions, writer); - } - default: - return {StatusCode::CANCELLED, "Invalid request type."}; + case ConfigMode::CHECK: + return UserProjectConfiguration::CheckProjectConfiguration(buildDirPath, writer); + case ConfigMode::CREATE_BUILD_DIR: + return UserProjectConfiguration::RunBuildDirectoryCreation(buildDirPath, writer); + case ConfigMode::GENERATE_JSON_FILES: { + std::vector cmakeOptions(request->cmakeoptions().begin(), request->cmakeoptions().end()); + return UserProjectConfiguration::RunProjectConfigurationCommands( + buildDirPath, utbotProjectContext, cmakeOptions, writer); + } + case ConfigMode::ALL: { + std::vector cmakeOptions(request->cmakeoptions().begin(), request->cmakeoptions().end()); + return UserProjectConfiguration::RunProjectReConfigurationCommands( + buildDirPath, fs::path(utbotProjectContext.projectPath), + utbotProjectContext, cmakeOptions, writer); + } + default: + return {StatusCode::CANCELLED, "Invalid request type."}; } } @@ -653,10 +653,10 @@ Status Server::TestsGenServiceImpl::GetProjectTargets(ServerContext *context, MEASURE_FUNCTION_EXECUTION_TIME try { - utbot::ProjectContext projectContext{ request->projectcontext() }; - auto buildDatabase = BuildDatabase::create(projectContext); - auto targets = buildDatabase->getAllTargets(); - ProjectTargetsWriter targetsWriter{ response }; + utbot::ProjectContext projectContext{request->projectcontext()}; + auto buildDatabase = std::make_shared(projectContext); + std::vector targets = buildDatabase->getAllTargetPaths(); + ProjectTargetsWriter targetsWriter(response); targetsWriter.writeResponse(projectContext, targets); } catch (CompilationDatabaseException const &e) { return failedToLoadCDbStatus(e); @@ -675,13 +675,13 @@ Status Server::TestsGenServiceImpl::GetFileTargets(ServerContext *context, MEASURE_FUNCTION_EXECUTION_TIME try { - utbot::ProjectContext projectContext{ request->projectcontext() }; - auto buildDatabase = BuildDatabase::create(projectContext); + utbot::ProjectContext projectContext{request->projectcontext()}; + auto buildDatabase = std::make_shared(projectContext); fs::path path = request->path(); - auto targets = buildDatabase->getTargetsForSourceFile(path); - FileTargetsWriter targetsWriter{ response }; - targetsWriter.writeResponse(targets, projectContext); - } catch (CompilationDatabaseException const& e) { + auto targetPaths = buildDatabase->getTargetPathsForSourceFile(path); + FileTargetsWriter targetsWriter{response}; + targetsWriter.writeResponse(targetPaths, projectContext); + } catch (CompilationDatabaseException const &e) { return failedToLoadCDbStatus(e); } return Status::OK; @@ -689,7 +689,7 @@ Status Server::TestsGenServiceImpl::GetFileTargets(ServerContext *context, RequestLockMutex &Server::TestsGenServiceImpl::getLock() { std::string const &client = RequestEnvironment::getClientId(); - auto [iterator, inserted] = locks.try_emplace(client); + auto[iterator, inserted] = locks.try_emplace(client); return iterator->second; } @@ -697,10 +697,10 @@ std::unique_lock Server::TestsGenServiceImpl::acquireLock(ProgressWriter *writer) { auto &lock = getLock(); if (lock.try_lock()) { - return std::unique_lock{ lock, std::adopt_lock }; + return std::unique_lock{lock, std::adopt_lock}; } if (writer != nullptr) { writer->writeProgress("Waiting for previous task to be finished"); } - return std::unique_lock{ lock }; + return std::unique_lock{lock}; } diff --git a/server/src/Server.h b/server/src/Server.h index 121f79194..fd9c22dcc 100644 --- a/server/src/Server.h +++ b/server/src/Server.h @@ -116,10 +116,6 @@ class Server { MEASURE_FUNCTION_EXECUTION_TIME TestGenT testGen{ request, testsWriter.get(), testMode }; - if constexpr (std::is_base_of_v) { - fs::path targetPath = testGen.getRequest()->targetpath(); - testGen.setTargetPath(targetPath); - } TimeExecStatistics::clearStatistic(); Status status = ProcessBaseTestRequest(testGen, testsWriter.get()); TimeExecStatistics::printStatistic(); diff --git a/server/src/Synchronizer.cpp b/server/src/Synchronizer.cpp index 9435e0719..649686b43 100644 --- a/server/src/Synchronizer.cpp +++ b/server/src/Synchronizer.cpp @@ -40,9 +40,8 @@ bool StubOperator::isHeader() const { } Synchronizer::Synchronizer(BaseTestGen *testGen, - StubGen const *stubGen, types::TypesHandler::SizeContext *sizeContext) - : testGen(testGen), stubGen(stubGen), sizeContext(sizeContext) { + : testGen(testGen), sizeContext(sizeContext) { } bool Synchronizer::isProbablyOutdated(const fs::path &srcFilePath) const { @@ -66,11 +65,19 @@ bool Synchronizer::isProbablyOutdated(const fs::path &srcFilePath) const { } CollectionUtils::FileSet Synchronizer::getOutdatedSourcePaths() const { - return CollectionUtils::filterOut(getAllFiles(), [this](fs::path const &sourcePath) { + return CollectionUtils::filterOut(getSourceFiles(), [this](fs::path const &sourcePath) { return !isProbablyOutdated(sourcePath); }); } +StubSet Synchronizer::getOutdatedStubs() const { + auto allFiles = getStubsFiles(); + auto outdatedStubs = CollectionUtils::filterOut(allFiles, [this](StubOperator const &stubOperator) { + return !isProbablyOutdated(stubOperator.getSourceFilePath()); + }); + return outdatedStubs; +} + bool Synchronizer::removeStubIfSourceAbsent(const StubOperator &stub) const { if (!fs::exists(stub.getSourceFilePath())) { try { @@ -113,17 +120,17 @@ void Synchronizer::synchronize(const types::TypesHandler &typesHandler) { if (TypeUtils::isSameType(*this->testGen)) { return; } - auto outdatedSourcePaths = getOutdatedSourcePaths(); if (testGen->settingsContext.useStubs) { - auto outdatedStubs = getStubSetFromSources(outdatedSourcePaths); + auto outdatedStubs = getOutdatedStubs(); synchronizeStubs(outdatedStubs, typesHandler); } + auto outdatedSourcePaths = getOutdatedSourcePaths(); synchronizeWrappers(outdatedSourcePaths); } void Synchronizer::synchronizeStubs(StubSet &outdatedStubs, const types::TypesHandler &typesHandler) { - StubSet allStubs = getStubSetFromSources(getAllFiles()); + StubSet allStubs = getStubsFiles(); auto stubDirPath = Paths::getStubsDirPath(testGen->projectContext); prepareDirectory(stubDirPath); auto filesInFolder = Paths::findFilesInFolder(stubDirPath); @@ -145,7 +152,7 @@ void Synchronizer::synchronizeStubs(StubSet &outdatedStubs, auto options = Fetcher::Options::Value::FUNCTION | Fetcher::Options::Value::INCLUDE | Fetcher::Options::Value::TYPE; auto stubFetcher = - Fetcher(options, testGen->compilationDatabase, sourceFilesMap, &testGen->types, + Fetcher(options, testGen->getProjectBuildDatabase()->compilationDatabase, sourceFilesMap, &testGen->types, &sizeContext->pointerSize, &sizeContext->maximumAlignment, testGen->compileCommandsJsonPath, false); @@ -157,7 +164,7 @@ void Synchronizer::synchronizeStubs(StubSet &outdatedStubs, auto stubsCdb = createStubsCompilationDatabase(stubFiles, ccJsonStubDirPath); auto sourceToHeaderRewriter = - SourceToHeaderRewriter(testGen->projectContext, testGen->compilationDatabase, + SourceToHeaderRewriter(testGen->projectContext, testGen->getProjectBuildDatabase()->compilationDatabase, stubFetcher.getStructsToDeclare(), testGen->serverBuildDir); for (const StubOperator &outdatedStub : outdatedStubs) { @@ -190,7 +197,7 @@ Synchronizer::createStubsCompilationDatabase(StubSet &stubFiles, void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths) const { auto sourceFilesNeedToRegenerateWrappers = outdatedSourcePaths; - for (fs::path const &sourceFilePath : getAllFiles()) { + for (fs::path const &sourceFilePath : getSourceFiles()) { if (!CollectionUtils::contains(sourceFilesNeedToRegenerateWrappers, sourceFilePath)) { auto wrapperFilePath = Paths::getWrapperFilePath(testGen->projectContext, sourceFilePath); @@ -203,14 +210,19 @@ void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedS sourceFilesNeedToRegenerateWrappers, testGen->progressWriter, "Generating wrappers", [this](fs::path const &sourceFilePath) { SourceToHeaderRewriter sourceToHeaderRewriter(testGen->projectContext, - testGen->compilationDatabase, nullptr, + testGen->getProjectBuildDatabase()->compilationDatabase, nullptr, testGen->serverBuildDir); std::string wrapper = sourceToHeaderRewriter.generateWrapper(sourceFilePath); printer::SourceWrapperPrinter(Paths::getSourceLanguage(sourceFilePath)).print(testGen->projectContext, sourceFilePath, wrapper); }); } -const CollectionUtils::FileSet &Synchronizer::getAllFiles() const { - return testGen->compilationDatabase->getAllFiles(); + +const CollectionUtils::FileSet &Synchronizer::getSourceFiles() const { + return testGen->getTargetBuildDatabase()->compilationDatabase->getAllFiles(); +} + +StubSet Synchronizer::getStubsFiles() const { + return getStubSetFromSources(testGen->getProjectBuildDatabase()->compilationDatabase->getAllFiles()); } void Synchronizer::prepareDirectory(const fs::path &stubDirectory) { @@ -221,7 +233,7 @@ void Synchronizer::prepareDirectory(const fs::path &stubDirectory) { if (!Paths::isHeaderFile(stubPath)) { fs::path sourcePath = Paths::stubPathToSourcePath(testGen->projectContext, stubPath); - if (!CollectionUtils::contains(getAllFiles(), sourcePath)) { + if (!CollectionUtils::contains(getSourceFiles(), sourcePath)) { LOG_S(DEBUG) << "Found extra file in stub directory: " << stubPath << ". Removing it."; fs::remove(stubPath); diff --git a/server/src/Synchronizer.h b/server/src/Synchronizer.h index 30bca12b5..4a8c1ccf8 100644 --- a/server/src/Synchronizer.h +++ b/server/src/Synchronizer.h @@ -21,10 +21,11 @@ class StubOperator { class Synchronizer { BaseTestGen *const testGen; - StubGen const *const stubGen; types::TypesHandler::SizeContext *sizeContext; - CollectionUtils::FileSet getOutdatedSourcePaths() const; + [[nodiscard]] CollectionUtils::FileSet getOutdatedSourcePaths() const; + + [[nodiscard]] std::unordered_set getOutdatedStubs() const; bool isProbablyOutdated(const fs::path &srcFilePath) const; @@ -42,18 +43,21 @@ class Synchronizer { void prepareDirectory(fs::path const& stubDirectory); static std::unordered_set + getStubSetFromSources(const CollectionUtils::FileSet &paths); public: static std::unordered_set + dropHeaders(const std::unordered_set &stubs); static CollectionUtils::FileSet dropHeaders(const CollectionUtils::FileSet &files); - Synchronizer(BaseTestGen *testGen, StubGen const *stubGen, types::TypesHandler::SizeContext *sizeContext); + Synchronizer(BaseTestGen *testGen, types::TypesHandler::SizeContext *sizeContext); void synchronize(const types::TypesHandler &typesHandler); - const CollectionUtils::FileSet &getAllFiles() const; + [[nodiscard]] const CollectionUtils::FileSet &getSourceFiles() const; + [[nodiscard]] std::unordered_set getStubsFiles() const; }; diff --git a/server/src/building/BaseCommand.cpp b/server/src/building/BaseCommand.cpp index 8cbd20c3b..0e9a70574 100644 --- a/server/src/building/BaseCommand.cpp +++ b/server/src/building/BaseCommand.cpp @@ -7,11 +7,11 @@ #include "tasks/ShellExecTask.h" #include "utils/CollectionUtils.h" #include "utils/StringUtils.h" +#include "utils/path/FileSystemPath.h" #include "loguru.h" #include -#include "utils/path/FileSystemPath.h" #include #include #include @@ -20,26 +20,33 @@ namespace utbot { BaseCommand::BaseCommand(std::list commandLine, fs::path directory, bool shouldChangeDirectory) : commandLine(std::move(commandLine)), directory(std::move(directory)), shouldChangeDirectory{shouldChangeDirectory} { initOptimizationLevel(); + initOutput(); } + BaseCommand::BaseCommand(std::vector commandLine, fs::path directory, bool shouldChangeDirectory) : commandLine(commandLine.begin(), commandLine.end()), directory(std::move(directory)), shouldChangeDirectory{shouldChangeDirectory} { initOptimizationLevel(); + initOutput(); } BaseCommand::BaseCommand(BaseCommand const &other) - : directory(other.directory), commandLine(other.commandLine), - environmentVariables(other.environmentVariables), shouldChangeDirectory(other.shouldChangeDirectory) { + : directory(other.directory), commandLine(other.commandLine), + environmentVariables(other.environmentVariables), shouldChangeDirectory(other.shouldChangeDirectory), + output(other.output) { if (other.optimizationLevel.has_value()) { optimizationLevel = - std::next(commandLine.begin(), - std::distance(other.commandLine.begin(), - other.optimizationLevel.value())); + std::next(commandLine.begin(), + std::distance(other.commandLine.begin(), + other.optimizationLevel.value())); } } + BaseCommand::BaseCommand(BaseCommand &&other) noexcept : directory(std::move(other.directory)), commandLine(std::move(other.commandLine)), environmentVariables(std::move(other.environmentVariables)), - optimizationLevel(other.optimizationLevel), shouldChangeDirectory(other.shouldChangeDirectory) { + optimizationLevel(other.optimizationLevel), + output(other.output), + shouldChangeDirectory(other.shouldChangeDirectory) { } void BaseCommand::initOptimizationLevel() { @@ -48,6 +55,14 @@ namespace utbot { optimizationLevel = it; } } + + void BaseCommand::initOutput() { + auto it = findOutput(); + if (it != commandLine.end()) { + output = it; + } + } + BaseCommand::iterator BaseCommand::findOutput() { auto it = std::find(commandLine.begin(), commandLine.end(), "-o"); if (it != commandLine.end()) { @@ -127,4 +142,20 @@ namespace utbot { optimizationLevel = addFlagToBegin(flag); } } + + fs::path BaseCommand::getBuildTool() const { + return *commandLine.begin(); + } + + void BaseCommand::setBuildTool(fs::path buildTool) { + *(commandLine.begin()) = std::move(buildTool); + } + + fs::path BaseCommand::getOutput() const { + return *output; + } + + void BaseCommand::setOutput(fs::path output) { + *(this->output) = std::move(output); + } } diff --git a/server/src/building/BaseCommand.h b/server/src/building/BaseCommand.h index 8646bb2cc..14ca850b5 100644 --- a/server/src/building/BaseCommand.h +++ b/server/src/building/BaseCommand.h @@ -14,6 +14,9 @@ namespace utbot { class BaseCommand { + private: + void initOutput(); + protected: bool shouldChangeDirectory = false; fs::path directory; @@ -23,6 +26,8 @@ namespace utbot { using iterator = decltype(commandLine)::iterator; using const_iterator = decltype(commandLine)::const_iterator; + iterator output; + std::optional optimizationLevel; void initOptimizationLevel(); @@ -31,7 +36,7 @@ namespace utbot { iterator findOptimizationLevelFlag(); - public: + BaseCommand() = default; BaseCommand(std::list commandLine, fs::path directory, bool shouldChangeDirectory = false); @@ -42,13 +47,17 @@ namespace utbot { BaseCommand(BaseCommand &&other) noexcept; + public: + [[nodiscard]] std::list &getCommandLine(); [[nodiscard]] const std::list &getCommandLine() const; [[nodiscard]] const fs::path &getDirectory() const; - [[nodiscard]] virtual fs::path getOutput() const = 0; + [[nodiscard]] fs::path getOutput() const; + + void setOutput(fs::path output); [[nodiscard]] virtual bool isArchiveCommand() const = 0; @@ -89,6 +98,10 @@ namespace utbot { size_t erase_if(std::function f); void setOptimizationLevel(const std::string &flag); + + [[nodiscard]] fs::path getBuildTool() const; + + void setBuildTool(fs::path buildTool); }; } diff --git a/server/src/building/BuildDatabase.cpp b/server/src/building/BuildDatabase.cpp index 14d1bb896..487ba0ee6 100644 --- a/server/src/building/BuildDatabase.cpp +++ b/server/src/building/BuildDatabase.cpp @@ -8,68 +8,48 @@ #include "utils/DynamicLibraryUtils.h" #include "utils/JsonUtils.h" #include "utils/StringUtils.h" +#include "utils/GrpcUtils.h" +#include "utils/GenerationUtils.h" #include "loguru.h" #include #include -#include #include +#include -static std::string tryConvertOptionToPath(const std::string &possibleFilePath, - const fs::path &dirPath) { - if (StringUtils::startsWith(possibleFilePath, "-")) { - return possibleFilePath; - } - fs::path fullFilePath; - try { - fullFilePath = Paths::getCCJsonFileFullPath(possibleFilePath, dirPath); - } catch (...) { - return possibleFilePath; - } - return fs::exists(fullFilePath) ? fullFilePath.string() : possibleFilePath; +BuildDatabase::BuildDatabase( + fs::path serverBuildDir, + fs::path buildCommandsJsonPath, + fs::path linkCommandsJsonPath, + fs::path compileCommandsJsonPath, + utbot::ProjectContext projectContext +) : serverBuildDir(std::move(serverBuildDir)), + buildCommandsJsonPath(std::move(buildCommandsJsonPath)), + linkCommandsJsonPath(std::move(linkCommandsJsonPath)), + compileCommandsJsonPath(std::move(compileCommandsJsonPath)), + projectContext(std::move(projectContext)) { } -BuildDatabase::BuildDatabase(const fs::path& buildCommandsJsonPath, - fs::path serverBuildDir, - utbot::ProjectContext projectContext) - : serverBuildDir(std::move(serverBuildDir)), projectContext(std::move(projectContext)) { - linkCommandsJsonPath = fs::canonical(buildCommandsJsonPath / "link_commands.json"); - compileCommandsJsonPath = fs::canonical(buildCommandsJsonPath / "compile_commands.json"); - if (!fs::exists(linkCommandsJsonPath) || !fs::exists(compileCommandsJsonPath)) { - throw CompilationDatabaseException("Couldn't open link_commands.json or compile_commands.json files"); - } - auto linkCommandsJson = JsonUtils::getJsonFromFile(linkCommandsJsonPath); - auto compileCommandsJson = JsonUtils::getJsonFromFile(compileCommandsJsonPath); - - createClangCompileCommandsJson(buildCommandsJsonPath, compileCommandsJson); - initInfo(linkCommandsJson); - filterInstalledFiles(); - addLocalSharedLibraries(); - fillTargetInfoParents(); -} - -std::shared_ptr BuildDatabase::create(const utbot::ProjectContext &projectContext) { - fs::path compileCommandsJsonPath = - CompilationUtils::substituteRemotePathToCompileCommandsJsonPath( - projectContext.projectPath, projectContext.buildDirRelativePath); - fs::path serverBuildDir = Paths::getUtbotBuildDir(projectContext); - std::shared_ptr buildDatabase = - std::make_shared(compileCommandsJsonPath, serverBuildDir, projectContext); - return buildDatabase; +BuildDatabase::BuildDatabase(BuildDatabase *baseBuildDatabase) : + serverBuildDir(baseBuildDatabase->serverBuildDir), + projectContext(baseBuildDatabase->projectContext), + buildCommandsJsonPath(baseBuildDatabase->buildCommandsJsonPath), + linkCommandsJsonPath(baseBuildDatabase->linkCommandsJsonPath), + compileCommandsJsonPath(baseBuildDatabase->compileCommandsJsonPath) { } fs::path BuildDatabase::createExplicitObjectFileCompilationCommand(const std::shared_ptr &objectInfo) { if (Paths::isSourceFile(objectInfo->getSourcePath())) { auto outputFile = objectInfo->getOutputFile(); auto tmpObjectFileName = - Paths::createTemporaryObjectFile(outputFile, objectInfo->getSourcePath()); + Paths::createTemporaryObjectFile(outputFile, objectInfo->getSourcePath()); objectInfo->setOutputFile(tmpObjectFileName); // redirect existing compilation command to temporary file LOG_IF_S(ERROR, CollectionUtils::containsKey(objectFileInfos, tmpObjectFileName)) - << "Temporary object file name generated by UTBot is already present in the " - "project: " - << tmpObjectFileName; + << "Temporary object file name generated by UTBot is already present in the " + "project: " + << tmpObjectFileName; objectInfo->linkUnit = outputFile; objectFileInfos[tmpObjectFileName] = objectInfo; return tmpObjectFileName; @@ -78,130 +58,23 @@ fs::path BuildDatabase::createExplicitObjectFileCompilationCommand(const std::sh } } -void BuildDatabase::createClangCompileCommandsJson(const fs::path &buildCommandsJsonPath, - const nlohmann::json &compileCommandsJson) { - CollectionUtils::MapFileTo>> fileCompileCommands; - for (auto const& compileCommand: compileCommandsJson) { - auto objectInfo = std::make_shared(); - - fs::path directory = compileCommand.at("directory").get(); - fs::path jsonFile = compileCommand.at("file").get(); - fs::path sourceFile = Paths::getCCJsonFileFullPath(jsonFile, directory); - - std::vector jsonArguments; - if (compileCommand.contains("command")) { - std::string command = compileCommand.at("command"); - jsonArguments = StringUtils::splitByWhitespaces(command); - } else { - jsonArguments = std::vector(compileCommand.at("arguments")); - } - std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(), - [&directory](const std::string &argument) { - return tryConvertOptionToPath(argument, directory); - }); - objectInfo->command = utbot::CompileCommand(jsonArguments, directory, sourceFile); - objectInfo->command.removeWerror(); - fs::path outputFile = objectInfo->getOutputFile(); - fs::path kleeFilePathTemplate = - Paths::createNewDirForFile(sourceFile, projectContext.buildDir(), serverBuildDir); - fs::path kleeFile = Paths::addSuffix(kleeFilePathTemplate, "_klee"); - objectInfo->kleeFilesInfo = std::make_shared(kleeFile); - - if (CollectionUtils::containsKey(objectFileInfos, outputFile) || CollectionUtils::containsKey(targetInfos, outputFile)) { - /* - * If the condition above is true, that means that the output file - * is built from multiple sources. Hence, it is not an object file, - * but an executable, and it should be treated as a target. - * This is a hack. This inconsistency is produced by Bear - * when it treats a Makefile command like - * gcc -o output a.c b.c c.c - * This code is creating artificial compile and link commands, similar - * to commands Bear generates from CMake command like - * add_executable(output a.c b.c c.c) - */ - auto targetInfo = targetInfos[outputFile]; - if (targetInfo == nullptr) { - LOG_S(DEBUG) << outputFile << " is treated as a target instead of an object file"; - auto targetObjectInfo = objectFileInfos[outputFile]; - auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(targetObjectInfo); - objectFileInfos.erase(outputFile); - - //create targetInfo - targetInfo = targetInfos[outputFile] = std::make_shared(); - targetInfo->commands.emplace_back( - std::initializer_list{ targetObjectInfo->command.getCompiler(), - "-o", outputFile, tmpObjectFileName }, - directory); - targetInfo->addFile(tmpObjectFileName); - } - //redirect new compilation command to temporary file - auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(objectInfo); - - //add new dependency to an implicit target - targetInfo->commands[0].addFlagToEnd(tmpObjectFileName); - targetInfo->addFile(tmpObjectFileName); - } else { - objectFileInfos[outputFile] = objectInfo; - } - const fs::path &sourcePath = objectInfo->getSourcePath(); - if (!CollectionUtils::containsKey(sourceFileInfos, sourcePath) || - conflictPriorityMore(objectInfo, fileCompileCommands[sourcePath].second)) { - fileCompileCommands[sourcePath] = { compileCommand, objectInfo }; - } - sourceFileInfos[sourcePath].emplace_back(objectInfo); - } - for (auto &[sourceFile, objectInfos]: sourceFileInfos) { - std::sort(objectInfos.begin(), objectInfos.end(), conflictPriorityMore); +void BuildDatabase::createClangCompileCommandsJson() { + CollectionUtils::MapFileTo fileCompileCommands; + for (const auto &[sourcePath, objectInfos]: sourceFileInfos) { + const std::shared_ptr &objectInfo = objectInfos.front(); + fileCompileCommands[sourcePath] = {{"directory", objectInfo->command.getDirectory()}, + {"command", objectInfo->command.toString()}, + {"file", objectInfo->command.getSourcePath()}}; } + nlohmann::json compileCommandsSingleFilesJson; for (const auto &compileCommand: fileCompileCommands) { - compileCommandsSingleFilesJson.push_back(compileCommand.second.first); + compileCommandsSingleFilesJson.push_back(compileCommand.second); } + fs::path clangCompileCommandsJsonPath = CompilationUtils::getClangCompileCommandsJsonPath(buildCommandsJsonPath); JsonUtils::writeJsonToFile(clangCompileCommandsJsonPath, compileCommandsSingleFilesJson); -} - -void BuildDatabase::initInfo(const nlohmann::json &linkCommandsJson) { - for (nlohmann::json const &linkCommand : linkCommandsJson) { - fs::path directory = linkCommand.at("directory").get(); - std::vector jsonArguments; - if (linkCommand.contains("command")) { - std::string command = linkCommand.at("command"); - jsonArguments = StringUtils::splitByWhitespaces(command); - } else { - jsonArguments = std::vector(linkCommand.at("arguments")); - } - if (StringUtils::endsWith(jsonArguments[0], "ranlib") || - StringUtils::endsWith(jsonArguments[0], "cmake")) { - continue; - } - std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(), - [&directory](const std::string &argument) { - return tryConvertOptionToPath(argument, directory); - }); - - mergeLibraryOptions(jsonArguments); - - utbot::LinkCommand command(jsonArguments, directory); - fs::path const &output = command.getOutput(); - auto targetInfo = targetInfos[output]; - if (targetInfo == nullptr) { - targetInfo = targetInfos[output] = std::make_shared(); - } - for (nlohmann::json const &jsonFile : linkCommand.at("files")) { - auto filename = jsonFile.get(); - fs::path currentFile = Paths::getCCJsonFileFullPath(filename, command.getDirectory()); - targetInfo->addFile(currentFile); - if (Paths::isObjectFile(currentFile)) { - if (!CollectionUtils::containsKey(objectFileInfos, currentFile)) { - throw CompilationDatabaseException("compile_commands.json doesn't contain a command for object file " - + currentFile.string()); - } - objectFileInfos[currentFile]->linkUnit = output; - } - } - targetInfo->commands.emplace_back(command); - } + compilationDatabase = CompilationUtils::getCompilationDatabase(clangCompileCommandsJsonPath); } void BuildDatabase::mergeLibraryOptions(std::vector &jsonArguments) const { @@ -219,7 +92,7 @@ namespace { CollectionUtils::OrderedFileSet collectLibraryDirs(const utbot::BaseCommand &command) { using namespace DynamicLibraryUtils; CollectionUtils::OrderedFileSet libraryDirs; - for (std::string const &argument : command.getCommandLine()) { + for (std::string const &argument: command.getCommandLine()) { auto optionalLibraryPath = getLibraryAbsolutePath(argument, command.getDirectory()); if (optionalLibraryPath.has_value()) { libraryDirs.insert(optionalLibraryPath.value()); @@ -227,7 +100,7 @@ namespace { if (StringUtils::startsWith(argument, libraryDirOptionWl)) { auto commaSeparated = StringUtils::split(argument, ','); bool isRpathNext = false; - for (auto part : commaSeparated) { + for (auto part: commaSeparated) { if (part == rpathFlag) { isRpathNext = true; continue; @@ -247,7 +120,7 @@ namespace { CollectionUtils::MapFileTo libraryNames; - for (const auto &argument : command.getCommandLine()) { + for (const auto &argument: command.getCommandLine()) { if (Paths::isSharedLibraryFile(argument) && argument != command.getOutput() && !StringUtils::startsWith(argument, libraryDirOptionWl)) { libraryNames.emplace(argument, argument); @@ -274,9 +147,9 @@ void BuildDatabase::addLibrariesForCommand(utbot::BaseCommand &command, auto libraryDirs = collectLibraryDirs(command); auto libraryNames = collectLibraryNames(command); std::unordered_map argumentToFile; - for (auto const &[libraryName, argument] : libraryNames) { + for (auto const &[libraryName, argument]: libraryNames) { fs::path name = libraryName; - for (auto const &libraryDir : libraryDirs) { + for (auto const &libraryDir: libraryDirs) { if (CollectionUtils::containsKey(sharedLibraryFiles, name)) { if (CollectionUtils::containsKey(sharedLibraryFiles.at(name), libraryDir)) { name = sharedLibraryFiles.at(name).at(libraryDir); @@ -293,72 +166,13 @@ void BuildDatabase::addLibrariesForCommand(utbot::BaseCommand &command, } } } - for (auto &argument : command.getCommandLine()) { + for (auto &argument: command.getCommandLine()) { if (CollectionUtils::containsKey(argumentToFile, argument)) { argument = argumentToFile[argument]; } } } -void BuildDatabase::filterInstalledFiles() { - for (auto &it : targetInfos) { - auto &linkFile = it.first; - auto &targetInfo = it.second; - CollectionUtils::OrderedFileSet fileset; - targetInfo->installedFiles = - CollectionUtils::filterOut(targetInfo->files, [this](fs::path const &file) { - return CollectionUtils::containsKey(targetInfos, file) || - CollectionUtils::containsKey(objectFileInfos, file); - }); - if (!targetInfo->installedFiles.empty()) { - LOG_S(DEBUG) << "Target " << linkFile << " depends on " << targetInfo->installedFiles.size() << " installed files"; - } - CollectionUtils::erase_if(targetInfo->files, [&targetInfo](fs::path const &file) { - return CollectionUtils::contains(targetInfo->installedFiles, file); - }); - } -} - -void BuildDatabase::addLocalSharedLibraries() { - sharedLibrariesMap sharedLibraryFiles; - for (const auto &[linkFile, linkUnit] : targetInfos) { - if (Paths::isSharedLibraryFile(linkFile)) { - auto withoutVersion = CompilationUtils::removeSharedLibraryVersion(linkFile); - sharedLibraryFiles[withoutVersion.filename()][linkFile.parent_path()] = linkFile; - } - } - for (auto &[linkFile, targetInfo] : targetInfos) { - for (auto &command : targetInfo->commands) { - addLibrariesForCommand(command, *targetInfo, sharedLibraryFiles); - } - } - for (auto &[objectFile, objectInfo] : objectFileInfos) { - addLibrariesForCommand(objectInfo->command, *objectInfo, sharedLibraryFiles, true); - } -} - -void BuildDatabase::fillTargetInfoParents() { - CollectionUtils::MapFileTo> parentTargets; - for (const auto &[linkFile, linkUnit] : targetInfos) { - for (const fs::path &dependencyFile : linkUnit->files) { - if (Paths::isLibraryFile(dependencyFile)) { - parentTargets[dependencyFile].emplace_back(linkFile); - } - if (Paths::isObjectFile(dependencyFile)) { - objectFileTargets[dependencyFile].emplace_back(linkFile); - } - } - } - for (auto &[library, parents] : parentTargets) { - if (!CollectionUtils::containsKey(targetInfos, library)) { - throw CompilationDatabaseException( - "link_commands.json doesn't contain a command for building library: " + - library.string() + "\nReferenced from command for: " + (parents.empty() ? "none" : parents[0].string())); - } - targetInfos[library]->parentLinkUnits = std::move(parents); - } -} - const fs::path &BuildDatabase::getCompileCommandsJson() { return compileCommandsJsonPath; } @@ -370,7 +184,7 @@ const fs::path &BuildDatabase::getLinkCommandsJson() { std::vector> BuildDatabase::getAllCompileCommands() const { std::vector> result; - for (auto &[file, compilationUnit] : objectFileInfos) { + for (auto &[file, compilationUnit]: objectFileInfos) { result.emplace_back(compilationUnit); } return result; @@ -391,42 +205,65 @@ CollectionUtils::FileSet BuildDatabase::getArchiveObjectFiles(const fs::path &ar } if (!CollectionUtils::containsKey(targetInfos, archive)) { throw CompilationDatabaseException( - "Couldn't find current archive file linkage information for " + archive.string()); + "Couldn't find current archive file linkage information for " + archive.string()); } std::shared_ptr targetInfo = targetInfos.at(archive); CollectionUtils::FileSet result; - for (const auto &file : targetInfo->files) { + for (const auto &file: targetInfo->files) { if (Paths::isLibraryFile(file)) { auto archiveObjectFiles = getArchiveObjectFiles(file); CollectionUtils::extend(result, archiveObjectFiles); } else { - const fs::path &sourcePath = getClientCompilationUnitInfo(file)->getSourcePath(); + const fs::path &sourcePath = getClientCompilationObjectInfo(file)->getSourcePath(); if (Paths::isSourceFile(sourcePath)) { result.insert(file); } else { - LOG_S(WARNING) << "Skipping source file " << file; + LOG_S(WARNING) << "Skipping not c/c++ source file: " << sourcePath.string(); } } } return result; } -fs::path BuildDatabase::getRootForSource(const fs::path& path) const { +CollectionUtils::FileSet BuildDatabase::getArchiveTargetFiles(const fs::path &archive) const { + if (Paths::isGtest(archive)) { + return {}; + } + if (!CollectionUtils::containsKey(targetInfos, archive)) { + throw CompilationDatabaseException( + "Couldn't find current archive file linkage information for " + archive.string()); + } + std::shared_ptr targetInfo = targetInfos.at(archive); + CollectionUtils::FileSet result = {archive}; + for (const auto &file: targetInfo->files) { + if (Paths::isLibraryFile(file)) { + auto archiveObjectFiles = getArchiveTargetFiles(file); + result.insert(file); + CollectionUtils::extend(result, archiveObjectFiles); + } + } + return result; +} + +fs::path BuildDatabase::getRootForSource(const fs::path &path) const { fs::path normalizedPath = Paths::normalizedTrimmed(path); if (Paths::isSourceFile(normalizedPath)) { if (!CollectionUtils::containsKey(sourceFileInfos, normalizedPath)) { - throw CompilationDatabaseException("No executable or library found for current source file in link_commands.json: " + path.string()); + throw CompilationDatabaseException( + "No executable or library found for current source file in link_commands.json: " + path.string()); } auto const &sourceFileInfo = sourceFileInfos.at(normalizedPath); auto linkUnit = sourceFileInfo[0]->linkUnit; if (linkUnit.empty()) { - throw CompilationDatabaseException("No executable or library found for current source file in link_commands.json: " + path.string()); + throw CompilationDatabaseException( + "No executable or library found for current source file in link_commands.json: " + path.string()); } return getRootForSource(linkUnit); } else { if (!CollectionUtils::containsKey(targetInfos, normalizedPath)) { - throw CompilationDatabaseException("No executable or library found for current library in link_commands.json: " + path.string()); + throw CompilationDatabaseException( + "No executable or library found for current library in link_commands.json: " + path.string()); } auto linkUnit = targetInfos.at(normalizedPath); if (!linkUnit->parentLinkUnits.empty()) { @@ -437,6 +274,10 @@ fs::path BuildDatabase::getRootForSource(const fs::path& path) const { } } +fs::path BuildDatabase::getRootForFirstSource() const { + return getRootForSource(sourceFileInfos.begin()->first); +} + fs::path BuildDatabase::getBitcodeForSource(const fs::path &sourceFile) const { fs::path serverBuildObjectFilePath = newDirForFile(sourceFile); return Paths::addExtension(serverBuildObjectFilePath, ".bc"); @@ -461,24 +302,41 @@ fs::path BuildDatabase::getBitcodeFile(const fs::path &filepath) const { } } + +std::shared_ptr +BuildDatabase::getClientCompilationObjectInfo(const fs::path &filepath) const { + if (!CollectionUtils::contains(objectFileInfos, filepath)) { + throw CompilationDatabaseException("Object file not found in compilation_commands.json: " + filepath.string()); + } + return objectFileInfos.at(filepath); +} + +std::shared_ptr +BuildDatabase::getClientCompilationSourceInfo(const fs::path &filepath) const { + if (!CollectionUtils::contains(sourceFileInfos, filepath)) { + throw CompilationDatabaseException("Source file not found in compilation_commands.json: " + filepath.string()); + } + LOG_IF_S(DEBUG, sourceFileInfos.at(filepath).size() > 1) << "More than one compile command for: " << filepath; + return sourceFileInfos.at(filepath)[0]; +} + std::shared_ptr BuildDatabase::getClientCompilationUnitInfo(const fs::path &filepath) const { if (Paths::isSourceFile(filepath)) { - if (!CollectionUtils::contains(sourceFileInfos, filepath)) { - throw CompilationDatabaseException("File not found in compilation_commands.json: " + filepath.string()); - } - return sourceFileInfos.at(filepath)[0]; - } if (Paths::isObjectFile(filepath)) { - if (!CollectionUtils::contains(objectFileInfos, filepath)) { - throw CompilationDatabaseException("File not found in compilation_commands.json: " + filepath.string()); - } - return objectFileInfos.at(filepath); + return getClientCompilationSourceInfo(filepath); + } + if (Paths::isObjectFile(filepath)) { + return getClientCompilationObjectInfo(filepath); } throw CompilationDatabaseException("File is not a compilation unit or an object file: " + filepath.string()); } -std::shared_ptr -BuildDatabase::getClientLinkUnitInfo(const fs::path &filepath) const { + +[[nodiscard]] bool BuildDatabase::hasUnitInfo(const fs::path &filepath) const { + return CollectionUtils::contains(sourceFileInfos, filepath) || CollectionUtils::contains(objectFileInfos, filepath); +} + +std::shared_ptr BuildDatabase::getClientLinkUnitInfo(const fs::path &filepath) const { if (Paths::isSourceFile(filepath)) { auto compilationInfo = getClientCompilationUnitInfo(filepath); return targetInfos.at(compilationInfo->linkUnit); @@ -490,9 +348,9 @@ BuildDatabase::getClientLinkUnitInfo(const fs::path &filepath) const { filepath.string()); } -bool BuildDatabase::conflictPriorityMore( - const std::shared_ptr &left, - const std::shared_ptr &right) { +bool BuildDatabase::ObjectFileInfo::conflictPriorityMore( + const std::shared_ptr &left, + const std::shared_ptr &right) { if (StringUtils::contains(left->getOutputFile().string(), "64")) { return true; } @@ -535,11 +393,11 @@ fs::path BuildDatabase::KleeFilesInfo::getKleeBitcodeFile() { return getKleeBitcodeFile(""); } -fs::path BuildDatabase::KleeFilesInfo::getKleeFile(const std::string& methodName) { +fs::path BuildDatabase::KleeFilesInfo::getKleeFile(const std::string &methodName) { return kleeFile; } -fs::path BuildDatabase::KleeFilesInfo::getKleeBitcodeFile(const std::string& methodName) { +fs::path BuildDatabase::KleeFilesInfo::getKleeBitcodeFile(const std::string &methodName) { return getCorrespondingBitcodeFile(getKleeFile()); } @@ -563,7 +421,7 @@ void BuildDatabase::ObjectFileInfo::setOutputFile(const fs::path &file) { command.setOutput(file); } -void BuildDatabase::ObjectFileInfo::addFile(fs::path file) { +void BuildDatabase::BaseFileInfo::addFile(fs::path file) { files.insert(std::move(file)); } @@ -571,28 +429,10 @@ bool BuildDatabase::ObjectFileInfo::is32bits() const { return CollectionUtils::contains(command.getCommandLine(), "-m32"); } -void BuildDatabase::TargetInfo::addFile(fs::path file) { - files.insert(std::move(file)); -} - fs::path BuildDatabase::TargetInfo::getOutput() const { return commands[0].getOutput(); } -CollectionUtils::FileSet BuildDatabase::getStubFiles( - const std::shared_ptr &linkUnitInfo) const { - auto iterator = linkUnitToStubFiles.find(linkUnitInfo); - if (iterator != linkUnitToStubFiles.end()) { - return iterator->second; - } - return {}; -} -void BuildDatabase::assignStubFilesToLinkUnit( - std::shared_ptr linkUnitInfo, - CollectionUtils::FileSet stubs) { - linkUnitToStubFiles.emplace(linkUnitInfo, std::move(stubs)); -} - std::vector> BuildDatabase::getRootTargets() const { return CollectionUtils::filterOut( CollectionUtils::getValues(targetInfos), @@ -605,10 +445,18 @@ std::vector> BuildDatabase::getAllTar return CollectionUtils::getValues(targetInfos); } +std::vector BuildDatabase::getAllTargetPaths() const { + return CollectionUtils::transformTo>(CollectionUtils::getValues(targetInfos), + [](const std::shared_ptr &targetInfo) { + return targetInfo->getOutput(); + }); +} + std::vector> BuildDatabase::getTargetsForSourceFile(const fs::path &sourceFilePath) const { CollectionUtils::MapFileTo cache; - std::function containsSourceFilePath = [&](fs::path const &unitFile) { + std::function< + bool(fs::path const &)> containsSourceFilePath = [&](fs::path const &unitFile) { if (CollectionUtils::containsKey(cache, unitFile)) { return cache[unitFile]; } @@ -619,9 +467,9 @@ BuildDatabase::getTargetsForSourceFile(const fs::path &sourceFilePath) const { } auto linkUnitInfo = getClientLinkUnitInfo(unitFile); bool result = CollectionUtils::anyTrue(CollectionUtils::transform( - linkUnitInfo->files, [&containsSourceFilePath](fs::path const &subFile) { - return containsSourceFilePath(subFile); - })); + linkUnitInfo->files, [&containsSourceFilePath](fs::path const &subFile) { + return containsSourceFilePath(subFile); + })); return cache[unitFile] = result; }; @@ -632,30 +480,29 @@ BuildDatabase::getTargetsForSourceFile(const fs::path &sourceFilePath) const { }); } -std::vector -BuildDatabase::autoTargetListForFile(const fs::path &sourceFilePath, const fs::path &objectFile) const { +std::vector BuildDatabase::getTargetPathsForSourceFile(const fs::path &sourceFilePath) const { + auto result = CollectionUtils::transformTo>( + getTargetsForSourceFile(sourceFilePath), + [&](const std::shared_ptr &targetInfo) { + return targetInfo->getOutput(); + }); + return result; +} - auto result = CollectionUtils::transformTo>(getTargetsForSourceFile(sourceFilePath), - [&](const std::shared_ptr &targetInfo) { - return targetInfo->getOutput(); - }); +std::vector BuildDatabase::getTargetPathsForObjectFile(const fs::path &objectFile) const { std::vector parents; if (CollectionUtils::containsKey(objectFileTargets, objectFile)) { parents = objectFileTargets.at(objectFile); } else { LOG_S(WARNING) << "No link unit parents were found for an object file: " << objectFile; } - result.insert( - result.end(), - std::make_move_iterator(parents.begin()), - std::make_move_iterator(parents.end()) - ); - return result; + return parents; } std::shared_ptr BuildDatabase::getPriorityTarget() const { CollectionUtils::MapFileTo cache; - std::function numberOfSources = [&](fs::path const &unitFile) { + std::function< + int(fs::path const &)> numberOfSources = [&](fs::path const &unitFile) { if (CollectionUtils::containsKey(cache, unitFile)) { return cache[unitFile]; } @@ -664,7 +511,7 @@ std::shared_ptr BuildDatabase::getPriorityTarget() co } auto linkUnitInfo = getClientLinkUnitInfo(unitFile); int result = 0; - for (const fs::path &subFile : linkUnitInfo->files) { + for (const fs::path &subFile: linkUnitInfo->files) { result += numberOfSources(subFile); } return cache[unitFile] = result; @@ -672,15 +519,28 @@ std::shared_ptr BuildDatabase::getPriorityTarget() co auto rootTargets = getRootTargets(); auto it = std::max_element(rootTargets.begin(), rootTargets.end(), - [&](std::shared_ptr a, - std::shared_ptr b) { + [&](const std::shared_ptr &a, + const std::shared_ptr &b) { return numberOfSources(a->getOutput()) < numberOfSources(b->getOutput()); }); return *it; } + fs::path BuildDatabase::newDirForFile(const fs::path &file) const { fs::path base = Paths::longestCommonPrefixPath(this->projectContext.buildDir(), this->projectContext.projectPath); return Paths::createNewDirForFile(file, base, this->serverBuildDir); } + +CollectionUtils::FileSet BuildDatabase::getSourceFilesForTarget(const fs::path &_target) { + return CollectionUtils::transformTo( + getArchiveObjectFiles(_target), + [this](fs::path const &objectPath) { + return getClientCompilationUnitInfo(objectPath)->getSourcePath(); + }); +} + +std::shared_ptr BuildDatabase::getTargetInfo(const fs::path &_target) { + return targetInfos[_target]; +} diff --git a/server/src/building/BuildDatabase.h b/server/src/building/BuildDatabase.h index 3015284c6..8c17f1d92 100644 --- a/server/src/building/BuildDatabase.h +++ b/server/src/building/BuildDatabase.h @@ -22,12 +22,17 @@ class BuildDatabase { explicit KleeFilesInfo(fs::path kleeFile); void setCorrectMethods(std::unordered_set correctMethods); + void setAllAreCorrect(bool allAreCorrect); bool isCorrectMethod(const std::string &method); + fs::path getKleeFile(); + fs::path getKleeBitcodeFile(); + fs::path getKleeFile(const std::string &methodName); + fs::path getKleeBitcodeFile(const std::string &methodName); private: @@ -38,13 +43,17 @@ class BuildDatabase { struct BaseFileInfo { BaseFileInfo() = default; + virtual ~BaseFileInfo() = default; + // Object files and libraries that current command depends on + CollectionUtils::OrderedFileSet files; + // Libraries that current command depends on, but those are already installed and not built // within project CollectionUtils::OrderedFileSet installedFiles; - virtual void addFile(fs::path file) = 0; + void addFile(fs::path file); }; /* @@ -55,9 +64,6 @@ class BuildDatabase { // Compilation command utbot::CompileCommand command; - // Object files and libraries that current command depends on - CollectionUtils::OrderedFileSet files; - // Example of executable or a library which contains current objectFile fs::path linkUnit; @@ -66,8 +72,10 @@ class BuildDatabase { // Directory from where to execute the command [[nodiscard]] fs::path const &getDirectory() const; + // User source file [[nodiscard]] fs::path getSourcePath() const; + // User object file [[nodiscard]] fs::path getOutputFile() const; @@ -75,7 +83,8 @@ class BuildDatabase { void setOutputFile(const fs::path &file); - void addFile(fs::path file) override; + static bool conflictPriorityMore(const std::shared_ptr &left, + const std::shared_ptr &right); }; /* @@ -88,26 +97,16 @@ class BuildDatabase { // Linkage command std::vector commands; - // Source files, object files and libraries that current command depends on - CollectionUtils::OrderedFileSet files; - // Units which contains current library std::vector parentLinkUnits; - void addFile(fs::path file) override; - // Executable or a library, the result of a command [[nodiscard]] fs::path getOutput() const; }; public: - BuildDatabase(const fs::path &buildCommandsJsonPath, - fs::path serverBuildDir, - utbot::ProjectContext projectContext); - - static std::shared_ptr create(const utbot::ProjectContext &projectContext); - const fs::path &getCompileCommandsJson(); + const fs::path &getLinkCommandsJson(); /** @@ -121,6 +120,35 @@ class BuildDatabase { */ [[nodiscard]] CollectionUtils::FileSet getArchiveObjectFiles(const fs::path &archive) const; + /** + * @brief Returns all target that are contained in a library or executable + * + * Recursively iterates over all libraries inside current library or executable. Returns all + * found target + * @param archive Executable or a library for which to find target files + * @return Set of paths to targets path. + * @throws CompilationDatabaseException if files are wrong + */ + [[nodiscard]] CollectionUtils::FileSet getArchiveTargetFiles(const fs::path &archive) const; + + /** + * @brief Returns compile command information for object file + * + * @param filepath Path to object file + * @return ObjectFileInfo for object file + * @throws CompilationDatabaseException if files are wrong + */ + [[nodiscard]] std::shared_ptr getClientCompilationObjectInfo(const fs::path &filepath) const; + + /** + * @brief Returns compile command information for current source file + * + * @param filepath Path to source file or object file + * @return ObjectFileInfo for current source file + * @throws CompilationDatabaseException if files are wrong + */ + [[nodiscard]] std::shared_ptr getClientCompilationSourceInfo(const fs::path &filepath) const; + /** * @brief Returns compile command information for current source file or object file * @@ -130,6 +158,14 @@ class BuildDatabase { */ [[nodiscard]] std::shared_ptr getClientCompilationUnitInfo(const fs::path &filepath) const; + /** + * @brief Returns true if BuildDatabase contains information for current source file or object file + * + * @param filepath Path to source file or object file + * @return true if contains current source file or object file + */ + [[nodiscard]] bool hasUnitInfo(const fs::path &filepath) const; + /** * @brief Returns link command information for current executable or library * @@ -138,6 +174,7 @@ class BuildDatabase { * @throws CompilationDatabaseException if files are wrong */ [[nodiscard]] std::shared_ptr getClientLinkUnitInfo(const fs::path &filepath) const; + [[nodiscard]] fs::path getObjectFile(const fs::path &sourceFile) const; /** @@ -148,7 +185,11 @@ class BuildDatabase { * @throws CompilationDatabaseException if file is wrong */ [[nodiscard]] fs::path getRootForSource(const fs::path &path) const; + + [[nodiscard]] fs::path getRootForFirstSource() const; + [[nodiscard]] fs::path getBitcodeForSource(const fs::path &sourceFile) const; + [[nodiscard]] fs::path getBitcodeFile(const fs::path &filepath) const; /** @@ -171,63 +212,56 @@ class BuildDatabase { */ std::vector> getAllCompileCommands() const; - /** - * @brief Gets all stub files associated with given link unit - * - * @param linkUnitInfo link unit info (preferably library) - * - * @return set of file paths to stubs - */ - CollectionUtils::FileSet - getStubFiles(const std::shared_ptr &linkUnitInfo) const; + virtual std::vector> getRootTargets() const; - /** - * @brief Assign set of file paths to stubs to given link unit - * - * @param linkUnitInfo link unit info (preferably library) - * @param stubs set of file paths to stubs - */ - void assignStubFilesToLinkUnit( - std::shared_ptr linkUnitInfo, - CollectionUtils::FileSet stubs); + virtual std::vector> getAllTargets() const; - std::vector> getRootTargets() const; - std::vector> getAllTargets() const; + virtual std::vector getAllTargetPaths() const; - std::vector - autoTargetListForFile(const fs::path &sourceFilePath, const fs::path &objectFile) const; + virtual std::vector getTargetPathsForSourceFile(const fs::path &sourceFilePath) const; - std::vector> - getTargetsForSourceFile(fs::path const&sourceFilePath) const; + virtual std::vector getTargetPathsForObjectFile(const fs::path &objectFile) const; std::shared_ptr getPriorityTarget() const; -private: - fs::path serverBuildDir; - utbot::ProjectContext projectContext; - fs::path linkCommandsJsonPath; - fs::path compileCommandsJsonPath; + + CollectionUtils::FileSet getSourceFilesForTarget(const fs::path &_target); + + std::shared_ptr getTargetInfo(const fs::path &_target); + + std::shared_ptr compilationDatabase; + +protected: + const fs::path serverBuildDir; + const fs::path buildCommandsJsonPath; + const fs::path linkCommandsJsonPath; + const fs::path compileCommandsJsonPath; + const utbot::ProjectContext projectContext; CollectionUtils::MapFileTo>> sourceFileInfos; CollectionUtils::MapFileTo> objectFileInfos; CollectionUtils::MapFileTo> targetInfos; CollectionUtils::MapFileTo> objectFileTargets; - std::unordered_map, CollectionUtils::FileSet> - linkUnitToStubFiles; + BuildDatabase( + fs::path serverBuildDir, + fs::path buildCommandsJsonPath, + fs::path linkCommandsJsonPath, + fs::path compileCommandsJsonPath, + utbot::ProjectContext projectContext + ); - static bool conflictPriorityMore(const std::shared_ptr &left, - const std::shared_ptr &right); + BuildDatabase(BuildDatabase *baseBuildDatabase); - void filterInstalledFiles(); - void addLocalSharedLibraries(); - void fillTargetInfoParents(); static fs::path getCorrespondingBitcodeFile(const fs::path &filepath); - void createClangCompileCommandsJson(const fs::path &buildCommandsJsonPath, - const nlohmann::json &compileCommandsJson); - void initInfo(const nlohmann::json &linkCommandsJson); + + void createClangCompileCommandsJson(); + void mergeLibraryOptions(std::vector &jsonArguments) const; - fs::path newDirForFile(fs::path const& file) const; - fs::path - createExplicitObjectFileCompilationCommand(const std::shared_ptr &objectInfo); + + fs::path newDirForFile(fs::path const &file) const; + + fs::path createExplicitObjectFileCompilationCommand(const std::shared_ptr &objectInfo); + + std::vector> getTargetsForSourceFile(fs::path const &sourceFilePath) const; using sharedLibrariesMap = std::unordered_map>; diff --git a/server/src/building/CompileCommand.cpp b/server/src/building/CompileCommand.cpp index be7d6fdb2..84482a256 100644 --- a/server/src/building/CompileCommand.cpp +++ b/server/src/building/CompileCommand.cpp @@ -12,7 +12,6 @@ namespace utbot { CompileCommand::CompileCommand(CompileCommand const &other) : BaseCommand(other) { - compiler = commandLine.begin(); sourcePath = std::next(commandLine.begin(), std::distance(other.commandLine.begin(), other.sourcePath)); @@ -21,9 +20,7 @@ namespace utbot { } CompileCommand::CompileCommand(CompileCommand &&other) noexcept : BaseCommand(std::move(other)), - sourcePath(other.sourcePath), - compiler(other.compiler), - output(other.output) { + sourcePath(other.sourcePath) { } CompileCommand &CompileCommand::operator=(const CompileCommand &other) { @@ -53,7 +50,6 @@ namespace utbot { fs::path directory, fs::path sourcePath) : BaseCommand(std::move(arguments), std::move(directory)) { - compiler = commandLine.begin(); { auto it = std::find_if(commandLine.begin(), commandLine.end(), [&sourcePath](std::string const &arg) { return fs::path(arg).filename() == sourcePath.filename(); @@ -61,16 +57,7 @@ namespace utbot { this->sourcePath = it; *this->sourcePath = sourcePath; } - { - auto it = findOutput(); - if (it != commandLine.end()) { - this->output = it; - *this->output = Paths::getCCJsonFileFullPath(*it, this->directory); - } else { - auto path = Paths::getCCJsonFileFullPath(Paths::replaceExtension(*this->sourcePath, ".o"), this->directory); - this->output = std::next(addFlagsToBegin({ "-o", path })); - } - } + initOutput(); } void swap(CompileCommand &a, CompileCommand &b) noexcept { @@ -80,7 +67,6 @@ namespace utbot { std::swap(a.optimizationLevel, b.optimizationLevel); std::swap(a.sourcePath, b.sourcePath); - std::swap(a.compiler, b.compiler); std::swap(a.output, b.output); } @@ -92,26 +78,10 @@ namespace utbot { *(this->sourcePath) = std::move(sourcePath); } - fs::path CompileCommand::getCompiler() const { - return *compiler; - } - - void CompileCommand::setCompiler(fs::path compiler) { - *(this->compiler) = std::move(compiler); - } - - fs::path CompileCommand::getOutput() const { - return *output; - } - bool CompileCommand::isArchiveCommand() const { return false; } - void CompileCommand::setOutput(fs::path output) { - *(this->output) = std::move(output); - } - void CompileCommand::removeCompilerFlagsAndOptions( const std::unordered_set &switchesToRemove) { size_t erased = @@ -128,9 +98,22 @@ namespace utbot { return StringUtils::startsWith(arg, "-I"); }); } + void CompileCommand::removeWerror() { CollectionUtils::erase_if(commandLine, [](const std::string &arg) { return StringUtils::startsWith(arg, "-Werror"); }); } + + void CompileCommand::initOutput() { + auto it = findOutput(); + if (it != commandLine.end()) { + this->output = it; + *this->output = Paths::getCCJsonFileFullPath(*it, this->directory); + } else { + auto path = Paths::getCCJsonFileFullPath(Paths::replaceExtension(*this->sourcePath, ".o"), this->directory); + this->output = std::next(addFlagsToBegin({"-o", path})); + } + + } } diff --git a/server/src/building/CompileCommand.h b/server/src/building/CompileCommand.h index 193797c9c..9e696a1d4 100644 --- a/server/src/building/CompileCommand.h +++ b/server/src/building/CompileCommand.h @@ -15,8 +15,8 @@ namespace utbot { class CompileCommand : public BaseCommand { private: iterator sourcePath; - iterator compiler; - iterator output; + + void initOutput(); public: CompileCommand() = default; @@ -39,16 +39,8 @@ namespace utbot { void setSourcePath(fs::path sourcePath); - [[nodiscard]] fs::path getCompiler() const; - - void setCompiler(fs::path compiler); - - [[nodiscard]] fs::path getOutput() const override; - [[nodiscard]] bool isArchiveCommand() const override; - void setOutput(fs::path output); - void removeCompilerFlagsAndOptions(const std::unordered_set &switchesToRemove); void removeIncludeFlags(); diff --git a/server/src/building/IRParser.cpp b/server/src/building/IRParser.cpp index e602bf902..2b8c95075 100644 --- a/server/src/building/IRParser.cpp +++ b/server/src/building/IRParser.cpp @@ -17,7 +17,7 @@ bool IRParser::parseModule(const fs::path &rootBitcode, tests::TestsMap &tests) { try { - LOG_S(MAX) << "Parse module: " << rootBitcode.c_str(); + LOG_S(DEBUG) << "Parse module: " << rootBitcode.c_str(); llvm::LLVMContext context; auto module = getModule(rootBitcode, context); if (module) { diff --git a/server/src/building/LinkCommand.cpp b/server/src/building/LinkCommand.cpp index 1fb1894d3..bc2f88a2a 100644 --- a/server/src/building/LinkCommand.cpp +++ b/server/src/building/LinkCommand.cpp @@ -11,12 +11,10 @@ namespace utbot { LinkCommand::LinkCommand(LinkCommand const &other) : BaseCommand(other) { - linker = commandLine.begin(); output = std::next(commandLine.begin(), std::distance(other.commandLine.begin(), other.output)); } - LinkCommand::LinkCommand(LinkCommand &&other) noexcept - : BaseCommand(std::move(other)), linker(other.linker), output(other.output) { + LinkCommand::LinkCommand(LinkCommand &&other) noexcept: BaseCommand(std::move(other)) { } LinkCommand &LinkCommand::operator=(const LinkCommand &other) { @@ -38,33 +36,19 @@ namespace utbot { } LinkCommand::LinkCommand(std::list arguments, fs::path directory, bool shouldChangeDirectory) - : BaseCommand(std::move(arguments), std::move(directory), shouldChangeDirectory) { - linker = commandLine.begin(); - { - auto it = findOutput(); - if (it != commandLine.end()) { - this->output = it; - *this->output = Paths::getCCJsonFileFullPath(*it, this->directory); - } else if (isArchiveCommand()) { - auto it = std::find_if(commandLine.begin(), commandLine.end(), [] (const std::string& argument) { - return Paths::isStaticLibraryFile(argument); - }); - this->output = std::next(addFlagsBeforeIterator({"-o"}, it)); - } else { - auto path = this->directory / "a.out"; - this->output = std::next(addFlagsToBegin({ "-o", path })); - } - } + : BaseCommand(std::move(arguments), std::move(directory), shouldChangeDirectory) { + initOutput(); } LinkCommand::LinkCommand(std::vector commandLine, fs::path directory, bool shouldChangeDirectory) - : LinkCommand(std::list{ commandLine.begin(), commandLine.end() }, - std::move(directory), shouldChangeDirectory) { + : LinkCommand(std::list{commandLine.begin(), commandLine.end()}, + std::move(directory), shouldChangeDirectory) { } - LinkCommand::LinkCommand(std::initializer_list commandLine, fs::path directory, bool shouldChangeDirectory) - : LinkCommand(std::list{ commandLine.begin(), commandLine.end() }, - std::move(directory), shouldChangeDirectory) { + LinkCommand::LinkCommand(std::initializer_list commandLine, fs::path directory, + bool shouldChangeDirectory) + : LinkCommand(std::list{commandLine.begin(), commandLine.end()}, + std::move(directory), shouldChangeDirectory) { } @@ -74,30 +58,30 @@ namespace utbot { std::swap(a.environmentVariables, b.environmentVariables); std::swap(a.optimizationLevel, b.optimizationLevel); - std::swap(a.linker, b.linker); std::swap(a.output, b.output); } - fs::path LinkCommand::getLinker() const { - return *linker; - } - - void LinkCommand::setLinker(fs::path linker) { - *(this->linker) = std::move(linker); - } - - fs::path LinkCommand::getOutput() const { - return *output; - } - - void LinkCommand::setOutput(fs::path output) { - *(this->output) = std::move(output); - } bool LinkCommand::isArchiveCommand() const { - return StringUtils::contains(getLinker().filename().c_str(), "ar"); + return StringUtils::contains(getBuildTool().filename().c_str(), "ar"); } bool LinkCommand::isSharedLibraryCommand() const { return CollectionUtils::contains(commandLine, "-shared"); } + + void LinkCommand::initOutput() { + auto it = findOutput(); + if (it != commandLine.end()) { + this->output = it; + *this->output = Paths::getCCJsonFileFullPath(*it, this->directory); + } else if (isArchiveCommand()) { + it = std::find_if(commandLine.begin(), commandLine.end(), [](const std::string &argument) { + return Paths::isStaticLibraryFile(argument); + }); + this->output = std::next(addFlagsBeforeIterator({"-o"}, it)); + } else { + auto path = this->directory / "a.out"; + this->output = std::next(addFlagsToBegin({"-o", path})); + } + } } diff --git a/server/src/building/LinkCommand.h b/server/src/building/LinkCommand.h index 7b444022a..8d835bd5f 100644 --- a/server/src/building/LinkCommand.h +++ b/server/src/building/LinkCommand.h @@ -10,8 +10,7 @@ namespace utbot { class LinkCommand : public BaseCommand { private: - iterator linker; - iterator output; + void initOutput(); public: LinkCommand() = default; @@ -28,18 +27,11 @@ namespace utbot { LinkCommand(std::vector commandLine, fs::path directory, bool shouldChangeDirectory = false); - LinkCommand(std::initializer_list commandLine, fs::path directory, bool shouldChangeDirectory = false); + LinkCommand(std::initializer_list commandLine, fs::path directory, + bool shouldChangeDirectory = false); friend void swap(LinkCommand &a, LinkCommand &b) noexcept; - [[nodiscard]] fs::path getLinker() const; - - void setLinker(fs::path linker); - - [[nodiscard]] fs::path getOutput() const override; - - void setOutput(fs::path output); - [[nodiscard]] bool isArchiveCommand() const override; [[nodiscard]] bool isSharedLibraryCommand() const; diff --git a/server/src/building/Linker.cpp b/server/src/building/Linker.cpp index 15041d391..56d42307b 100644 --- a/server/src/building/Linker.cpp +++ b/server/src/building/Linker.cpp @@ -56,15 +56,15 @@ Result Linker::linkForTarget(const fs::path &target, const f const fs::path &objectFile) { testGen.setTargetPath(target); - auto siblings = testGen.buildDatabase->getArchiveObjectFiles(target); + auto siblings = testGen.getTargetBuildDatabase()->getArchiveObjectFiles(target); auto stubSources = stubGen.getStubSources(target); CollectionUtils::MapFileTo filesToLink; for (const auto &sibling : siblings) { auto siblingCompilationUnitInfo = - testGen.buildDatabase->getClientCompilationUnitInfo(sibling); + testGen.getClientCompilationUnitInfo(sibling); fs::path siblingObjectFile = siblingCompilationUnitInfo->getOutputFile(); - fs::path bitcodeFile = testGen.buildDatabase->getBitcodeForSource( + fs::path bitcodeFile = testGen.getTargetBuildDatabase()->getBitcodeForSource( siblingCompilationUnitInfo->getSourcePath()); if (CollectionUtils::contains(stubSources, siblingCompilationUnitInfo->getSourcePath())) { @@ -75,7 +75,7 @@ Result Linker::linkForTarget(const fs::path &target, const f } kleeGenerator->buildByCDb(filesToLink, stubSources); - auto linkUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(sourceFilePath); + auto linkUnitInfo = testGen.getTargetBuildDatabase()->getClientLinkUnitInfo(sourceFilePath); std::optional moduleOutput = linkUnitInfo->getOutput(); std::string suffixForParentOfStubs = StringUtils::stringFormat("___%s", Paths::mangle(moduleOutput.value().filename())); @@ -84,27 +84,19 @@ Result Linker::linkForTarget(const fs::path &target, const f return stubsSetResult; } -std::vector Linker::getTargetList(const fs::path &sourceFile, const fs::path &objectFile) const { - if (testGen.hasAutoTarget()) { - return testGen.buildDatabase->autoTargetListForFile(sourceFile, objectFile); - } else { - return {testGen.getTargetPath()}; - } -} - void Linker::linkForOneFile(const fs::path &sourceFilePath) { ExecUtils::throwIfCancelled(); - auto compilationUnitInfo = testGen.buildDatabase->getClientCompilationUnitInfo(sourceFilePath); + auto compilationUnitInfo = testGen.getClientCompilationUnitInfo(sourceFilePath); fs::path objectFile = compilationUnitInfo->getOutputFile(); if (CollectionUtils::contains(testedFiles, sourceFilePath)) { return; } - if (!testGen.buildDatabase->isFirstObjectFileForSource(objectFile)) { + if (!testGen.getTargetBuildDatabase()->isFirstObjectFileForSource(objectFile)) { return; } - std::vector targets = getTargetList(sourceFilePath, objectFile); + std::vector targets = testGen.getTargetBuildDatabase()->getTargetPathsForObjectFile(objectFile); LOG_S(DEBUG) << "Linking bitcode for file " << sourceFilePath.filename(); for (size_t i = 0; i < targets.size(); i++) { const auto& target = targets[i]; @@ -113,15 +105,14 @@ void Linker::linkForOneFile(const fs::path &sourceFilePath) { if (result.isSuccess()) { auto [targetBitcode, stubsSet, _] = result.getOpt().value(); addToGenerated({ objectFile }, targetBitcode); - auto&& targetUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(target); - testGen.buildDatabase->assignStubFilesToLinkUnit(targetUnitInfo, stubsSet); + auto&& targetUnitInfo = testGen.getTargetBuildDatabase()->getClientLinkUnitInfo(target); return; } else { LOG_S(DEBUG) << "Linkage for target " << target.filename() << " failed: " << result.getError()->c_str(); if (i + 1 == targets.size()) { addToGenerated({ objectFile }, {}); fs::path possibleBitcodeFileName = - testGen.buildDatabase->getBitcodeFile(testGen.getTargetPath()); + testGen.getTargetBuildDatabase()->getBitcodeFile(testGen.getTargetBuildDatabase()->getTargetPath()); brokenLinkFiles.insert(possibleBitcodeFileName); } } @@ -129,18 +120,20 @@ void Linker::linkForOneFile(const fs::path &sourceFilePath) { } Result Linker::linkWholeTarget(const fs::path &target) { - auto requestTarget = testGen.getTargetPath(); + auto requestTarget = testGen.getTargetBuildDatabase()->getTargetPath(); + LOG_IF_S(WARNING, !testGen.getTargetBuildDatabase()->hasAutoTarget() && requestTarget != target) + << "Try link target that not specified by user"; testGen.setTargetPath(target); - auto targetUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(target); - auto siblings = testGen.buildDatabase->getArchiveObjectFiles(target); + auto targetUnitInfo = testGen.getTargetBuildDatabase()->getClientLinkUnitInfo(target); + auto siblings = testGen.getTargetBuildDatabase()->getArchiveObjectFiles(target); auto stubSources = stubGen.getStubSources(target); CollectionUtils::MapFileTo filesToLink; CollectionUtils::FileSet siblingObjectsToBuild; for (const fs::path &objectFile : siblings) { - auto objectInfo = testGen.buildDatabase->getClientCompilationUnitInfo(objectFile); + auto objectInfo = testGen.getClientCompilationUnitInfo(objectFile); bool insideFolder = true; if (auto folderTestGen = dynamic_cast(&testGen)) { fs::path folderGen = folderTestGen->folderPath; @@ -148,14 +141,12 @@ Result Linker::linkWholeTarget(const fs::path &target) { insideFolder = false; } } - if (testGen.buildDatabase->isFirstObjectFileForSource(objectFile) && - !CollectionUtils::contains(testedFiles, objectInfo->getSourcePath()) && - insideFolder) { - filesToLink.emplace(objectFile, objectInfo->kleeFilesInfo->getKleeBitcodeFile()); + if (!CollectionUtils::contains(testedFiles, objectInfo->getSourcePath()) && insideFolder) { + fs::path bitcodeFile = objectInfo->kleeFilesInfo->getKleeBitcodeFile(); + filesToLink.emplace(objectFile, bitcodeFile); } else { + fs::path bitcodeFile = testGen.getTargetBuildDatabase()->getBitcodeForSource(objectInfo->getSourcePath()); siblingObjectsToBuild.insert(objectInfo->getOutputFile()); - fs::path bitcodeFile = - testGen.buildDatabase->getBitcodeForSource(objectInfo->getSourcePath()); filesToLink.emplace(objectFile, bitcodeFile); } } @@ -173,17 +164,18 @@ void Linker::linkForProject() { testGen.tests, testGen.progressWriter, "Compiling and linking source files", [&](auto const &it) { fs::path const &sourceFile = it.first; - auto compilationUnitInfo = testGen.buildDatabase->getClientCompilationUnitInfo(sourceFile); + auto compilationUnitInfo = testGen.getClientCompilationUnitInfo(sourceFile); fs::path objectFile = compilationUnitInfo->getOutputFile(); if (!CollectionUtils::contains(testedFiles, sourceFile)) { - auto objectInfo = testGen.buildDatabase->getClientCompilationUnitInfo(sourceFile); + auto objectInfo = testGen.getClientCompilationUnitInfo(sourceFile); if (objectInfo->linkUnit.empty()) { LOG_S(WARNING) << "No executable or library found for current source file in " "link_commands.json: " << sourceFile; return; } - std::vector targets = getTargetList(sourceFile, objectFile); + std::vector targets = testGen.getTargetBuildDatabase()->getTargetPathsForObjectFile( + objectFile); bool success = false; for (const auto &target : targets) { if (!CollectionUtils::contains(triedTargets, target)) { @@ -195,13 +187,11 @@ void Linker::linkForProject() { auto linkres = result.getOpt().value(); auto objectFiles = CollectionUtils::transformTo( linkres.presentedFiles, [&](const fs::path &sourceFile) { - auto compilationUnitInfo = testGen.buildDatabase->getClientCompilationUnitInfo( + auto compilationUnitInfo = testGen.getClientCompilationUnitInfo( sourceFile); return compilationUnitInfo->getOutputFile(); }); addToGenerated(objectFiles, linkres.bitcodeOutput); - auto &&targetUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(target); - testGen.buildDatabase->assignStubFilesToLinkUnit(targetUnitInfo, linkres.stubsSet); break; } else { std::stringstream ss; @@ -219,9 +209,9 @@ void Linker::linkForProject() { void Linker::addToGenerated(const CollectionUtils::FileSet &objectFiles, const fs::path &output) { for (const auto &objectFile : objectFiles) { - auto objectInfo = testGen.buildDatabase->getClientCompilationUnitInfo(objectFile); + auto objectInfo = testGen.getClientCompilationUnitInfo(objectFile); const fs::path &sourcePath = objectInfo->getSourcePath(); - if (testGen.buildDatabase->isFirstObjectFileForSource(objectFile) && + if (testGen.getTargetBuildDatabase()->isFirstObjectFileForSource(objectFile) && !CollectionUtils::contains(testedFiles, sourcePath)) { testedFiles.insert(sourcePath); bitcodeFileName[sourcePath] = output; @@ -266,7 +256,7 @@ std::vector Linker::getTestMethods() { isAnyOneLinked = true; for (const auto &[methodName, _] : tests.methods) { auto compilationUnitInfo = - testGen.buildDatabase->getClientCompilationUnitInfo(fileName); + testGen.getClientCompilationUnitInfo(fileName); if (compilationUnitInfo->kleeFilesInfo->isCorrectMethod(methodName)) { testMethods.emplace_back(methodName, bitcodePath, @@ -293,7 +283,7 @@ std::vector Linker::getTestMethods() { method.classObj.has_value() && method.classObj->type.typeName() == lineInfo->scopeName)) { auto compilationUnitInfo = - testGen.buildDatabase->getClientCompilationUnitInfo(fileName); + testGen.getClientCompilationUnitInfo(fileName); if (compilationUnitInfo->kleeFilesInfo->isCorrectMethod(methodName)) { tests::TestMethod testMethod{ methodName, bitcodeFileName.at(lineInfo->filePath), @@ -355,7 +345,7 @@ Result Linker::link(const CollectionUtils::MapFileTo Linker::link(const CollectionUtils::MapFileTogetClientCompilationUnitInfo(objectFile); + auto compilationUnitInfo = testGen.getClientCompilationUnitInfo(objectFile); auto sourcePath = compilationUnitInfo->getSourcePath(); if (CollectionUtils::containsKey(testGen.tests, sourcePath)) { testMakefilesPrinter.GetMakefiles(sourcePath).write(); @@ -420,39 +410,19 @@ static const std::string STUB_BITCODE_FILES_NAME = "STUB_BITCODE_FILES"; static const std::string STUB_BITCODE_FILES = "$(STUB_BITCODE_FILES)"; Result Linker::generateStubsMakefile( - const fs::path &root, const fs::path &outputFile, const fs::path &stubsMakefile) const { - ShellExecTask::ExecutionParameters nmCommand( - Paths::getLLVMnm(), - { "--print-file-name", "--undefined-only", "--just-symbol-name", outputFile }); - auto [out, status, _] = ShellExecTask::runShellCommandTask(nmCommand, testGen.serverBuildDir); - if (status != 0) { - std::string errorMessage = - StringUtils::stringFormat("llvm-nm on %s failed: %s", outputFile, out); - LOG_S(ERROR) << errorMessage; - return errorMessage; + const fs::path &root, const fs::path &outputFile, const fs::path &stubsMakefile) const { + auto result = StubGen(testGen).getStubSetForObject(outputFile); + if (!result.isSuccess()) { + return result; } - auto symbols = - CollectionUtils::transform(StringUtils::split(out, '\n'), [](std::string const &line) { - return StringUtils::splitByWhitespaces(line).back(); - }); - CollectionUtils::erase_if(symbols, [](std::string const &symbol) { - return StringUtils::startsWith(symbol, "__ubsan") || - StringUtils::startsWith(symbol, "klee_"); - }); - auto signatures = CollectionUtils::transform(symbols, [](std::string const &symbol) { - Tests::MethodDescription methodDescription; - methodDescription.name = symbol; - return methodDescription; - }); - auto rootLinkUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(root); - auto stubsSet = StubGen(testGen).findStubFilesBySignatures(signatures); + auto stubsSet = result.getOpt().value(); printer::DefaultMakefilePrinter makefilePrinter; auto bitcodeStubFiles = CollectionUtils::transformTo>( Synchronizer::dropHeaders(stubsSet), [this, &makefilePrinter](const fs::path &stubPath) { fs::path sourcePath = Paths::stubPathToSourcePath(testGen.projectContext, stubPath); - fs::path bitcodeFile = kleeGenerator->getBuildDatabase()->getBitcodeFile(sourcePath); + fs::path bitcodeFile = kleeGenerator->getBitcodeFile(sourcePath); bitcodeFile = Paths::getStubBitcodeFilePath(bitcodeFile); - auto command = kleeGenerator->getCompileCommandForKlee(sourcePath, {}, {}); + auto command = kleeGenerator->getCompileCommandForKlee(sourcePath, {}, {}, true); command->setSourcePath(stubPath); command->setOutput(bitcodeFile); auto commandWithChangingDirectory = utbot::CompileCommand(command.value(), true); @@ -478,8 +448,9 @@ Result Linker::linkWithStubsIfNeeded(const fs::path &linkMakefile, return errorMessage; } - auto command = MakefileUtils::MakefileCommand(testGen.projectContext, linkMakefile, "all"); - auto [out, status, _] = command.run(testGen.serverBuildDir); + auto command = MakefileUtils::MakefileCommand(testGen.projectContext, linkMakefile, + printer::DefaultMakefilePrinter::TARGET_ALL); + auto[out, status, _] = command.run(testGen.serverBuildDir); if (status != 0) { std::string errorMessage = StringUtils::stringFormat("link with stubs failed: %s", command.getFailedCommand()); @@ -512,7 +483,7 @@ std::string getArchiveArgument(std::string const &argument, if (StringUtils::startsWith(argument, "-")) { return ""; } - hasArchiveOption |= !argument.empty() && argument != linkCommand.getLinker(); + hasArchiveOption |= !argument.empty() && argument != linkCommand.getBuildTool(); return argument; } @@ -673,7 +644,7 @@ Linker::getLinkActionsForExecutable(fs::path const &workingDir, BuildDatabase::TargetInfo const &linkUnitInfo, fs::path const &output, bool shouldChangeDirectory) { - + using namespace DynamicLibraryUtils; auto commands = CollectionUtils::transform( @@ -726,7 +697,7 @@ Linker::declareRootLibraryTarget(printer::DefaultMakefilePrinter &bitcodeLinkMak linkActions.insert(linkActions.begin(), removeRootAction.toStringWithChangingDirectory()); bitcodeLinkMakefilePrinter.declareTarget(rootOutput, { output, STUB_BITCODE_FILES }, linkActions); - bitcodeLinkMakefilePrinter.declareTarget("all", { rootOutput }, {}); + bitcodeLinkMakefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_ALL, { rootOutput }, {}); return rootOutput; } @@ -741,7 +712,7 @@ Linker::addLinkTargetRecursively(const fs::path &fileToBuild, const std::optional &testedFilePath, bool shouldChangeDirectory) { if (Paths::isObjectFile(fileToBuild)) { - auto compilationUnitInfo = testGen.buildDatabase->getClientCompilationUnitInfo(fileToBuild); + auto compilationUnitInfo = testGen.getClientCompilationUnitInfo(fileToBuild); fs::path sourcePath = compilationUnitInfo->getSourcePath(); BuildResult::Type type = CollectionUtils::contains(stubSources, sourcePath) ? BuildResult::Type::ALL_STUBS @@ -754,7 +725,7 @@ Linker::addLinkTargetRecursively(const fs::path &fileToBuild, } return { bitcode, type }; } else { - auto linkUnit = testGen.buildDatabase->getClientLinkUnitInfo(fileToBuild); + auto linkUnit = testGen.getTargetBuildDatabase()->getClientLinkUnitInfo(fileToBuild); CollectionUtils::MapFileTo dependencies; // object file -> bitcode BuildResult::Type unitType = BuildResult::Type::NONE; for (auto const &subfile : linkUnit->files) { @@ -770,7 +741,7 @@ Linker::addLinkTargetRecursively(const fs::path &fileToBuild, } auto bitcodeDependencies = CollectionUtils::getValues(dependencies); fs::path prefixPath = getPrefixPath(bitcodeDependencies, testGen.serverBuildDir); - auto output = testGen.buildDatabase->getBitcodeFile(fileToBuild); + auto output = testGen.getTargetBuildDatabase()->getBitcodeFile(fileToBuild); output = LinkerUtils::applySuffix(output, unitType, suffixForParentOfStubs); if (Paths::isLibraryFile(fileToBuild)) { auto archiveActions = getArchiveCommands(prefixPath, dependencies, *linkUnit, output, shouldChangeDirectory); @@ -796,7 +767,7 @@ Linker::addLinkTargetRecursively(const fs::path &fileToBuild, auto actions = CollectionUtils::transform( linkActions, std::bind(&utbot::LinkCommand::toStringWithChangingDirectory, std::placeholders::_1)); bitcodeLinkMakefilePrinter.declareTarget(output, bitcodeDependencies, actions); - bitcodeLinkMakefilePrinter.declareTarget("all", { output }, {}); + bitcodeLinkMakefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_ALL, { output }, {}); } return { output, unitType }; } diff --git a/server/src/building/Linker.h b/server/src/building/Linker.h index 907927ed5..66aa01d13 100644 --- a/server/src/building/Linker.h +++ b/server/src/building/Linker.h @@ -12,13 +12,13 @@ #include "utils/CollectionUtils.h" #include "utils/MakefileUtils.h" #include "utils/Void.h" +#include "stubs/StubGen.h" #include #include #include #include #include -#include class Linker { public: @@ -62,8 +62,6 @@ class Linker { bool isForOneFile(); - std::vector getTargetList(const fs::path &sourceFile, const fs::path &objectFile) const; - Result linkForTarget(const fs::path &target, const fs::path &sourceFilePath, const std::shared_ptr &compilationUnitInfo, const fs::path &objectFile); diff --git a/server/src/building/ProjectBuildDatabase.h b/server/src/building/ProjectBuildDatabase.h new file mode 100644 index 000000000..ddf8c339e --- /dev/null +++ b/server/src/building/ProjectBuildDatabase.h @@ -0,0 +1,26 @@ +#ifndef UTBOTCPP_PROJECTBUILDDATABASE_H +#define UTBOTCPP_PROJECTBUILDDATABASE_H + +#include "BuildDatabase.h" + +class ProjectBuildDatabase : public BuildDatabase { +private: + void initObjects(const nlohmann::json &compileCommandsJson); + + void initInfo(const nlohmann::json &linkCommandsJson); + + void filterInstalledFiles(); + + void addLocalSharedLibraries(); + + void fillTargetInfoParents(); + +public: + ProjectBuildDatabase(fs::path buildCommandsJsonPath, fs::path serverBuildDir, + utbot::ProjectContext projectContext); + + ProjectBuildDatabase(utbot::ProjectContext projectContext); +}; + + +#endif //UTBOTCPP_PROJECTBUILDDATABASE_H diff --git a/server/src/building/ProjectBuildDatabse.cpp b/server/src/building/ProjectBuildDatabse.cpp new file mode 100644 index 000000000..299ada427 --- /dev/null +++ b/server/src/building/ProjectBuildDatabse.cpp @@ -0,0 +1,231 @@ +#include "ProjectBuildDatabase.h" +#include "utils/GrpcUtils.h" +#include "exceptions/CompilationDatabaseException.h" +#include "utils/JsonUtils.h" +#include "loguru.h" +#include "utils/StringUtils.h" + + +static std::string tryConvertOptionToPath(const std::string &possibleFilePath, + const fs::path &dirPath) { + if (StringUtils::startsWith(possibleFilePath, "-")) { + return possibleFilePath; + } + fs::path fullFilePath; + try { + fullFilePath = Paths::getCCJsonFileFullPath(possibleFilePath, dirPath); + } catch (...) { + return possibleFilePath; + } + return fs::exists(fullFilePath) ? fullFilePath.string() : possibleFilePath; +} + +ProjectBuildDatabase::ProjectBuildDatabase(fs::path _buildCommandsJsonPath, + fs::path _serverBuildDir, + utbot::ProjectContext _projectContext) : + BuildDatabase(_serverBuildDir, + _buildCommandsJsonPath, + fs::canonical(_buildCommandsJsonPath / "link_commands.json"), + fs::canonical(_buildCommandsJsonPath / "compile_commands.json"), + std::move(_projectContext)) { + if (!fs::exists(linkCommandsJsonPath) || !fs::exists(compileCommandsJsonPath)) { + throw CompilationDatabaseException("Couldn't open link_commands.json or compile_commands.json files"); + } + + auto linkCommandsJson = JsonUtils::getJsonFromFile(linkCommandsJsonPath); + auto compileCommandsJson = JsonUtils::getJsonFromFile(compileCommandsJsonPath); + + initObjects(compileCommandsJson); + initInfo(linkCommandsJson); + filterInstalledFiles(); + addLocalSharedLibraries(); + fillTargetInfoParents(); + createClangCompileCommandsJson(); +} + +ProjectBuildDatabase::ProjectBuildDatabase(utbot::ProjectContext projectContext) : ProjectBuildDatabase( + CompilationUtils::substituteRemotePathToCompileCommandsJsonPath(projectContext.projectPath, + projectContext.buildDirRelativePath), + Paths::getUtbotBuildDir(projectContext), std::move(projectContext)) { +} + + +void ProjectBuildDatabase::initObjects(const nlohmann::json &compileCommandsJson) { + for (const nlohmann::json &compileCommand: compileCommandsJson) { + auto objectInfo = std::make_shared(); + + fs::path directory = compileCommand.at("directory").get(); + fs::path jsonFile = compileCommand.at("file").get(); + fs::path sourceFile = Paths::getCCJsonFileFullPath(jsonFile, directory); + + std::vector jsonArguments; + if (compileCommand.contains("command")) { + std::string command = compileCommand.at("command"); + jsonArguments = StringUtils::splitByWhitespaces(command); + } else { + jsonArguments = std::vector(compileCommand.at("arguments")); + } + std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(), + [&directory](const std::string &argument) { + return tryConvertOptionToPath(argument, directory); + }); + objectInfo->command = utbot::CompileCommand(jsonArguments, directory, sourceFile); + objectInfo->command.removeWerror(); + fs::path outputFile = objectInfo->getOutputFile(); + fs::path kleeFilePathTemplate = + Paths::createNewDirForFile(sourceFile, projectContext.buildDir(), serverBuildDir); + fs::path kleeFile = Paths::addSuffix(kleeFilePathTemplate, "_klee"); + objectInfo->kleeFilesInfo = std::make_shared(kleeFile); + + if (CollectionUtils::containsKey(objectFileInfos, outputFile) || + CollectionUtils::containsKey(targetInfos, outputFile)) { + /* + * If the condition above is true, that means that the output file + * is built from multiple sources. Hence, it is not an object file, + * but an executable, and it should be treated as a target. + * This is a hack. This inconsistency is produced by Bear + * when it treats a Makefile command like + * gcc -o output a.c b.c c.c + * This code is creating artificial compile and link commands, similar + * to commands Bear generates from CMake command like + * add_executable(output a.c b.c c.c) + */ + auto targetInfo = targetInfos[outputFile]; + if (targetInfo == nullptr) { + LOG_S(DEBUG) << outputFile << " is treated as a target instead of an object file"; + auto targetObjectInfo = objectFileInfos[outputFile]; + auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(targetObjectInfo); + objectFileInfos.erase(outputFile); + + //create targetInfo + targetInfo = targetInfos[outputFile] = std::make_shared(); + targetInfo->commands.emplace_back( + std::initializer_list{targetObjectInfo->command.getBuildTool(), + "-o", outputFile, tmpObjectFileName}, + directory); + targetInfo->addFile(tmpObjectFileName); + } + //redirect new compilation command to temporary file + auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(objectInfo); + + //add new dependency to an implicit target + targetInfo->commands[0].addFlagToEnd(tmpObjectFileName); + targetInfo->addFile(tmpObjectFileName); + } else { + objectFileInfos[outputFile] = objectInfo; + } + const fs::path &sourcePath = objectInfo->getSourcePath(); + sourceFileInfos[sourcePath].emplace_back(objectInfo); + } + for (auto &[sourceFile, objectInfos]: sourceFileInfos) { + std::sort(objectInfos.begin(), objectInfos.end(), BuildDatabase::ObjectFileInfo::conflictPriorityMore); + } +} + +void ProjectBuildDatabase::initInfo(const nlohmann::json &linkCommandsJson) { + for (nlohmann::json const &linkCommand: linkCommandsJson) { + fs::path directory = linkCommand.at("directory").get(); + std::vector jsonArguments; + if (linkCommand.contains("command")) { + std::string command = linkCommand.at("command"); + jsonArguments = StringUtils::splitByWhitespaces(command); + } else { + jsonArguments = std::vector(linkCommand.at("arguments")); + } + if (StringUtils::endsWith(jsonArguments[0], "ranlib") || + StringUtils::endsWith(jsonArguments[0], "cmake")) { + continue; + } + std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(), + [&directory](const std::string &argument) { + return tryConvertOptionToPath(argument, directory); + }); + + mergeLibraryOptions(jsonArguments); + + utbot::LinkCommand command(jsonArguments, directory); + fs::path const &output = command.getOutput(); + auto targetInfo = targetInfos[output]; + if (targetInfo == nullptr) { + targetInfo = targetInfos[output] = std::make_shared(); + } else { + LOG_S(WARNING) << "Multiple commands for one file: " << output.string(); + } + for (nlohmann::json const &jsonFile: linkCommand.at("files")) { + auto filename = jsonFile.get(); + fs::path currentFile = Paths::getCCJsonFileFullPath(filename, command.getDirectory()); + targetInfo->addFile(currentFile); + if (Paths::isObjectFile(currentFile)) { + if (!CollectionUtils::containsKey(objectFileInfos, currentFile)) { + throw CompilationDatabaseException( + "compile_commands.json doesn't contain a command for object file " + + currentFile.string()); + } + objectFileInfos[currentFile]->linkUnit = output; + } + } + targetInfo->commands.emplace_back(command); + } +} + + +void ProjectBuildDatabase::filterInstalledFiles() { + for (auto &it: targetInfos) { + auto &linkFile = it.first; + auto &targetInfo = it.second; + CollectionUtils::OrderedFileSet fileset; + targetInfo->installedFiles = + CollectionUtils::filterOut(targetInfo->files, [this](fs::path const &file) { + return CollectionUtils::containsKey(targetInfos, file) || + CollectionUtils::containsKey(objectFileInfos, file); + }); + if (!targetInfo->installedFiles.empty()) { + LOG_S(DEBUG) << "Target " << linkFile << " depends on " << targetInfo->installedFiles.size() + << " installed files"; + } + CollectionUtils::erase_if(targetInfo->files, [&targetInfo](fs::path const &file) { + return CollectionUtils::contains(targetInfo->installedFiles, file); + }); + } +} + +void ProjectBuildDatabase::addLocalSharedLibraries() { + sharedLibrariesMap sharedLibraryFiles; + for (const auto &[linkFile, linkUnit]: targetInfos) { + if (Paths::isSharedLibraryFile(linkFile)) { + auto withoutVersion = CompilationUtils::removeSharedLibraryVersion(linkFile); + sharedLibraryFiles[withoutVersion.filename()][linkFile.parent_path()] = linkFile; + } + } + for (auto &[linkFile, targetInfo]: targetInfos) { + for (auto &command: targetInfo->commands) { + addLibrariesForCommand(command, *targetInfo, sharedLibraryFiles); + } + } + for (auto &[objectFile, objectInfo]: objectFileInfos) { + addLibrariesForCommand(objectInfo->command, *objectInfo, sharedLibraryFiles, true); + } +} + +void ProjectBuildDatabase::fillTargetInfoParents() { + CollectionUtils::MapFileTo> parentTargets; + for (const auto &[linkFile, linkUnit]: targetInfos) { + for (const fs::path &dependencyFile: linkUnit->files) { + if (Paths::isLibraryFile(dependencyFile)) { + parentTargets[dependencyFile].emplace_back(linkFile); + } + if (Paths::isObjectFile(dependencyFile)) { + objectFileTargets[dependencyFile].emplace_back(linkFile); + } + } + } + for (auto &[library, parents]: parentTargets) { + if (!CollectionUtils::containsKey(targetInfos, library)) { + throw CompilationDatabaseException( + "link_commands.json doesn't contain a command for building library: " + + library.string() + "\nReferenced from command for: " + + (parents.empty() ? "none" : parents[0].string())); + } + targetInfos[library]->parentLinkUnits = std::move(parents); + } +} diff --git a/server/src/building/RunCommand.cpp b/server/src/building/RunCommand.cpp index 6f7920f89..421f59bdd 100644 --- a/server/src/building/RunCommand.cpp +++ b/server/src/building/RunCommand.cpp @@ -6,22 +6,22 @@ namespace utbot { RunCommand::RunCommand(std::vector commandLine, fs::path directory, bool shouldChangeDirectory) - : BaseCommand(std::move(commandLine), std::move(directory), shouldChangeDirectory) { - } - fs::path RunCommand::getOutput() const { - throw UnImplementedException("RunTestsCommand doesn't have output by default"); + : BaseCommand(std::move(commandLine), std::move(directory), shouldChangeDirectory) { } + std::string RunCommand::toStringWithChangingDirectoryToNew(const fs::path &targetDirectory) const { std::string baseCommand = toString(); return StringUtils::stringFormat(R"(cd "%s" && %s)", targetDirectory, baseCommand); } - RunCommand RunCommand::forceRemoveFile(const fs::path &path, fs::path const &workingDir, bool shouldChangeDirectory) { - return { { "rm", "-f", path }, workingDir, shouldChangeDirectory }; + + RunCommand + RunCommand::forceRemoveFile(const fs::path &path, fs::path const &workingDir, bool shouldChangeDirectory) { + return {{"rm", "-f", path}, workingDir, shouldChangeDirectory}; } RunCommand RunCommand::copyFile(const fs::path &from, const fs::path &to, fs::path const &workingDir) { - return { { "cp", from, to }, workingDir }; + return {{"cp", from, to}, workingDir}; } bool RunCommand::isArchiveCommand() const { diff --git a/server/src/building/RunCommand.h b/server/src/building/RunCommand.h index e76d63122..c651ac12d 100644 --- a/server/src/building/RunCommand.h +++ b/server/src/building/RunCommand.h @@ -10,14 +10,13 @@ namespace utbot { class RunCommand : public BaseCommand { public: RunCommand(std::vector commandLine, fs::path directory, bool shouldChangeDirectory = false); - fs::path getOutput() const override; std::string toStringWithChangingDirectoryToNew(const fs::path &targetDirectory) const override; - static RunCommand forceRemoveFile(fs::path const &path, fs::path const &workingDir, bool shouldChangeDirectory = false); - static RunCommand - copyFile(fs::path const &from, const fs::path &to, fs::path const &workingDir); + forceRemoveFile(fs::path const &path, fs::path const &workingDir, bool shouldChangeDirectory = false); + + static RunCommand copyFile(fs::path const &from, const fs::path &to, fs::path const &workingDir); bool isArchiveCommand() const override; }; diff --git a/server/src/building/TargetBuildDatabase.cpp b/server/src/building/TargetBuildDatabase.cpp new file mode 100644 index 000000000..fc9a3b74f --- /dev/null +++ b/server/src/building/TargetBuildDatabase.cpp @@ -0,0 +1,75 @@ +#include "TargetBuildDatabase.h" + +#include "loguru.h" +#include "utils/GrpcUtils.h" +#include "utils/GenerationUtils.h" + +TargetBuildDatabase::TargetBuildDatabase(BuildDatabase *baseBuildDatabase, const std::string &targetOrSourcePath) : + BuildDatabase(baseBuildDatabase) { + if (Paths::isSourceFile(targetOrSourcePath)) { + target = baseBuildDatabase->getRootForSource(targetOrSourcePath); + } else if (targetOrSourcePath == GrpcUtils::UTBOT_AUTO_TARGET_PATH || targetOrSourcePath.empty()) { + target = baseBuildDatabase->getRootForFirstSource(); + } else { + auto new_target = GenerationUtils::findTarget(baseBuildDatabase->getAllTargets(), targetOrSourcePath); + if (new_target.has_value()) { + target = new_target.value(); + } else { + throw CompilationDatabaseException("Can't find target: " + targetOrSourcePath); + } + } + + isAutoTarget = target == GrpcUtils::UTBOT_AUTO_TARGET_PATH; + + { + auto objectFilesList = baseBuildDatabase->getArchiveObjectFiles(target); + for (const auto &objectFilePath: objectFilesList) { + auto objectFileInfo = baseBuildDatabase->getClientCompilationObjectInfo(objectFilePath); + sourceFileInfos[objectFileInfo->getSourcePath()].push_back(objectFileInfo); + LOG_IF_S(DEBUG, sourceFileInfos[objectFileInfo->getSourcePath()].size() > 1) + << "Multiple compile commands for file \"" << objectFileInfo->getSourcePath() << "\" in target \"" + << target.string() << "\""; + objectFileInfos[objectFileInfo->getOutputFile()] = objectFileInfo; + objectFileTargets[objectFileInfo->getOutputFile()] = baseBuildDatabase->getTargetPathsForObjectFile( + objectFileInfo->getOutputFile()); + } + } + + { + auto targetFilesList = baseBuildDatabase->getArchiveTargetFiles(target); + for (const auto &objectFilePath: targetFilesList) { + targetInfos[objectFilePath] = baseBuildDatabase->getTargetInfo(objectFilePath); + } + } + + createClangCompileCommandsJson(); +} + +std::vector> TargetBuildDatabase::getRootTargets() const { + if (!hasAutoTarget()) { + return {targetInfos.at(target)}; + } + return BuildDatabase::getRootTargets(); +} + +std::vector TargetBuildDatabase::getTargetPathsForSourceFile(const fs::path &sourceFilePath) const { + if (!hasAutoTarget()) { + return {target}; + } + return BuildDatabase::getTargetPathsForSourceFile(sourceFilePath); +} + +std::vector TargetBuildDatabase::getTargetPathsForObjectFile(const fs::path &objectFile) const { + if (!hasAutoTarget()) { + return {target}; + } + return BuildDatabase::getTargetPathsForObjectFile(objectFile); +} + +bool TargetBuildDatabase::hasAutoTarget() const { + return isAutoTarget; +} + +fs::path TargetBuildDatabase::getTargetPath() const { + return target; +} diff --git a/server/src/building/TargetBuildDatabase.h b/server/src/building/TargetBuildDatabase.h new file mode 100644 index 000000000..18d87de25 --- /dev/null +++ b/server/src/building/TargetBuildDatabase.h @@ -0,0 +1,26 @@ +#ifndef UTBOTCPP_TARGETBUILDDATABASE_H +#define UTBOTCPP_TARGETBUILDDATABASE_H + +#include "BuildDatabase.h" + + +class TargetBuildDatabase : public BuildDatabase { +private: + fs::path target; + bool isAutoTarget; + +public: + TargetBuildDatabase(BuildDatabase *baseBuildDatabase, const std::string &targetOrSourcePath); + + bool hasAutoTarget() const; + + fs::path getTargetPath() const; + + std::vector> getRootTargets() const override; + + std::vector getTargetPathsForSourceFile(const fs::path &sourceFilePath) const override; + + std::vector getTargetPathsForObjectFile(const fs::path &objectFile) const override; +}; + +#endif //UTBOTCPP_TARGETBUILDDATABASE_H diff --git a/server/src/coverage/GcovCoverageTool.cpp b/server/src/coverage/GcovCoverageTool.cpp index 98793050a..176e29665 100644 --- a/server/src/coverage/GcovCoverageTool.cpp +++ b/server/src/coverage/GcovCoverageTool.cpp @@ -13,6 +13,7 @@ #include "utils/MakefileUtils.h" #include "utils/StringUtils.h" #include "utils/path/FileSystemPath.h" +#include "printers/DefaultMakefilePrinter.h" #include "loguru.h" #include "json.hpp" @@ -39,11 +40,12 @@ GcovCoverageTool::getBuildRunCommands(const std::vector &testsToLaunch projectContext, Paths::testPathToSourcePath(projectContext, testToLaunch.testFilePath)); auto gtestFlags = getGTestFlags(testToLaunch); - auto buildCommand = - MakefileUtils::MakefileCommand(projectContext, makefile, "build", gtestFlags); - auto runCommand = - MakefileUtils::MakefileCommand(projectContext, makefile, "run", gtestFlags); - result.push_back({ testToLaunch, buildCommand, runCommand }); + auto buildCommand = MakefileUtils::MakefileCommand(projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_BUILD, + gtestFlags); + auto runCommand = MakefileUtils::MakefileCommand(projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_RUN, gtestFlags); + result.push_back({testToLaunch, buildCommand, runCommand}); }); return result; } diff --git a/server/src/coverage/LlvmCoverageTool.cpp b/server/src/coverage/LlvmCoverageTool.cpp index bbe3888a3..723b23b23 100644 --- a/server/src/coverage/LlvmCoverageTool.cpp +++ b/server/src/coverage/LlvmCoverageTool.cpp @@ -14,6 +14,7 @@ #include "utils/MakefileUtils.h" #include "utils/StringUtils.h" #include "utils/path/FileSystemPath.h" +#include "printers/DefaultMakefilePrinter.h" #include "loguru.h" @@ -36,13 +37,15 @@ LlvmCoverageTool::getBuildRunCommands(const std::vector &testsToLaunch std::vector profileEnv; if (withCoverage) { auto profrawFilePath = Paths::getProfrawFilePath(projectContext, testName); - profileEnv = { StringUtils::stringFormat("LLVM_PROFILE_FILE=%s", profrawFilePath) }; + profileEnv = {StringUtils::stringFormat("LLVM_PROFILE_FILE=%s", profrawFilePath)}; } - auto buildCommand = MakefileUtils::MakefileCommand(projectContext, makefilePath, "build", + auto buildCommand = MakefileUtils::MakefileCommand(projectContext, makefilePath, + printer::DefaultMakefilePrinter::TARGET_BUILD, gtestFlags, profileEnv); - auto runCommand = MakefileUtils::MakefileCommand(projectContext, makefilePath, "run", + auto runCommand = MakefileUtils::MakefileCommand(projectContext, makefilePath, + printer::DefaultMakefilePrinter::TARGET_RUN, gtestFlags, profileEnv); - return BuildRunCommand{ testToLaunch, buildCommand, runCommand }; + return BuildRunCommand{testToLaunch, buildCommand, runCommand}; }); } diff --git a/server/src/coverage/TestRunner.cpp b/server/src/coverage/TestRunner.cpp index 53156752a..6e3b79806 100644 --- a/server/src/coverage/TestRunner.cpp +++ b/server/src/coverage/TestRunner.cpp @@ -1,4 +1,6 @@ #include "TestRunner.h" + +#include "printers/DefaultMakefilePrinter.h" #include "GTestLogger.h" #include "Paths.h" #include "TimeExecStatistics.h" @@ -39,8 +41,10 @@ TestRunner::TestRunner( std::vector TestRunner::getTestsFromMakefile(const fs::path &makefile, const fs::path &testFilePath) { - auto cmdGetAllTests = MakefileUtils::MakefileCommand(projectContext, makefile, "run", "--gtest_list_tests", {"GTEST_FILTER=*"}); - auto [out, status, _] = cmdGetAllTests.run(projectContext.buildDir(), false); + auto cmdGetAllTests = MakefileUtils::MakefileCommand(projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_RUN, + "--gtest_list_tests", {"GTEST_FILTER=*"}); + auto[out, status, _] = cmdGetAllTests.run(projectContext.buildDir(), false); if (status != 0) { auto [err, _, logFilePath] = cmdGetAllTests.run(projectContext.buildDir(), true); progressWriter->writeProgress(StringUtils::stringFormat("command %s failed.\n" @@ -170,7 +174,8 @@ bool TestRunner::buildTest(const utbot::ProjectContext& projectContext, const fs ExecUtils::throwIfCancelled(); fs::path makefile = Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); if (fs::exists(makefile)) { - auto command = MakefileUtils::MakefileCommand(projectContext, makefile, "build", "", {}); + auto command = MakefileUtils::MakefileCommand(projectContext, makefile, + printer::DefaultMakefilePrinter::TARGET_BUILD, "", {}); LOG_S(DEBUG) << "Try compile tests for: " << sourcePath.string(); auto[out, status, logFilePath] = command.run(projectContext.buildDir(), true); if (status != 0) { @@ -233,4 +238,4 @@ void TestRunner::cleanCoverage() { ExecUtils::throwIfCancelled(); coverageTool->cleanCoverage(); -} \ No newline at end of file +} diff --git a/server/src/fetchers/Fetcher.cpp b/server/src/fetchers/Fetcher.cpp index 06b304479..06f4ac94b 100644 --- a/server/src/fetchers/Fetcher.cpp +++ b/server/src/fetchers/Fetcher.cpp @@ -31,8 +31,7 @@ Fetcher::Fetcher(Options options, : options(options), projectTests(&tests), projectTypes(types), pointerSize(pointerSize), maximumAlignment(maximumAlignment), fetchFunctionBodies(fetchFunctionBodies), clangToolRunner(compilationDatabase) { - buildRootPath = Paths::subtractPath(compileCommandsJsonPath.string(), - CompilationUtils::UTBOT_BUILD_DIR_NAME); + buildRootPath = Paths::subtractPath(compileCommandsJsonPath.string(), CompilationUtils::UTBOT_BUILD_DIR_NAME); if (options.has(Options::Value::TYPE)) { addMatcher(anyTypeDeclarationMatcher); addMatcher(structJustDeclMatcher); diff --git a/server/src/printers/DefaultMakefilePrinter.cpp b/server/src/printers/DefaultMakefilePrinter.cpp index 962d15d3a..2981e5dd7 100644 --- a/server/src/printers/DefaultMakefilePrinter.cpp +++ b/server/src/printers/DefaultMakefilePrinter.cpp @@ -4,6 +4,10 @@ namespace printer { +const std::string DefaultMakefilePrinter::TARGET_ALL = "all"; +const std::string DefaultMakefilePrinter::TARGET_BUILD = "build"; +const std::string DefaultMakefilePrinter::TARGET_RUN = "run"; + DefaultMakefilePrinter::DefaultMakefilePrinter() { writeCopyrightHeader(); } diff --git a/server/src/printers/DefaultMakefilePrinter.h b/server/src/printers/DefaultMakefilePrinter.h index 94c60f73a..b355fae15 100644 --- a/server/src/printers/DefaultMakefilePrinter.h +++ b/server/src/printers/DefaultMakefilePrinter.h @@ -9,6 +9,10 @@ namespace printer { class DefaultMakefilePrinter : public Printer { public: + static const std::string TARGET_ALL; + static const std::string TARGET_BUILD; + static const std::string TARGET_RUN; + DefaultMakefilePrinter(); ~DefaultMakefilePrinter() override = default; diff --git a/server/src/printers/NativeMakefilePrinter.cpp b/server/src/printers/NativeMakefilePrinter.cpp index 1b6769fbe..510102113 100644 --- a/server/src/printers/NativeMakefilePrinter.cpp +++ b/server/src/printers/NativeMakefilePrinter.cpp @@ -116,14 +116,14 @@ namespace printer { } NativeMakefilePrinter::NativeMakefilePrinter( - utbot::ProjectContext projectContext, - std::shared_ptr buildDatabase, + const BaseTestGen *testGen, fs::path const &rootPath, fs::path primaryCompiler, CollectionUtils::FileSet const *stubSources, std::map> pathToShellVariable) : RelativeMakefilePrinter(pathToShellVariable), - projectContext(std::move(projectContext)), buildDatabase(buildDatabase), rootPath(std::move(rootPath)), + testGen(testGen), + rootPath(std::move(rootPath)), primaryCompiler(std::move(primaryCompiler)), primaryCxxCompiler(CompilationUtils::toCppCompiler(this->primaryCompiler)), primaryCompilerName(CompilationUtils::getCompilerName(this->primaryCompiler)), @@ -135,7 +135,7 @@ namespace printer { CompilationUtils::getCoverageLinkFlags(primaryCxxCompilerName), " ")), sanitizerLinkFlags(SanitizerUtils::getSanitizeLinkFlags(primaryCxxCompilerName)), - buildDirectory(Paths::getUtbotBuildDir(projectContext)), + buildDirectory(Paths::getUtbotBuildDir(testGen->projectContext)), dependencyDirectory(buildDirectory / "dependencies"), stubSources(stubSources) { @@ -164,13 +164,13 @@ namespace printer { } fs::path NativeMakefilePrinter::getTemporaryDependencyFile(fs::path const &file) { - fs::path relativePath = fs::relative(file, projectContext.projectPath); + fs::path relativePath = fs::relative(file, testGen->projectContext.projectPath); return getRelativePath(dependencyDirectory) / Paths::addExtension(relativePath, ".Td"); } fs::path NativeMakefilePrinter::getDependencyFile(fs::path const &file) { - fs::path relativePath = fs::relative(file, projectContext.projectPath); + fs::path relativePath = fs::relative(file, testGen->projectContext.projectPath); return getRelativePath(dependencyDirectory) / Paths::addExtension(relativePath, ".d"); } @@ -185,8 +185,8 @@ namespace printer { gtestCompilationArguments.setSourcePath(getRelativePath(gtestAllSourceFile)); gtestCompilationArguments.setOutput(gtestAllObjectFile); gtestCompilationArguments.addFlagsToBegin( - { stringFormat("-I%s", getRelativePath(gtestLib) / "googletest" / "include"), - stringFormat("-I%s", getRelativePath(gtestLib) / "googletest") }); + { CompilationUtils::getIncludePath(getRelativePath(gtestLib) / "googletest" / "include"), + CompilationUtils::getIncludePath(getRelativePath(gtestLib) / "googletest") }); declareTarget(gtestAllObjectFile, { gtestCompilationArguments.getSourcePath() }, { gtestCompilationArguments.toStringWithChangingDirectory() }); @@ -206,8 +206,8 @@ namespace printer { auto gtestCompilationArguments = defaultCompileCommand; gtestCompilationArguments.addFlagsToBegin( - {stringFormat("-I%s", getRelativePath(gtestLib / "googletest" / "include")), - stringFormat("-I%s", getRelativePath(gtestLib / "googletest"))}); + {CompilationUtils::getIncludePath(getRelativePath(gtestLib / "googletest" / "include")), + CompilationUtils::getIncludePath(getRelativePath(gtestLib / "googletest"))}); gtestCompilationArguments.setSourcePath(getRelativePath(gtestMainSourceFile)); gtestCompilationArguments.setOutput(gtestMainObjectFile); declareTarget(gtestMainObjectFile, { gtestCompilationArguments.getSourcePath() }, @@ -226,10 +226,10 @@ namespace printer { const BuildDatabase::ObjectFileInfo &compilationUnitInfo) { auto compileCommand = compilationUnitInfo.command; fs::path compiler = CompilationUtils::getBundledCompilerPath( - CompilationUtils::getCompilerName(compileCommand.getCompiler())); + CompilationUtils::getCompilerName(compileCommand.getBuildTool())); fs::path cxxCompiler = CompilationUtils::toCppCompiler(compiler); auto compilerName = CompilationUtils::getCompilerName(compiler); - compileCommand.setCompiler(getRelativePathForLinker(compiler)); + compileCommand.setBuildTool(getRelativePathForLinker(compiler)); compileCommand.setSourcePath(getRelativePath(sourcePath)); compileCommand.setOutput(getRelativePath(target)); @@ -270,7 +270,7 @@ namespace printer { BuildResult NativeMakefilePrinter::addObjectFile(const fs::path &objectFile, const std::string &suffixForParentOfStubs) { - auto compilationUnitInfo = buildDatabase->getClientCompilationUnitInfo(objectFile); + auto compilationUnitInfo = testGen->getClientCompilationUnitInfo(objectFile); fs::path sourcePath = compilationUnitInfo->getSourcePath(); fs::path pathToCompile; @@ -278,17 +278,17 @@ namespace printer { BuildResult::Type buildResultType; BuildResult buildResult; if (CollectionUtils::contains(*stubSources, sourcePath)) { - pathToCompile = Paths::sourcePathToStubPath(projectContext, sourcePath); - recompiledFile = Paths::getRecompiledFile(projectContext, pathToCompile); + pathToCompile = Paths::sourcePathToStubPath(testGen->projectContext, sourcePath); + recompiledFile = Paths::getRecompiledFile(testGen->projectContext, pathToCompile); buildResultType = BuildResult::Type::ALL_STUBS; } else { if (Paths::isCXXFile(sourcePath)) { pathToCompile = sourcePath; } else { - pathToCompile = Paths::getWrapperFilePath(projectContext, sourcePath); + pathToCompile = Paths::getWrapperFilePath(testGen->projectContext, sourcePath); } recompiledFile = - Paths::getRecompiledFile(projectContext, compilationUnitInfo->getOutputFile()); + Paths::getRecompiledFile(testGen->projectContext, compilationUnitInfo->getOutputFile()); buildResultType = BuildResult::Type::NO_STUBS; } @@ -299,25 +299,25 @@ namespace printer { } void NativeMakefilePrinter::addTestTarget(const fs::path &sourcePath) { - auto compilationUnitInfo = buildDatabase->getClientCompilationUnitInfo(sourcePath); + auto compilationUnitInfo = testGen->getClientCompilationUnitInfo(sourcePath); auto testCompilationCommand = compilationUnitInfo->command; - testCompilationCommand.setCompiler(getRelativePathForLinker(primaryCxxCompiler)); + testCompilationCommand.setBuildTool(getRelativePathForLinker(primaryCxxCompiler)); testCompilationCommand.setOptimizationLevel(OPTIMIZATION_FLAG); testCompilationCommand.removeCompilerFlagsAndOptions( UNSUPPORTED_FLAGS_AND_OPTIONS_TEST_MAKE); testCompilationCommand.removeIncludeFlags(); const fs::path gtestLib = Paths::getGtestLibPath(); - testCompilationCommand.addFlagToBegin(stringFormat("-I%s", getRelativePath(gtestLib / "googletest" / "include"))); + testCompilationCommand.addFlagToBegin(CompilationUtils::getIncludePath(getRelativePath(gtestLib / "googletest" / "include"))); if (Paths::isCXXFile(sourcePath)) { - testCompilationCommand.addFlagToBegin(stringFormat("-I%s", getRelativePath(Paths::getAccessPrivateLibPath()))); + testCompilationCommand.addFlagToBegin(CompilationUtils::getIncludePath(getRelativePath(Paths::getAccessPrivateLibPath()))); } testCompilationCommand.addFlagToBegin(FPIC_FLAG); testCompilationCommand.addFlagsToBegin(SANITIZER_NEEDED_FLAGS); - fs::path testSourcePath = Paths::sourcePathToTestPath(projectContext, sourcePath); + fs::path testSourcePath = Paths::sourcePathToTestPath(testGen->projectContext, sourcePath); fs::path compilationDirectory = compilationUnitInfo->getDirectory(); - fs::path testObjectDir = Paths::getTestObjectDir(projectContext); - fs::path testSourceRelativePath = fs::relative(testSourcePath, projectContext.testDirPath); + fs::path testObjectDir = Paths::getTestObjectDir(testGen->projectContext); + fs::path testSourceRelativePath = fs::relative(testSourcePath, testGen->projectContext.testDirPath); fs::path testObjectPathRelative = getRelativePath( testObjectDir / Paths::addExtension(testSourceRelativePath, ".o")); testCompilationCommand.setOutput( @@ -332,7 +332,7 @@ namespace printer { artifacts.push_back(testCompilationCommand.getOutput()); - auto rootLinkUnitInfo = buildDatabase->getClientLinkUnitInfo(rootPath); + auto rootLinkUnitInfo = testGen->getTargetBuildDatabase()->getClientLinkUnitInfo(rootPath); fs::path testExecutablePath = getTestExecutablePath(sourcePath); std::vector filesToLink{ "$(GTEST_MAIN)", "$(GTEST_ALL)", testCompilationCommand.getOutput(), @@ -353,7 +353,7 @@ namespace printer { { dynamicLinkCommand.toStringWithChangingDirectory() }); } else { utbot::LinkCommand dynamicLinkCommand = rootLinkUnitInfo->commands.front(); - dynamicLinkCommand.setLinker(cxxLinker); + dynamicLinkCommand.setBuildTool(cxxLinker); dynamicLinkCommand.setOutput(testExecutablePath); dynamicLinkCommand.erase_if([&](std::string const &argument) { return CollectionUtils::contains(rootLinkUnitInfo->files, argument) || @@ -386,7 +386,7 @@ namespace printer { sharedOutput.value().parent_path()))); dynamicLinkCommand.addFlagToBegin("$(LDFLAGS)"); - dynamicLinkCommand.setLinker(getRelativePathForLinker(cxxLinker)); + dynamicLinkCommand.setBuildTool(getRelativePathForLinker(cxxLinker)); dynamicLinkCommand.setOutput( getRelativePath(testExecutablePath)); @@ -399,14 +399,13 @@ namespace printer { } fs::path NativeMakefilePrinter::getTestExecutablePath(const fs::path &sourcePath) const { return Paths::removeExtension( - Paths::removeExtension(Paths::getRecompiledFile(projectContext, sourcePath))); + Paths::removeExtension(Paths::getRecompiledFile(testGen->projectContext, sourcePath))); } NativeMakefilePrinter::NativeMakefilePrinter(const NativeMakefilePrinter &baseMakefilePrinter, const fs::path &sourcePath) : RelativeMakefilePrinter(baseMakefilePrinter.pathToShellVariable), - projectContext(baseMakefilePrinter.projectContext), - buildDatabase(baseMakefilePrinter.buildDatabase), + testGen(baseMakefilePrinter.testGen), rootPath(baseMakefilePrinter.rootPath), primaryCompiler(baseMakefilePrinter.primaryCompiler), primaryCxxCompiler(baseMakefilePrinter.primaryCxxCompiler), @@ -427,7 +426,7 @@ namespace printer { fs::path testExecutablePath = getTestExecutablePath(sourcePath); - auto rootLinkUnitInfo = buildDatabase->getClientLinkUnitInfo(rootPath); + auto rootLinkUnitInfo = testGen->getTargetBuildDatabase()->getClientLinkUnitInfo(rootPath); fs::path coverageInfoBinary = sharedOutput.value(); if (!Paths::isLibraryFile(coverageInfoBinary)) { @@ -449,8 +448,8 @@ namespace printer { testRunCommand.addEnvironmentVariable(SanitizerUtils::ASAN_OPTIONS_NAME, SanitizerUtils::ASAN_OPTIONS_VALUE); - declareTarget("build", { getRelativePath(testExecutablePath) }, {}); - declareTarget("run", { "build" }, + declareTarget(TARGET_BUILD, { getRelativePath(testExecutablePath) }, {}); + declareTarget(TARGET_RUN, { TARGET_BUILD }, { testRunCommand.toStringWithChangingDirectory() }); close(); @@ -469,7 +468,7 @@ namespace printer { return buildResults[unitFile] = buildResult; } - auto linkUnitInfo = buildDatabase->getClientLinkUnitInfo(unitFile); + auto linkUnitInfo = testGen->getTargetBuildDatabase()->getClientLinkUnitInfo(unitFile); BuildResult::Type unitType = BuildResult::Type::NONE; CollectionUtils::MapFileTo fileMapping; auto unitBuildResults = CollectionUtils::transformTo>( @@ -490,7 +489,7 @@ namespace printer { bool isExecutable = !Paths::isLibraryFile(unitFile); fs::path recompiledFile = - Paths::getRecompiledFile(projectContext, linkUnitInfo->getOutput()); + Paths::getRecompiledFile(testGen->projectContext, linkUnitInfo->getOutput()); if (isExecutable && !transformExeToLib) { recompiledFile = Paths::isObjectFile(recompiledFile) ? recompiledFile : Paths::addExtension(recompiledFile, ".o"); @@ -514,13 +513,13 @@ namespace printer { } if (!linkCommand.isArchiveCommand()) { if (isExecutable && !transformExeToLib) { - linkCommand.setLinker(Paths::getLd()); + linkCommand.setBuildTool(Paths::getLd()); for (std::string &argument : linkCommand.getCommandLine()) { transformCompilerFlagsToLinkerFlags(argument); } } else { - linkCommand.setLinker(CompilationUtils::getBundledCompilerPath( - CompilationUtils::getCompilerName(linkCommand.getLinker()))); + linkCommand.setBuildTool(CompilationUtils::getBundledCompilerPath( + CompilationUtils::getCompilerName(linkCommand.getBuildTool()))); } std::vector libraryDirectoriesFlags; for (std::string &argument : linkCommand.getCommandLine()) { @@ -530,9 +529,9 @@ namespace printer { getLibraryAbsolutePath(argument, linkCommand.getDirectory()); if (optionalLibraryAbsolutePath.has_value()) { const fs::path &absolutePath = optionalLibraryAbsolutePath.value(); - if (Paths::isSubPathOf(projectContext.buildDir(), absolutePath)) { + if (Paths::isSubPathOf(testGen->projectContext.buildDir(), absolutePath)) { fs::path recompiledDir = - Paths::getRecompiledFile(projectContext, absolutePath); + Paths::getRecompiledFile(testGen->projectContext, absolutePath); std::string directoryFlag = getLibraryDirectoryFlag(recompiledDir); libraryDirectoriesFlags.push_back(directoryFlag); } @@ -555,7 +554,7 @@ namespace printer { } } - linkCommand.setLinker(getRelativePathForLinker(linkCommand.getLinker())); + linkCommand.setBuildTool(getRelativePathForLinker(linkCommand.getBuildTool())); for (std::string &argument : linkCommand.getCommandLine()) { tryChangeToRelativePath(argument); @@ -614,11 +613,11 @@ namespace printer { void NativeMakefilePrinter::addStubs(const CollectionUtils::FileSet &stubsSet) { auto stubObjectFiles = CollectionUtils::transformTo( Synchronizer::dropHeaders(stubsSet), [this](fs::path const &stub) { - fs::path sourcePath = Paths::stubPathToSourcePath(projectContext, stub); + fs::path sourcePath = Paths::stubPathToSourcePath(testGen->projectContext, stub); fs::path stubBuildFilePath = - Paths::getStubBuildFilePath(projectContext, sourcePath); - auto compilationUnitInfo = buildDatabase->getClientCompilationUnitInfo(sourcePath); - fs::path target = Paths::getRecompiledFile(projectContext, stub); + Paths::getStubBuildFilePath(testGen->projectContext, sourcePath); + auto compilationUnitInfo = testGen->getClientCompilationUnitInfo(sourcePath, true); + fs::path target = Paths::getRecompiledFile(testGen->projectContext, stub); addCompileTarget(stub, target, *compilationUnitInfo); return target; }); @@ -655,8 +654,7 @@ namespace printer { } // if in -I flag if (argument.length() >= 3 && StringUtils::startsWith(argument, "-I")) { - argument = "-I" + - getRelativePath(argument.substr(2)).string(); + argument = CompilationUtils::getIncludePath(getRelativePath(argument.substr(2)).string()); } } } diff --git a/server/src/printers/NativeMakefilePrinter.h b/server/src/printers/NativeMakefilePrinter.h index d7e46787e..d6ce86631 100644 --- a/server/src/printers/NativeMakefilePrinter.h +++ b/server/src/printers/NativeMakefilePrinter.h @@ -15,8 +15,7 @@ namespace printer { class NativeMakefilePrinter : public RelativeMakefilePrinter { friend class TestMakefilesPrinter; private: - const utbot::ProjectContext projectContext; - std::shared_ptr buildDatabase; + const BaseTestGen *testGen; fs::path rootPath; fs::path primaryCompiler; @@ -67,8 +66,7 @@ namespace printer { bool transformExeToLib); public: - NativeMakefilePrinter(utbot::ProjectContext projectContext, - std::shared_ptr buildDatabase, + NativeMakefilePrinter(const BaseTestGen *testGen, fs::path const &rootPath, fs::path primaryCompiler, CollectionUtils::FileSet const *stubSources, diff --git a/server/src/printers/RelativeMakefilePrinter.h b/server/src/printers/RelativeMakefilePrinter.h index 07504d42b..4f699b2ea 100644 --- a/server/src/printers/RelativeMakefilePrinter.h +++ b/server/src/printers/RelativeMakefilePrinter.h @@ -1,5 +1,6 @@ #ifndef UNITTESTBOT_RELATIVEMAKEFILEPRINTER_H #define UNITTESTBOT_RELATIVEMAKEFILEPRINTER_H + #include "printers/DefaultMakefilePrinter.h" namespace printer { diff --git a/server/src/printers/TestMakefilesPrinter.cpp b/server/src/printers/TestMakefilesPrinter.cpp index 27b15fe1a..88a23fbb3 100644 --- a/server/src/printers/TestMakefilesPrinter.cpp +++ b/server/src/printers/TestMakefilesPrinter.cpp @@ -30,27 +30,27 @@ namespace printer { sharedMakefileContent(std::move(sharedMakefileStr)), objMakefileContent(std::move(objMakefileStr)) { } - TestMakefilesPrinter::TestMakefilesPrinter(const BaseTestGen &testGen, + TestMakefilesPrinter::TestMakefilesPrinter(const BaseTestGen *testGen, CollectionUtils::FileSet const *stubSources) : TestMakefilesPrinter( - testGen.projectContext, - testGen.buildDatabase, - testGen.getTargetPath(), + testGen, + testGen->getTargetBuildDatabase()->getTargetPath(), CompilationUtils::getBundledCompilerPath(CompilationUtils::getCompilerName( - testGen.compilationDatabase->getBuildCompilerPath())), + testGen->getTargetBuildDatabase()->compilationDatabase->getBuildCompilerPath())), stubSources) { } TestMakefilesPrinter::TestMakefilesPrinter( - utbot::ProjectContext projectContext, - std::shared_ptr buildDatabase, + const BaseTestGen *testGen, fs::path const &rootPath, fs::path primaryCompiler, CollectionUtils::FileSet const *stubSources) : - RelativeMakefilePrinter(Paths::getUtbotBuildDir(projectContext), Paths::getRelativeUtbotBuildDir(projectContext), projectContext.projectPath), - projectContext(projectContext), - sharedMakefilePrinter(projectContext, buildDatabase, rootPath, primaryCompiler, stubSources, pathToShellVariable), - objMakefilePrinter(projectContext, buildDatabase, rootPath, primaryCompiler, stubSources, pathToShellVariable) { + RelativeMakefilePrinter(Paths::getUtbotBuildDir(testGen->projectContext), + Paths::getRelativeUtbotBuildDir(testGen->projectContext), + testGen->projectContext.projectPath), + projectContext(testGen->projectContext), + sharedMakefilePrinter(testGen, rootPath, primaryCompiler, stubSources, pathToShellVariable), + objMakefilePrinter(testGen, rootPath, primaryCompiler, stubSources, pathToShellVariable) { } void @@ -89,24 +89,24 @@ namespace printer { MakefileUtils::getMakeCommand(sharedMakefilePathRelative, "bin", true), " ") }); - generalMakefilePrinter.declareTarget("build", {FORCE}, { + generalMakefilePrinter.declareTarget(TARGET_BUILD, {FORCE}, { StringUtils::stringFormat("%s || %s", StringUtils::joinWith(MakefileUtils::getMakeCommand( - sharedMakefilePathRelative, "build", true), " "), + sharedMakefilePathRelative, TARGET_BUILD, true), " "), StringUtils::joinWith(MakefileUtils::getMakeCommand( - objMakefilePathRelative, "build", true), " ")) + objMakefilePathRelative, TARGET_BUILD, true), " ")) }); - generalMakefilePrinter.declareTarget("run", {FORCE}, { + generalMakefilePrinter.declareTarget(TARGET_RUN, {FORCE}, { StringUtils::stringFormat("%s && { %s; exit $$?; } || { %s && { %s; exit $$?; } }", StringUtils::joinWith(MakefileUtils::getMakeCommand( - sharedMakefilePathRelative, "build", true), " "), + sharedMakefilePathRelative, TARGET_BUILD, true), " "), StringUtils::joinWith(MakefileUtils::getMakeCommand( - sharedMakefilePathRelative, "run", true), " "), + sharedMakefilePathRelative, TARGET_RUN, true), " "), StringUtils::joinWith(MakefileUtils::getMakeCommand( - objMakefilePathRelative, "build", true), " "), + objMakefilePathRelative, TARGET_BUILD, true), " "), StringUtils::joinWith(MakefileUtils::getMakeCommand( - objMakefilePathRelative, "run", true), " ")) + objMakefilePathRelative, TARGET_RUN, true), " ")) }); generalMakefilePrinter.declareTarget("clean", {FORCE}, { StringUtils::joinWith( @@ -120,4 +120,4 @@ namespace printer { NativeMakefilePrinter(sharedMakefilePrinter, path).ss.str(), NativeMakefilePrinter(objMakefilePrinter, path).ss.str()}; } -} \ No newline at end of file +} diff --git a/server/src/printers/TestMakefilesPrinter.h b/server/src/printers/TestMakefilesPrinter.h index 9301adda6..535a0e5da 100644 --- a/server/src/printers/TestMakefilesPrinter.h +++ b/server/src/printers/TestMakefilesPrinter.h @@ -19,19 +19,18 @@ namespace printer { void write() const; }; - class TestMakefilesPrinter: public RelativeMakefilePrinter { + class TestMakefilesPrinter : public RelativeMakefilePrinter { private: utbot::ProjectContext projectContext; printer::NativeMakefilePrinter sharedMakefilePrinter; printer::NativeMakefilePrinter objMakefilePrinter; public: - TestMakefilesPrinter(const BaseTestGen &testGen, + TestMakefilesPrinter(const BaseTestGen *testGen, CollectionUtils::FileSet const *stubSources); TestMakefilesPrinter( - utbot::ProjectContext projectContext, - std::shared_ptr buildDatabase, + const BaseTestGen *testGen, fs::path const &rootPath, fs::path primaryCompiler, CollectionUtils::FileSet const *stubSources); diff --git a/server/src/streams/FileTargetsWriter.cpp b/server/src/streams/FileTargetsWriter.cpp index c71793aaf..467a99426 100644 --- a/server/src/streams/FileTargetsWriter.cpp +++ b/server/src/streams/FileTargetsWriter.cpp @@ -1,10 +1,10 @@ #include "FileTargetsWriter.h" void FileTargetsWriter::writeResponse( - const std::vector> &targets, + const std::vector &targetPaths, const utbot::ProjectContext &projectContext) { if (!hasStream()) { return; } - writeTargets(targets, projectContext); + writeTargets(targetPaths, projectContext); } diff --git a/server/src/streams/FileTargetsWriter.h b/server/src/streams/FileTargetsWriter.h index 05e3df5d2..293e22f32 100644 --- a/server/src/streams/FileTargetsWriter.h +++ b/server/src/streams/FileTargetsWriter.h @@ -11,7 +11,7 @@ class FileTargetsWriter : public TargetsWriter { : TargetsWriter(response) { } - void writeResponse(const std::vector> &targets, + void writeResponse(const std::vector &targetPaths, const utbot::ProjectContext& projectContext); }; diff --git a/server/src/streams/ProjectTargetsWriter.cpp b/server/src/streams/ProjectTargetsWriter.cpp index 4592430e4..0414eeb3a 100644 --- a/server/src/streams/ProjectTargetsWriter.cpp +++ b/server/src/streams/ProjectTargetsWriter.cpp @@ -6,11 +6,11 @@ ProjectTargetsWriter::ProjectTargetsWriter(testsgen::ProjectTargetsResponse *res void ProjectTargetsWriter::writeResponse( const utbot::ProjectContext &projectContext, - const std::vector> &targets) { + const std::vector &targetPaths) { if (!hasStream()) { return; } - writeTargets(targets, projectContext); + writeTargets(targetPaths, projectContext); auto utbotAutoTarget = std::make_unique(GrpcUtils::createAutoTarget()); writer->set_allocated_prioritytarget(utbotAutoTarget.release()); } diff --git a/server/src/streams/ProjectTargetsWriter.h b/server/src/streams/ProjectTargetsWriter.h index 814bfbe1a..5f535ffa9 100644 --- a/server/src/streams/ProjectTargetsWriter.h +++ b/server/src/streams/ProjectTargetsWriter.h @@ -13,7 +13,7 @@ class ProjectTargetsWriter : public TargetsWriter> &targets); + const std::vector &targetPaths); }; diff --git a/server/src/streams/TargetsWriter.h b/server/src/streams/TargetsWriter.h index d6102ecb5..ad40fcada 100644 --- a/server/src/streams/TargetsWriter.h +++ b/server/src/streams/TargetsWriter.h @@ -13,13 +13,13 @@ class TargetsWriter : public MessageWriter { protected: using MessageWriter::writer; - void writeTargets(const std::vector> &targets, + void writeTargets(const std::vector &targetPaths, const utbot::ProjectContext &projectContext) { auto projectTarget = writer->add_targets(); *projectTarget = GrpcUtils::createAutoTarget(); - for (auto const &target : targets) { + for (auto const &target : targetPaths) { projectTarget = writer->add_targets(); - GrpcUtils::initProjectTarget(*projectTarget, projectContext, target->getOutput()); + GrpcUtils::initProjectTarget(*projectTarget, projectContext, target); } } }; diff --git a/server/src/stubs/StubGen.cpp b/server/src/stubs/StubGen.cpp index 3f0e86ace..676014b38 100644 --- a/server/src/stubs/StubGen.cpp +++ b/server/src/stubs/StubGen.cpp @@ -8,7 +8,8 @@ #include "clang-utils/SourceToHeaderRewriter.h" #include "printers/CCJsonPrinter.h" #include "streams/stubs/StubsWriter.h" - +#include "loguru.h" +#include "environment/EnvironmentPaths.h" StubGen::StubGen(BaseTestGen &testGen) : testGen(testGen) { } @@ -18,16 +19,15 @@ CollectionUtils::FileSet StubGen::getStubSources(const fs::path &target) { return {}; } fs::path testedFilePath = *testGen.testingMethodsSourcePaths.begin(); - auto stubSources = StubSourcesFinder(testGen.buildDatabase).excludeFind(testedFilePath, target); + auto stubSources = StubSourcesFinder(testGen.getProjectBuildDatabase()).excludeFind(testedFilePath, target); return { stubSources.begin(), stubSources.end() }; -}; +} CollectionUtils::FileSet StubGen::findStubFilesBySignatures(const std::vector &signatures) { fs::path ccJsonDirPath = Paths::getUtbotBuildDir(testGen.projectContext) / "stubs_build_files"; - auto stubFiles = - Paths::findFilesInFolder(Paths::getStubsDirPath(testGen.projectContext)); + auto stubFiles = Paths::findFilesInFolder(Paths::getStubsDirPath(testGen.projectContext)); stubFiles = Synchronizer::dropHeaders(stubFiles); CollectionUtils::erase_if(stubFiles, [this](fs::path const &stubPath) { fs::path sourcePath = Paths::stubPathToSourcePath(testGen.projectContext, stubPath); @@ -100,3 +100,30 @@ bool StubGen::cmpMethodsDecl(const Tests::MethodDescription &decl1, } return true; } + +Result StubGen::getStubSetForObject(const fs::path &objectFilePath) { + ShellExecTask::ExecutionParameters nmCommand( + Paths::getLLVMnm(), + { "--print-file-name", "--undefined-only", "--just-symbol-name", objectFilePath }); + auto [out, status, _] = ShellExecTask::runShellCommandTask(nmCommand, testGen.serverBuildDir); + if (status != 0) { + std::string errorMessage = + StringUtils::stringFormat("llvm-nm on %s failed: %s", objectFilePath, out); + LOG_S(ERROR) << errorMessage; + return errorMessage; + } + auto symbols = + CollectionUtils::transform(StringUtils::split(out, '\n'), [](std::string const &line) { + return StringUtils::splitByWhitespaces(line).back(); + }); + CollectionUtils::erase_if(symbols, [](std::string const &symbol) { + return StringUtils::startsWith(symbol, "__ubsan") || + StringUtils::startsWith(symbol, "klee_"); + }); + auto signatures = CollectionUtils::transform(symbols, [](std::string const &symbol) { + Tests::MethodDescription methodDescription; + methodDescription.name = symbol; + return methodDescription; + }); + return findStubFilesBySignatures(signatures); +} diff --git a/server/src/stubs/StubGen.h b/server/src/stubs/StubGen.h index 397d17b0a..87ed4972f 100644 --- a/server/src/stubs/StubGen.h +++ b/server/src/stubs/StubGen.h @@ -21,6 +21,7 @@ class StubGen { static tests::Tests mergeSourceFileIntoStub(const tests::Tests &methodDescription, const tests::Tests &srcFile); + Result getStubSetForObject(const fs::path &objectFilePath); private: BaseTestGen &testGen; diff --git a/server/src/stubs/StubSourcesFinder.cpp b/server/src/stubs/StubSourcesFinder.cpp index 3c3b882d4..da5a5cbe1 100644 --- a/server/src/stubs/StubSourcesFinder.cpp +++ b/server/src/stubs/StubSourcesFinder.cpp @@ -2,7 +2,7 @@ #include "loguru.h" -StubSourcesFinder::StubSourcesFinder(std::shared_ptr buildDatabase) +StubSourcesFinder::StubSourcesFinder(std::shared_ptr buildDatabase) : buildDatabase(std::move(buildDatabase)) { } @@ -18,8 +18,7 @@ std::vector StubSourcesFinder::find(const fs::path& testedFilePath) { return stubSources; } -std::vector StubSourcesFinder::excludeFind(const fs::path &testedFilePath, - const fs::path &rootPath) { +std::vector StubSourcesFinder::excludeFind(const fs::path &testedFilePath, const fs::path &rootPath) { auto allBitcodeFiles = buildDatabase->getArchiveObjectFiles(rootPath); CollectionUtils::FileSet libraryBitcodeFiles = getLibraryBitcodeFiles(testedFilePath); std::vector stubSources; diff --git a/server/src/stubs/StubSourcesFinder.h b/server/src/stubs/StubSourcesFinder.h index 7ee47987e..10461eb90 100644 --- a/server/src/stubs/StubSourcesFinder.h +++ b/server/src/stubs/StubSourcesFinder.h @@ -1,7 +1,7 @@ #ifndef UNITTESTBOT_STUBSOURCESFINDER_H #define UNITTESTBOT_STUBSOURCESFINDER_H -#include "building/BuildDatabase.h" +#include "building/ProjectBuildDatabase.h" #include "stubs/Stubs.h" #include "utils/path/FileSystemPath.h" @@ -10,7 +10,7 @@ class StubSourcesFinder { public: - explicit StubSourcesFinder(std::shared_ptr buildDatabase); + explicit StubSourcesFinder(std::shared_ptr buildDatabase); std::vector find(const fs::path& testedFilePath); @@ -19,7 +19,7 @@ class StubSourcesFinder { void printAllModules(); private: - std::shared_ptr buildDatabase; + std::shared_ptr buildDatabase; CollectionUtils::FileSet getLibraryBitcodeFiles(const fs::path &testedFilePath); }; diff --git a/server/src/testgens/BaseTestGen.cpp b/server/src/testgens/BaseTestGen.cpp index 06c442700..a07a34c54 100644 --- a/server/src/testgens/BaseTestGen.cpp +++ b/server/src/testgens/BaseTestGen.cpp @@ -1,18 +1,20 @@ #include "BaseTestGen.h" +#include "exceptions/CompilationDatabaseException.h" #include "FileTestGen.h" #include "FolderTestGen.h" #include "LineTestGen.h" #include "utils/ExecUtils.h" #include "utils/ServerUtils.h" #include "utils/TypeUtils.h" +#include "loguru.h" BaseTestGen::BaseTestGen(const testsgen::ProjectContext &projectContext, const testsgen::SettingsContext &settingsContext, ProgressWriter *progressWriter, bool testMode) - : projectContext(projectContext), - settingsContext(settingsContext), progressWriter(progressWriter) { + : projectContext(projectContext), + settingsContext(settingsContext), progressWriter(progressWriter) { serverBuildDir = Paths::getUtbotBuildDir(this->projectContext); } @@ -29,45 +31,60 @@ bool BaseTestGen::isBatched() const { void BaseTestGen::setInitializedTestsMap() { tests.clear(); - for (const fs::path & sourcePath : testingMethodsSourcePaths) { + for (const fs::path &sourcePath: testingMethodsSourcePaths) { tests::Tests testsSuite; testsSuite.sourceFilePath = sourcePath; testsSuite.sourceFileNameNoExt = testsSuite.sourceFilePath.stem().string(); testsSuite.relativeFileDir = - Paths::getRelativeDirPath(projectContext, testsSuite.sourceFilePath); + Paths::getRelativeDirPath(projectContext, testsSuite.sourceFilePath); testsSuite.testFilename = Paths::sourcePathToTestName(testsSuite.sourceFilePath); testsSuite.testHeaderFilePath = - Paths::getGeneratedHeaderPath(projectContext, testsSuite.sourceFilePath); + Paths::getGeneratedHeaderPath(projectContext, testsSuite.sourceFilePath); testsSuite.testSourceFilePath = - Paths::sourcePathToTestPath(projectContext, testsSuite.sourceFilePath); + Paths::sourcePathToTestPath(projectContext, testsSuite.sourceFilePath); tests[testsSuite.sourceFilePath] = testsSuite; } } void BaseTestGen::setTargetPath(fs::path _targetPath) { - if (targetPath != _targetPath) { - targetPath = std::move(_targetPath); - if (!hasAutoTarget()) { - updateTargetSources(); - } + if (targetBuildDatabase->hasAutoTarget() && targetBuildDatabase->getTargetPath() != _targetPath) { + targetBuildDatabase = std::make_shared(projectBuildDatabase.get(), _targetPath); + updateTargetSources(_targetPath); } } -void BaseTestGen::updateTargetSources() { - targetSources = CollectionUtils::transformTo( - buildDatabase->getArchiveObjectFiles(getTargetPath()), [this](fs::path const &objectPath) { - return buildDatabase->getClientCompilationUnitInfo(objectPath)->getSourcePath(); - }); +void BaseTestGen::updateTargetSources(fs::path _targetPath) { + targetSources = targetBuildDatabase->getSourceFilesForTarget(_targetPath); for (auto it = tests.begin(); it != tests.end(); it++) { tests::Tests &test = it.value(); test.isFilePresentedInCommands = CollectionUtils::contains(targetSources, test.sourceFilePath); } } -fs::path const &BaseTestGen::getTargetPath() const { - return targetPath.value(); +std::shared_ptr BaseTestGen::getProjectBuildDatabase() const { + return projectBuildDatabase; } -bool BaseTestGen::hasAutoTarget() const { - return getTargetPath() == GrpcUtils::UTBOT_AUTO_TARGET_PATH; +std::shared_ptr BaseTestGen::getTargetBuildDatabase() const { + return targetBuildDatabase; +} + +std::shared_ptr BaseTestGen::getProjectBuildDatabase() { + return projectBuildDatabase; +} + +std::shared_ptr BaseTestGen::getTargetBuildDatabase() { + return targetBuildDatabase; +} + +std::shared_ptr +BaseTestGen::getClientCompilationUnitInfo(const fs::path &path, bool fullProject) const { + std::shared_ptr objectFileInfo; + if (targetBuildDatabase->hasUnitInfo(path) || !fullProject) { + objectFileInfo = targetBuildDatabase->getClientCompilationUnitInfo(path); + } else { + objectFileInfo = projectBuildDatabase->getClientCompilationUnitInfo(path); + LOG_S(WARNING) << "Can't find in target: " << path; + } + return objectFileInfo; } diff --git a/server/src/testgens/BaseTestGen.h b/server/src/testgens/BaseTestGen.h index 611bf2e7d..5e87e0219 100644 --- a/server/src/testgens/BaseTestGen.h +++ b/server/src/testgens/BaseTestGen.h @@ -2,10 +2,10 @@ #define UNITTESTBOT_BASETESTGEN_H #include "ProjectContext.h" -#include "ProjectTarget.h" #include "SettingsContext.h" #include "Tests.h" -#include "building/BuildDatabase.h" +#include "building/ProjectBuildDatabase.h" +#include "building/TargetBuildDatabase.h" #include "printers/TestsPrinter.h" #include "streams/tests/TestsWriter.h" #include "stubs/Stubs.h" @@ -24,8 +24,6 @@ class BaseTestGen { fs::path serverBuildDir; fs::path compileCommandsJsonPath; - std::shared_ptr compilationDatabase; - std::shared_ptr buildDatabase; CollectionUtils::FileSet sourcePaths, testingMethodsSourcePaths; tests::TestsMap tests; @@ -33,7 +31,6 @@ class BaseTestGen { std::vector synchronizedStubs; types::TypeMaps types; - std::optional targetPath; CollectionUtils::FileSet targetSources; virtual std::string toString() = 0; @@ -42,12 +39,25 @@ class BaseTestGen { bool isBatched() const; - bool hasAutoTarget() const; - fs::path const &getTargetPath() const; void setTargetPath(fs::path _targetPath); virtual ~BaseTestGen() = default; + + std::shared_ptr getProjectBuildDatabase() const; + + std::shared_ptr getTargetBuildDatabase() const; + + std::shared_ptr getProjectBuildDatabase(); + + std::shared_ptr getTargetBuildDatabase(); + + std::shared_ptr + getClientCompilationUnitInfo(const fs::path &path, bool fullProject = false) const; + protected: + std::shared_ptr projectBuildDatabase; + std::shared_ptr targetBuildDatabase; + BaseTestGen(const testsgen::ProjectContext &projectContext, const testsgen::SettingsContext &settingsContext, ProgressWriter *progressWriter, @@ -55,9 +65,9 @@ class BaseTestGen { void setInitializedTestsMap(); - virtual void setTargetForSource(fs::path const& sourcePath) = 0; + virtual void setTargetForSource(fs::path const &sourcePath) = 0; - void updateTargetSources(); + void updateTargetSources(fs::path _targetPath); }; diff --git a/server/src/testgens/FileTestGen.cpp b/server/src/testgens/FileTestGen.cpp index cd954ac85..47af24915 100644 --- a/server/src/testgens/FileTestGen.cpp +++ b/server/src/testgens/FileTestGen.cpp @@ -5,9 +5,9 @@ FileTestGen::FileTestGen(const testsgen::FileRequest &request, ProgressWriter *progressWriter, bool testMode) - : ProjectTestGen(request.projectrequest(), progressWriter, testMode, false), - filepath(fs::weakly_canonical(request.filepath())) { - testingMethodsSourcePaths = { filepath }; + : ProjectTestGen(request.projectrequest(), progressWriter, testMode, false), + filepath(fs::weakly_canonical(request.filepath())) { + testingMethodsSourcePaths = {filepath}; setInitializedTestsMap(); } diff --git a/server/src/testgens/ProjectTestGen.cpp b/server/src/testgens/ProjectTestGen.cpp index 05feec01c..6c6ca59b1 100644 --- a/server/src/testgens/ProjectTestGen.cpp +++ b/server/src/testgens/ProjectTestGen.cpp @@ -9,23 +9,23 @@ ProjectTestGen::ProjectTestGen(const testsgen::ProjectRequest &request, ProgressWriter *progressWriter, bool testMode, bool autoDetect) - : BaseTestGen(request.projectcontext(), - request.settingscontext(), - progressWriter, - testMode), request(&request) { + : BaseTestGen(request.projectcontext(), + request.settingscontext(), + progressWriter, + testMode), request(&request) { fs::create_directories(projectContext.testDirPath); compileCommandsJsonPath = CompilationUtils::substituteRemotePathToCompileCommandsJsonPath( - projectContext.projectPath, projectContext.buildDirRelativePath); - buildDatabase = - std::make_shared(compileCommandsJsonPath, serverBuildDir, projectContext); - compilationDatabase = CompilationUtils::getCompilationDatabase(compileCommandsJsonPath); + projectContext.projectPath, projectContext.buildDirRelativePath); + projectBuildDatabase = std::make_shared(compileCommandsJsonPath, serverBuildDir, projectContext); + targetBuildDatabase = std::make_shared(projectBuildDatabase.get(), request.targetpath()); if (autoDetect) { autoDetectSourcePathsIfNotEmpty(); } else { - sourcePaths = compilationDatabase->getAllFiles(); + sourcePaths = targetBuildDatabase->compilationDatabase->getAllFiles(); } testingMethodsSourcePaths = sourcePaths; setInitializedTestsMap(); + updateTargetSources(targetBuildDatabase->getTargetPath()); } std::string ProjectTestGen::toString() { @@ -36,7 +36,7 @@ std::string ProjectTestGen::toString() { } void ProjectTestGen::setTargetForSource(const fs::path &sourcePath) { - fs::path root = buildDatabase->getRootForSource(sourcePath); + fs::path root = targetBuildDatabase->getRootForSource(sourcePath); setTargetPath(root); } @@ -53,7 +53,7 @@ void ProjectTestGen::autoDetectSourcePathsIfNotEmpty() { // requestSourcePaths are from settings.json auto requestSourcePaths = getRequestSourcePaths(); // sourcePathsCandidates are from compile_commands.json - auto sourcePathsCandidates = compilationDatabase->getAllFiles(); + auto sourcePathsCandidates = targetBuildDatabase->compilationDatabase->getAllFiles(); if (!requestSourcePaths.empty()) { sourcePaths = Paths::filterPathsByDirNames(sourcePathsCandidates, requestSourcePaths, Paths::isSourceFile); diff --git a/server/src/testgens/ProjectTestGen.h b/server/src/testgens/ProjectTestGen.h index d96c754b5..9fe1f0696 100644 --- a/server/src/testgens/ProjectTestGen.h +++ b/server/src/testgens/ProjectTestGen.h @@ -2,7 +2,6 @@ #define UNITTESTBOT_PROJECTTESTGEN_H #include "BaseTestGen.h" -#include "ProjectTarget.h" #include @@ -18,7 +17,7 @@ class ProjectTestGen : public BaseTestGen { std::string toString() override; const testsgen::ProjectRequest *getRequest() const; - + void setTargetForSource(fs::path const &sourcePath) override; private: diff --git a/server/src/testgens/SnippetTestGen.cpp b/server/src/testgens/SnippetTestGen.cpp index f1230c319..600521db3 100644 --- a/server/src/testgens/SnippetTestGen.cpp +++ b/server/src/testgens/SnippetTestGen.cpp @@ -3,22 +3,23 @@ #include "printers/CCJsonPrinter.h" #include "utils/CompilationUtils.h" +const std::string SNIPPET_TARGET = "executable"; + SnippetTestGen::SnippetTestGen(const testsgen::SnippetRequest &request, ProgressWriter *progressWriter, bool testMode) - : BaseTestGen(request.projectcontext(), - request.settingscontext(), - progressWriter, - testMode) { + : BaseTestGen(request.projectcontext(), + request.settingscontext(), + progressWriter, + testMode) { filePath = fs::weakly_canonical(request.filepath()); - sourcePaths = { filePath }; + sourcePaths = {filePath}; testingMethodsSourcePaths = sourcePaths; printer::CCJsonPrinter::createDummyBuildDB(sourcePaths, serverBuildDir); compileCommandsJsonPath = serverBuildDir; - utbot::ProjectContext projectContext{ request, serverBuildDir }; - buildDatabase = - std::make_shared(compileCommandsJsonPath, serverBuildDir, projectContext); - compilationDatabase = CompilationUtils::getCompilationDatabase(serverBuildDir); + utbot::ProjectContext projectContext{request, serverBuildDir}; + projectBuildDatabase = std::make_shared(compileCommandsJsonPath, serverBuildDir, projectContext); + targetBuildDatabase = std::make_shared(projectBuildDatabase.get(), serverBuildDir / SNIPPET_TARGET); setTargetForSource(filePath); setInitializedTestsMap(); } @@ -28,6 +29,6 @@ std::string SnippetTestGen::toString() { } void SnippetTestGen::setTargetForSource(const fs::path &sourcePath) { - fs::path root = serverBuildDir / "executable"; + fs::path root = serverBuildDir / SNIPPET_TARGET; setTargetPath(root); } diff --git a/server/src/types/TypesResolver.cpp b/server/src/types/TypesResolver.cpp index bf235887c..8074498bb 100644 --- a/server/src/types/TypesResolver.cpp +++ b/server/src/types/TypesResolver.cpp @@ -20,7 +20,7 @@ static bool canBeReplaced(const std::string &nameInMap, const std::string &name) return nameInMap.empty() && !name.empty(); } -template +template bool isCandidateToReplace(uint64_t id, std::unordered_map &someMap, std::string const &name) { diff --git a/server/src/utils/CompilationUtils.cpp b/server/src/utils/CompilationUtils.cpp index fde3c4d8a..406070f0b 100644 --- a/server/src/utils/CompilationUtils.cpp +++ b/server/src/utils/CompilationUtils.cpp @@ -228,4 +228,8 @@ namespace CompilationUtils { return std::nullopt; } } + + std::string getIncludePath(const fs::path &includePath) { + return "-I" + includePath.string(); + } } diff --git a/server/src/utils/CompilationUtils.h b/server/src/utils/CompilationUtils.h index 792c8a137..fd1449c0d 100644 --- a/server/src/utils/CompilationUtils.h +++ b/server/src/utils/CompilationUtils.h @@ -50,6 +50,8 @@ namespace CompilationUtils { fs::path getBundledCompilerPath(CompilerName compilerName); std::optional getResourceDirectory(const fs::path& buildCompilerPath); + + std::string getIncludePath(const fs::path &includePath); } #endif //UNITTESTBOT_COPMILATIONUTILS_H diff --git a/server/src/utils/GenerationUtils.cpp b/server/src/utils/GenerationUtils.cpp index 436cadadc..d0343cff6 100644 --- a/server/src/utils/GenerationUtils.cpp +++ b/server/src/utils/GenerationUtils.cpp @@ -50,32 +50,39 @@ void GenerationUtils::generateCoverageAndResultsAndWriteStatus( std::optional GenerationUtils::findTarget(const BaseTestGen &baseTestGen, const std::string &name) { + return findTarget(baseTestGen.getTargetBuildDatabase()->getAllTargets(), name); +} + +std::optional +GenerationUtils::findTarget(const std::vector> &allTargets, + const std::string &name) { if (name.empty()) { LOG_S(INFO) << "Target was not chosen. Using UTBot: Auto target instead."; return GrpcUtils::UTBOT_AUTO_TARGET_PATH; } - auto allTargets = baseTestGen.buildDatabase->getAllTargets(); auto candidates = CollectionUtils::filterOut(allTargets, [&name](auto const &target) { fs::path output = target->getOutput(); - return !(output == name || output.stem() == name || output.stem() == "lib" + name); + return !(output == name || output.stem() == name || output.stem() == "lib" + name || output.filename() == name); }); if (candidates.empty()) { - LOG_S(WARNING) << "Couldn't find appropriate target. List of available targets:\n"; + std::stringstream ss; + ss << "Couldn't find \"" << name << "\" target. List of available targets:\n"; for (const auto &target : allTargets) { - LOG_S(WARNING) << target->getOutput() << "\n"; + ss << target->getOutput() << "\n"; } - LOG_S(WARNING) << "\n"; + LOG_S(WARNING) << ss.str(); return std::nullopt; } else if (candidates.size() == 1) { return candidates[0]->getOutput(); } else { - LOG_S(WARNING) << "There are multiple candidates for given target. " + std::stringstream ss; + ss << "There are multiple candidates for given target. " "Please, specify full path of your preferred target. " "List of candidates:\n"; for (const auto &candidate : candidates) { - LOG_S(WARNING) << candidate->getOutput() << "\n"; + ss << candidate->getOutput() << "\n"; } - LOG_S(WARNING) << "\n"; + LOG_S(WARNING) << ss.str(); return std::nullopt; } } diff --git a/server/src/utils/GenerationUtils.h b/server/src/utils/GenerationUtils.h index c86ee750f..c80cc229f 100644 --- a/server/src/utils/GenerationUtils.h +++ b/server/src/utils/GenerationUtils.h @@ -24,6 +24,10 @@ using grpc::Status; using grpc::StatusCode; namespace GenerationUtils { + + std::optional + findTarget(const std::vector> &allTargets, const std::string &name); + std::optional findTarget(const BaseTestGen &baseTestGen, const std::string &name); template @@ -34,24 +38,16 @@ namespace GenerationUtils { ServerUtils::setThreadOptions(ctx, true); auto testsWriter = std::make_unique(); auto testGen = std::make_unique(request, testsWriter.get(), true); - if constexpr (std::is_base_of_v) { - auto targetPath = findTarget(*testGen, testGen->getRequest()->targetpath()); - if (!targetPath.has_value()) { - auto status = grpc::Status(grpc::INVALID_ARGUMENT, "Couldn't find appropriate target"); - return std::make_pair(std::move(testGen), status); - } - testGen->setTargetPath(targetPath.value()); - } Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(*testGen, testsWriter.get()); if (status.error_code() == grpc::FAILED_PRECONDITION) { if (status.error_message() == FileNotPresentedInArtifactException::MESSAGE || status.error_message() == FileNotPresentedInCommandsException::MESSAGE) { fs::path path = status.error_details(); - auto targetsForSourceFile = testGen->buildDatabase->getTargetsForSourceFile(path); + auto targetPaths = testGen->getProjectBuildDatabase()->getTargetPathsForSourceFile(path); LOG_S(WARNING) << "List of possible targets for current file:\n"; - for (auto const& target: targetsForSourceFile) { - LOG_S(WARNING) << target->getOutput() << "\n"; + for (auto const& target: targetPaths) { + LOG_S(WARNING) << target << "\n"; } LOG_S(WARNING) << "\n"; } diff --git a/server/src/utils/GrpcUtils.h b/server/src/utils/GrpcUtils.h index 269567d6c..8406850fb 100644 --- a/server/src/utils/GrpcUtils.h +++ b/server/src/utils/GrpcUtils.h @@ -2,7 +2,6 @@ #define UNITTESTBOT_GRPCUTILS_H #include "ProjectContext.h" -#include "ProjectTarget.h" #include "utils/path/FileSystemPath.h" #include diff --git a/server/src/utils/path/FileSystemPath.h b/server/src/utils/path/FileSystemPath.h index d67fea6eb..b25a8cd23 100644 --- a/server/src/utils/path/FileSystemPath.h +++ b/server/src/utils/path/FileSystemPath.h @@ -13,17 +13,13 @@ namespace fs { class path { public: - path(const std::filesystem::path& p) : path_(normalizedTrimmed(p)) { - } + path(const std::filesystem::path &p) : path_(normalizedTrimmed(p)) {} path() {} - path(const std::string& s) : path_(normalizedTrimmed(s)) { - } - - path(const char *s) : path_(normalizedTrimmed(s)) { + path(const std::string &s) : path_(normalizedTrimmed(s)) {} - } + path(const char *s) : path_(normalizedTrimmed(s)) {} path root_path() const { return path(path_.root_path()); diff --git a/server/test/framework/KleeGen_Tests.cpp b/server/test/framework/KleeGen_Tests.cpp index df91a3ec2..51486f1c6 100644 --- a/server/test/framework/KleeGen_Tests.cpp +++ b/server/test/framework/KleeGen_Tests.cpp @@ -15,18 +15,15 @@ namespace { struct TestSuite { std::string name; - fs::path buildPath; CollectionUtils::FileSet sourcesFilePaths; }; - fs::path tmpDirPath = baseSuitePath / buildDirRelativePath; TestSuite testSuite; void SetUp() override { clearEnv(CompilationUtils::CompilerName::CLANG); testSuite = { suiteName, - buildPath, { getTestFilePath("assertion_failures.c"), getTestFilePath("basic_functions.c"), getTestFilePath("complex_structs.c"), @@ -43,31 +40,16 @@ namespace { getTestFilePath("types.c"), getTestFilePath("inner/inner_basic_functions.c") } }; } - - KleeGenerator initKleeGenerator(const TestSuite &suite, std::string &errorMessage) { - std::shared_ptr compilationDatabase = - CompilationDatabase::autoDetectFromDirectory( - suite.buildPath.string(), errorMessage); - types::TypesHandler::SizeContext sizeContext; - types::TypeMaps typeMaps; - types::TypesHandler typesHandler(typeMaps, sizeContext); - fs::path testsDirPath = tmpDirPath / "test"; - utbot::ProjectContext projectContext{ suite.name, "", testsDirPath, - buildDirRelativePath }; - auto buildDatabase = - std::make_shared(suite.buildPath, suite.buildPath, projectContext); - utbot::SettingsContext settingsContext{ true, true, 15, 0, true, false }; - KleeGenerator generator(std::move(projectContext), - std::move(settingsContext), tmpDirPath, - compilationDatabase, typesHandler, {}, buildDatabase); - return generator; - } }; TEST_F(KleeGen_Test, BuildByCDb) { - std::string errorMessage; - auto generator = initKleeGenerator(testSuite, errorMessage); - ASSERT_TRUE(errorMessage.empty()); + types::TypesHandler::SizeContext sizeContext; + types::TypeMaps typeMaps; + types::TypesHandler typesHandler(typeMaps, sizeContext); + auto request = testUtils::createProjectRequest(testSuite.name, suitePath, buildDirRelativePath, {}); + auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); + KleeGenerator generator(&testGen, typesHandler, {}); + CollectionUtils::FileSet sources(testSuite.sourcesFilePaths.begin(), testSuite.sourcesFilePaths.end()); sources.erase(getTestFilePath("snippet.c")); sources.erase(getTestFilePath("external_dependent.c")); @@ -78,9 +60,13 @@ namespace { } TEST_F(KleeGen_Test, DefaultBuild) { - std::string errorMessage; - auto generator = initKleeGenerator(testSuite, errorMessage); - ASSERT_TRUE(errorMessage.empty()); + types::TypesHandler::SizeContext sizeContext; + types::TypeMaps typeMaps; + types::TypesHandler typesHandler(typeMaps, sizeContext); + auto request = testUtils::createProjectRequest(testSuite.name, suitePath, buildDirRelativePath, {}); + auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); + KleeGenerator generator(&testGen, typesHandler, {}); + fs::path sourceFilePath = *testSuite.sourcesFilePaths.begin(); auto actualFilePath = generator.defaultBuild(sourceFilePath); EXPECT_TRUE(fs::exists(actualFilePath.getOpt().value())); diff --git a/server/test/framework/Library_Test.cpp b/server/test/framework/Library_Test.cpp index 1a583616b..21d63481e 100644 --- a/server/test/framework/Library_Test.cpp +++ b/server/test/framework/Library_Test.cpp @@ -20,12 +20,12 @@ namespace { std::pair createTestForFunction(const fs::path &pathToFile, int lineNum, int kleeTimeout = 60) { auto lineRequest = testUtils::createLineRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, pathToFile, lineNum, true, false, kleeTimeout); + srcPaths, pathToFile, lineNum, + pathToFile, true, false, + kleeTimeout); auto request = GrpcUtils::createFunctionRequest(std::move(lineRequest)); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetForSource(pathToFile); - Status status = - Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); return { testGen, status }; } }; diff --git a/server/test/framework/Regression_Tests.cpp b/server/test/framework/Regression_Tests.cpp index 36a82f989..0df4c355d 100644 --- a/server/test/framework/Regression_Tests.cpp +++ b/server/test/framework/Regression_Tests.cpp @@ -28,22 +28,22 @@ namespace { std::pair createTestForFunction(const fs::path &pathToFile, int lineNum, bool verbose = true) { auto lineRequest = testUtils::createLineRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, pathToFile, lineNum, false, verbose, 0); + srcPaths, pathToFile, lineNum, + pathToFile, false, verbose, 0); auto request = GrpcUtils::createFunctionRequest(std::move(lineRequest)); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetForSource(pathToFile); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); - return { testGen, status }; + return {testGen, status}; } std::pair createTestForFolder(const fs::path &pathToFolder, bool useStubs = true, bool verbose = true) { auto folderRequest = testUtils::createProjectRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, useStubs, verbose, 0); + srcPaths, GrpcUtils::UTBOT_AUTO_TARGET_PATH, useStubs, + verbose, 0); auto request = GrpcUtils::createFolderRequest(std::move(folderRequest), pathToFolder); auto testGen = FolderTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetPath(GrpcUtils::UTBOT_AUTO_TARGET_PATH); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); return {testGen, status}; @@ -89,10 +89,9 @@ namespace { TEST_F(Regression_Test, Incomplete_Array_Type) { fs::path folderPath = suitePath / "SAT-760"; auto projectRequest = testUtils::createProjectRequest( - projectName, suitePath, buildDirRelativePath, { suitePath, folderPath }); + projectName, suitePath, buildDirRelativePath, { suitePath, folderPath }, "SAT-760"); auto request = GrpcUtils::createFolderRequest(std::move(projectRequest), folderPath); auto testGen = FolderTestGen(*request, writer.get(), TESTMODE); - testUtils::setTargetForFirstSource(testGen); fs::path source1 = folderPath / "SAT-760_1.c"; fs::path source2 = folderPath / "SAT-760_2.c"; diff --git a/server/test/framework/Server_Tests.cpp b/server/test/framework/Server_Tests.cpp index 00b5f7ac7..6982d0d01 100644 --- a/server/test/framework/Server_Tests.cpp +++ b/server/test/framework/Server_Tests.cpp @@ -56,31 +56,39 @@ namespace { void generateFiles(const fs::path &sourceFile, const fs::path &testsRelativeDir) { fs::path testsDirPath = getTestFilePath(testsRelativeDir); - utbot::ProjectContext projectContext{ projectName, suitePath, testsDirPath, - buildDirRelativePath }; - generateFiles(sourceFile, projectContext); + + auto projectContext = GrpcUtils::createProjectContext( + projectName, suitePath, testsDirPath, buildDirRelativePath); + + auto settingsContext = GrpcUtils::createSettingsContext(true, false, 30, 0, false, false); + + auto request = GrpcUtils::createProjectRequest(std::move(projectContext), + std::move(settingsContext), + srcPaths, + sourceFile); + + auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); + + generateFiles(sourceFile, testGen); } - void generateFiles(const fs::path &sourceFile, - const utbot::ProjectContext &projectContext) { + void generateFiles(const fs::path &sourceFile, const BaseTestGen& testGen) { fs::path serverBuildDir = buildPath / "temp"; - auto buildDatabase = - std::make_shared(buildPath, serverBuildDir, projectContext); fs::path compilerPath = CompilationUtils::getBundledCompilerPath(compilerName); CollectionUtils::FileSet stubsSources; - fs::path root = buildDatabase->getRootForSource(sourceFile); - printer::TestMakefilesPrinter testMakefilePrinter(projectContext, buildDatabase, - root, compilerPath, &stubsSources); + fs::path root = testGen.getTargetBuildDatabase()->getTargetPath(); + printer::TestMakefilesPrinter testMakefilePrinter(&testGen, root, compilerPath, &stubsSources); testMakefilePrinter.addLinkTargetRecursively(root, ""); testMakefilePrinter.GetMakefiles(sourceFile).write(); auto compilationDatabase = CompilationUtils::getCompilationDatabase(buildPath); auto structsToDeclare = std::make_shared(); - SourceToHeaderRewriter sourceToHeaderRewriter(projectContext, compilationDatabase, + SourceToHeaderRewriter sourceToHeaderRewriter(testGen.projectContext, compilationDatabase, structsToDeclare, serverBuildDir); std::string wrapper = sourceToHeaderRewriter.generateWrapper(sourceFile); - printer::SourceWrapperPrinter(Paths::getSourceLanguage(sourceFile)).print(projectContext, sourceFile, wrapper); + printer::SourceWrapperPrinter(Paths::getSourceLanguage(sourceFile)).print(testGen.projectContext, + sourceFile, wrapper); } @@ -631,9 +639,9 @@ namespace { TEST_F(Server_Test, Char_Literals_Test) { std::string suite = "char"; setSuite(suite); - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -654,10 +662,8 @@ namespace { fs::path b_c = getTestFilePath("b.c"); fs::path main_c = getTestFilePath("main.c"); { - auto request = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "ex"); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -674,11 +680,8 @@ namespace { } })); } { - auto request = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "one"); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - fs::path one = testGen.buildDatabase->getClientLinkUnitInfo(a_c)->getOutput(); - testGen.setTargetPath(one); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -692,10 +695,8 @@ namespace { } { auto request = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "two"); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - fs::path two = testGen.buildDatabase->getClientLinkUnitInfo(b_c)->getOutput(); - testGen.setTargetPath(two); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -714,9 +715,9 @@ namespace { TEST_F(Server_Test, Datacom_Test) { std::string suite = "datacom"; setSuite(suite); - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -909,9 +910,9 @@ namespace { std::string suite = "small-project"; setSuite(suite); srcPaths = {suitePath, suitePath / "lib", suitePath / "src"}; - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -930,9 +931,9 @@ namespace { std::string suite = "small-project"; setSuite(suite); srcPaths = {}; - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -954,9 +955,9 @@ namespace { std::string suite = "small-project"; setSuite(suite); srcPaths = { suitePath / "lib"}; - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -988,11 +989,10 @@ namespace { } TEST_P(Parameterized_Server_Test, Folder_Test) { - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto projectRequest = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto request = GrpcUtils::createFolderRequest(std::move(projectRequest), suitePath / "inner"); auto testGen = FolderTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -1002,7 +1002,7 @@ namespace { TEST_P(Parameterized_Server_Test, Line_Test1) { auto request = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - basic_functions_c, 17, false, false, 0); + basic_functions_c, 17, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); auto testGen = LineTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(basic_functions_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); @@ -1019,7 +1019,7 @@ namespace { TEST_P(Parameterized_Server_Test, Line_Test2) { auto request = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - basic_functions_c, 17, false, false, 0); + basic_functions_c, 17, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); auto testGen = LineTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(basic_functions_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); @@ -1082,7 +1082,7 @@ namespace { TEST_P(Parameterized_Server_Test, Function_Test) { auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - basic_functions_c, 6, false, false, 0); + basic_functions_c, 6, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); auto request = GrpcUtils::createFunctionRequest(std::move(lineRequest)); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(basic_functions_c); @@ -1110,7 +1110,7 @@ namespace { TEST_P(Parameterized_Server_Test, Predicate_Test_Integer) { auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - basic_functions_c, 17, false, false, 0); + basic_functions_c, 17, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); auto predicateInfo = std::make_unique(); predicateInfo->set_predicate("=="); predicateInfo->set_returnvalue("36"); @@ -1133,7 +1133,7 @@ namespace { TEST_P(Parameterized_Server_Test, Predicate_Test_Str) { auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - basic_functions_c, 32, false, false, 0); + basic_functions_c, 32, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); auto predicateInfo = std::make_unique(); predicateInfo->set_predicate("=="); predicateInfo->set_returnvalue("abacaba"); @@ -1157,7 +1157,7 @@ namespace { TEST_P(Parameterized_Server_Test, Symbolic_Stdin_Test) { auto request = std::make_unique(); auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - symbolic_stdin_c, 8, false, false, 0); + symbolic_stdin_c, 8, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); request->set_allocated_linerequest(lineRequest.release()); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(symbolic_stdin_c); @@ -1179,7 +1179,7 @@ namespace { TEST_P(Parameterized_Server_Test, Symbolic_Stdin_Long_Read) { auto request = std::make_unique(); auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - symbolic_stdin_c, 19, false, false, 0); + symbolic_stdin_c, 19, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false, false, 0); request->set_allocated_linerequest(lineRequest.release()); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(symbolic_stdin_c); @@ -1455,11 +1455,10 @@ namespace { std::string suite = "object-file"; setSuite(suite); static const std::string source2_c = getTestFilePath("source2.c"); - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto projectRequest = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto request = GrpcUtils::createFileRequest(std::move(projectRequest), source2_c); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -1570,9 +1569,9 @@ namespace { TEST_P(Parameterized_Server_Test, Clang_Resources_Directory_Test) { std::string suite = "stddef"; setSuite(suite); - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -1583,9 +1582,9 @@ namespace { TEST_P(Parameterized_Server_Test, Installed_Dependency_Test) { std::string suite = "installed"; setSuite(suite); - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -1600,9 +1599,9 @@ namespace { std::string suite = "small-project"; setSuite(suite); srcPaths = {}; - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - setTargetForFirstSource(testGen); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); diff --git a/server/test/framework/Stub_Tests.cpp b/server/test/framework/Stub_Tests.cpp index a14e36cf9..143080505 100644 --- a/server/test/framework/Stub_Tests.cpp +++ b/server/test/framework/Stub_Tests.cpp @@ -8,6 +8,8 @@ #include "coverage/CoverageAndResultsGenerator.h" #include "streams/coverage/ServerCoverageAndResultsWriter.h" #include "streams/stubs/ServerStubsWriter.h" +#include "stubs/StubGen.h" +#include "Synchronizer.h" #include @@ -111,9 +113,10 @@ namespace { TEST_F(Stub_Test, Project_Stubs_Test) { auto stubsWriter = std::make_unique(nullptr, false); - auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, true); + auto request = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, + GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = std::make_unique(*request, writer.get(), TESTMODE); - std::vector stubSources = { calc_sum_c, calc_mult_c, literals_foo_c }; + std::vector stubSources = {calc_sum_c, calc_mult_c, literals_foo_c}; Status status = Server::TestsGenServiceImpl::ProcessProjectStubsRequest(testGen.get(), stubsWriter.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -122,7 +125,7 @@ namespace { TEST_F(Stub_Test, Implicit_Stubs_Test) { auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - literals_foo_c, true); + literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); @@ -135,7 +138,7 @@ namespace { TEST_F(Stub_Test, Pregenerated_Stubs_Test) { { auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - literals_foo_c, true); + literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); @@ -146,7 +149,7 @@ namespace { { auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, literals_foo_c, true); + srcPaths, literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); @@ -159,33 +162,28 @@ namespace { TEST_F(Stub_Test, Multimodule_Lib_Heuristic_Test) { auto request = testUtils::createProjectRequest(projectName, suitePath, buildDirRelativePath, - { foreign, calc, suitePath, literals }, true); + {foreign, calc, suitePath, literals}, + foreign_bar_c, true); auto testGen = ProjectTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetForSource(foreign_bar_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); EXPECT_EQ(testUtils::getNumberOfTests(testGen.tests), 2); - auto root = testGen.buildDatabase->getRootForSource(foreign_bar_c); - auto linkUnitInfo = testGen.buildDatabase->getClientLinkUnitInfo(root); - auto stubFiles = testGen.buildDatabase->getStubFiles(linkUnitInfo); - utbot::ProjectContext projectContext{ projectName, suitePath, getTestDirectory(), - buildDirRelativePath }; - auto stubCandidates = { calc_sum_c }; - auto expectedStubFiles = CollectionUtils::transformTo( - stubCandidates, [&projectContext](fs::path const &path) { - return Paths::sourcePathToStubPath(projectContext, path); - }); - EXPECT_EQ(expectedStubFiles, stubFiles); + const fs::path objectFile = testGen.getClientCompilationUnitInfo(foreign_bar_c)->getOutputFile(); + auto result = StubGen(testGen).getStubSetForObject(objectFile); + ASSERT_TRUE(result.isSuccess()); + auto stubCandidates = {calc_sum_c}; + auto expectedStubFiles = CollectionUtils::transformTo( + stubCandidates, [&testGen](fs::path const &path) { + return Paths::sourcePathToStubPath(testGen.projectContext, path); + }); + EXPECT_EQ(expectedStubFiles, result.getOpt().value()); } - - TEST_F(Stub_Test, File_Tests_With_Stubs) { auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, literals_foo_c, true); + srcPaths, literals_foo_c, literals_foo_c, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetForSource(literals_foo_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); EXPECT_EQ(testUtils::getNumberOfTests(testGen.tests), 5); @@ -218,7 +216,7 @@ namespace { TEST_F(Stub_Test, Run_Tests_For_Unused_Function) { auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, calc_sum_c, true); + srcPaths, calc_sum_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(calc_sum_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); @@ -239,7 +237,7 @@ namespace { TEST_F(Stub_Test, File_Tests_Without_Stubs) { auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, literals_foo_c, false); + srcPaths, literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, false); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); @@ -270,7 +268,7 @@ namespace { } TEST_F(Stub_Test, DISABLED_Sync_Stub_When_Source_Changed_Test) { - auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, literals_foo_c, true); + auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -279,11 +277,11 @@ namespace { modifySources(sourcesToModify); std::string stubCode = modifyStubFile(sum_stub_c); - auto request2 = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, literals_foo_c, true); + auto request2 = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen2 = FileTestGen(*request2, writer.get(), TESTMODE); { auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - literals_foo_c, true); + literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); @@ -292,7 +290,7 @@ namespace { } { auto request = createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, literals_foo_c, true); + srcPaths, literals_foo_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(literals_foo_c); diff --git a/server/test/framework/Syntax_Tests.cpp b/server/test/framework/Syntax_Tests.cpp index 8b5df170f..0cfe70559 100644 --- a/server/test/framework/Syntax_Tests.cpp +++ b/server/test/framework/Syntax_Tests.cpp @@ -81,10 +81,10 @@ namespace { std::pair createTestForFunction(const fs::path &pathToFile, int lineNum, int kleeTimeout = 60) { auto lineRequest = createLineRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, pathToFile, lineNum, false, false, kleeTimeout); + srcPaths, pathToFile, lineNum, pathToFile, + false, false, kleeTimeout); auto request = GrpcUtils::createFunctionRequest(std::move(lineRequest)); auto testGen = FunctionTestGen(*request, writer.get(), TESTMODE); - testGen.setTargetForSource(pathToFile); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); size_t failed_build = TestRunner::buildTests(testGen.projectContext, testGen.tests); if (status.ok() && failed_build != 0) { @@ -2199,7 +2199,8 @@ namespace { TEST_F(Syntax_Test, Run_Tests_For_Linked_List) { auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, linked_list_c, true, false); + srcPaths, linked_list_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true, + false); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(linked_list_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); @@ -2232,7 +2233,7 @@ namespace { TEST_F(Syntax_Test, Run_Tests_For_Tree) { auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, - srcPaths, tree_c, true, false); + srcPaths, tree_c, GrpcUtils::UTBOT_AUTO_TARGET_PATH, true, false); auto testGen = FileTestGen(*request, writer.get(), TESTMODE); testGen.setTargetForSource(tree_c); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); diff --git a/server/test/framework/Targets_Test.cpp b/server/test/framework/Targets_Test.cpp index da41615c6..5fc2e13d3 100644 --- a/server/test/framework/Targets_Test.cpp +++ b/server/test/framework/Targets_Test.cpp @@ -11,90 +11,279 @@ class TargetsTest : public BaseTest { } fs::path parse_c = getTestFilePath("parse.c"); - - fs::path getTargetPathByName(BuildDatabase const &buildDatabase, fs::path const &fileName) { - auto rootTargets = buildDatabase.getRootTargets(); - auto it = - std::find_if(rootTargets.begin(), rootTargets.end(), - [&fileName](std::shared_ptr linkUnitInfo) { - return linkUnitInfo->getOutput().filename() == fileName; - }); - assert(it != rootTargets.end()); - return it->get()->getOutput(); - } + fs::path get_10_c = getTestFilePath("get_10.c"); + fs::path get_20x_c = getTestFilePath("get_20x.c"); + fs::path shared_c = getTestFilePath("shared.c"); + fs::path get_val_main_c = getTestFilePath("get_val_main.c"); + fs::path get_val_main_2_c = getTestFilePath("get_val_main_2.c"); }; using namespace testUtils; -TEST_F(TargetsTest, Valid_Target_Test_1) { - { - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); - auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); - auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - fs::path ls = getTargetPathByName(*testGen.buildDatabase, "ls"); - testGen.setTargetPath(ls); +TEST_F(TargetsTest, Valid_Target_Test_ls) { + auto projectRequest = + createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "ls"); + auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); + auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); - ASSERT_TRUE(status.ok()) << status.error_message(); + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); - checkTestCasePredicates( + checkMinNumberOfTestsInFile(testGen, parse_c, 1); + checkTestCasePredicates( testGen.tests.at(parse_c).methods.begin().value().testCases, - std::vector({ [](const tests::Tests::MethodTestCase &testCase) { + std::vector({[](const tests::Tests::MethodTestCase &testCase) { std::string ret = testCase.returnValue.view->getEntryValue(nullptr); return ret == "\'l\'"; - } }), + }}), "parse"); - } - { - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); - auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); - auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - fs::path cat = getTargetPathByName(*testGen.buildDatabase, "cat"); - testGen.setTargetPath(cat); - - Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); - ASSERT_TRUE(status.ok()) << status.error_message(); - - checkTestCasePredicates( +} + +TEST_F(TargetsTest, Valid_Target_Test_cat) { + auto projectRequest = + createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "cat"); + auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); + auto testGen = FileTestGen(*request, writer.get(), TESTMODE); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, parse_c, 1); + checkTestCasePredicates( testGen.tests.at(parse_c).methods.begin().value().testCases, - std::vector({ [](const tests::Tests::MethodTestCase &testCase) { + std::vector({[](const tests::Tests::MethodTestCase &testCase) { std::string ret = testCase.returnValue.view->getEntryValue(nullptr); return ret == "\'c\'"; - } }), + }}), "parse"); - } - { - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); - auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); - auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - fs::path dummy = getTargetPathByName(*testGen.buildDatabase, "dummy"); - testGen.setTargetPath(dummy); - - Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); - ASSERT_FALSE(status.ok()); - - int numberOfTests = testUtils::getNumberOfTests(testGen.tests); - EXPECT_EQ(0, numberOfTests); - } - { - auto projectRequest = - createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); - auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); - auto testGen = FileTestGen(*request, writer.get(), TESTMODE); - fs::path autoTarget = GrpcUtils::UTBOT_AUTO_TARGET_PATH; - testGen.setTargetPath(autoTarget); - - Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); - ASSERT_TRUE(status.ok()); - checkTestCasePredicates( - testGen.tests.at(parse_c).methods.begin().value().testCases, - std::vector({[](const tests::Tests::MethodTestCase &testCase) { - std::string ret = testCase.returnValue.view->getEntryValue(nullptr); - return ret == "\'c\'" || ret == "\'l\'"; - }}), - "parse"); - } } + +TEST_F(TargetsTest, Valid_Target_Test_dummy) { + auto projectRequest = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths, "dummy"); + auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); + auto testGen = FileTestGen(*request, writer.get(), TESTMODE); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_FALSE(status.ok()); + + int numberOfTests = testUtils::getNumberOfTests(testGen.tests); + EXPECT_EQ(0, numberOfTests); +} + +TEST_F(TargetsTest, Valid_Target_Test_parse) { + auto projectRequest = createProjectRequest(projectName, suitePath, buildDirRelativePath, srcPaths); + auto request = GrpcUtils::createFileRequest(std::move(projectRequest), parse_c); + auto testGen = FileTestGen(*request, writer.get(), TESTMODE); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + checkMinNumberOfTestsInFile(testGen, parse_c, 1); + checkTestCasePredicates( + testGen.tests.at(parse_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + std::string ret = testCase.returnValue.view->getEntryValue(nullptr); + return ret == "\'c\'" || ret == "\'l\'"; + }}), + "parse"); +} + +TEST_F(TargetsTest, Valid_Target_Test_get_10) { + std::unique_ptr projectRequest = createProjectRequest( + projectName, suitePath, buildDirRelativePath, srcPaths, "get_10", false, false, 15); + + auto testGen = ProjectTestGen(*projectRequest.get(), writer.get(), TESTMODE, true); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, get_10_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_10_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return testCase.returnValue.view->getEntryValue(nullptr) == "10"; + }}), + "get_any_val"); + + checkMinNumberOfTestsInFile(testGen, shared_c, 1); + checkTestCasePredicates( + testGen.tests.at(shared_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (10 + std::stoi(testCase.paramValues.front().view->getEntryValue(nullptr))); + }}), + "add_val"); + + checkMinNumberOfTestsInFile(testGen, get_val_main_c, 2); + checkTestCasePredicates( + testGen.tests.at(get_val_main_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (10 + 0); + }}), + "get_res"); + + checkNumberOfTestsInFile(testGen, parse_c, 0); + checkNumberOfTestsInFile(testGen, get_20x_c, 0); + checkNumberOfTestsInFile(testGen, get_val_main_2_c, 0); +} + +TEST_F(TargetsTest, Valid_Target_Test_get_20) { + std::unique_ptr projectRequest = createProjectRequest( + projectName, suitePath, buildDirRelativePath, srcPaths, "get_20", false, false, 15); + + auto testGen = ProjectTestGen(*projectRequest.get(), writer.get(), TESTMODE, true); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, get_20x_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_20x_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return testCase.returnValue.view->getEntryValue(nullptr) == "20"; + }}), + "get_any_val"); + + checkMinNumberOfTestsInFile(testGen, shared_c, 1); + checkTestCasePredicates( + testGen.tests.at(shared_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (20 + std::stoi(testCase.paramValues.front().view->getEntryValue(nullptr))); + }}), + "add_val"); + + checkMinNumberOfTestsInFile(testGen, get_val_main_c, 2); + checkTestCasePredicates( + testGen.tests.at(get_val_main_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (20 + 0); + }}), + "get_res"); + + checkNumberOfTestsInFile(testGen, parse_c, 0); + checkNumberOfTestsInFile(testGen, get_10_c, 0); + checkNumberOfTestsInFile(testGen, get_val_main_2_c, 0); +} + +TEST_F(TargetsTest, Valid_Target_Test_get_10_2) { + std::unique_ptr projectRequest = createProjectRequest( + projectName, suitePath, buildDirRelativePath, srcPaths, "get_10_2", false, false, 15); + + auto testGen = ProjectTestGen(*projectRequest.get(), writer.get(), TESTMODE, true); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, get_10_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_10_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return testCase.returnValue.view->getEntryValue(nullptr) == "10"; + }}), + "get_any_val"); + + checkMinNumberOfTestsInFile(testGen, shared_c, 1); + checkTestCasePredicates( + testGen.tests.at(shared_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (10 + std::stoi(testCase.paramValues.front().view->getEntryValue(nullptr))); + }}), + "add_val"); + + checkMinNumberOfTestsInFile(testGen, get_val_main_2_c, 2); + checkTestCasePredicates( + testGen.tests.at(get_val_main_2_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (10 + 5); + }}), + "get_res"); + + checkNumberOfTestsInFile(testGen, parse_c, 0); + checkNumberOfTestsInFile(testGen, get_20x_c, 0); + checkNumberOfTestsInFile(testGen, get_val_main_c, 0); +} + +TEST_F(TargetsTest, Valid_Target_Test_libshared) { + std::unique_ptr projectRequest = createProjectRequest( + projectName, suitePath, buildDirRelativePath, srcPaths, "libshared_get.so", false, false, 15); + + auto testGen = ProjectTestGen(*projectRequest.get(), writer.get(), TESTMODE, true); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, get_20x_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_20x_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return testCase.returnValue.view->getEntryValue(nullptr) == "20"; + }}), + "get_any_val"); + + checkMinNumberOfTestsInFile(testGen, shared_c, 1); + checkTestCasePredicates( + testGen.tests.at(shared_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (20 + std::stoi(testCase.paramValues.front().view->getEntryValue(nullptr))); + }}), + "add_val"); + + checkMinNumberOfTestsInFile(testGen, get_val_main_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_val_main_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (20 + 0); + }}), + "get_res"); + + checkNumberOfTestsInFile(testGen, parse_c, 0); + checkNumberOfTestsInFile(testGen, get_10_c, 0); + checkNumberOfTestsInFile(testGen, get_val_main_2_c, 0); +} + +TEST_F(TargetsTest, Valid_Target_Test_get_libstatic) { + std::unique_ptr projectRequest = createProjectRequest( + projectName, suitePath, buildDirRelativePath, srcPaths, "libstatic_get.a", false, false, 15); + + auto testGen = ProjectTestGen(*projectRequest.get(), writer.get(), TESTMODE, true); + + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + + checkMinNumberOfTestsInFile(testGen, get_20x_c, 1); + checkTestCasePredicates( + testGen.tests.at(get_20x_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return testCase.returnValue.view->getEntryValue(nullptr) == "200"; + }}), + "get_any_val"); + + checkMinNumberOfTestsInFile(testGen, shared_c, 1); + checkTestCasePredicates( + testGen.tests.at(shared_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (200 + std::stoi(testCase.paramValues.front().view->getEntryValue(nullptr))); + }}), + "add_val"); + + checkMinNumberOfTestsInFile(testGen, get_val_main_c, 2); + checkTestCasePredicates( + testGen.tests.at(get_val_main_c).methods.begin().value().testCases, + std::vector({[](const tests::Tests::MethodTestCase &testCase) { + return std::stoi(testCase.returnValue.view->getEntryValue(nullptr)) == + (200 + 0); + }}), + "get_res"); + + checkNumberOfTestsInFile(testGen, parse_c, 0); + checkNumberOfTestsInFile(testGen, get_10_c, 0); + checkNumberOfTestsInFile(testGen, get_val_main_2_c, 0); +} + diff --git a/server/test/framework/TestUtils.cpp b/server/test/framework/TestUtils.cpp index 43acde556..c9965e7a8 100644 --- a/server/test/framework/TestUtils.cpp +++ b/server/test/framework/TestUtils.cpp @@ -76,10 +76,10 @@ namespace testUtils { CoverageLines actualLinesCovered; CoverageLines actualLinesUncovered; for (const auto &[filePath, fileCoverage] : coverageMap) { - for(const auto &sourceLine : fileCoverage.fullCoverageLines) { + for (const auto &sourceLine : fileCoverage.fullCoverageLines) { actualLinesCovered[filePath].insert(sourceLine.line); } - for(const auto &sourceLine : fileCoverage.noCoverageLines) { + for (const auto &sourceLine : fileCoverage.noCoverageLines) { actualLinesUncovered[filePath].insert(sourceLine.line); } } @@ -141,14 +141,14 @@ namespace testUtils { } const auto status = testResultMap.at(filename).at(testname).status(); EXPECT_TRUE((testsgen::TestStatus::TEST_PASSED == status) || - (testsgen::TestStatus::TEST_DEATH == status)); + (testsgen::TestStatus::TEST_DEATH == status)); } } void checkStatusesCount(const Coverage::TestResultMap &testResultMap, const std::vector &tests, - const StatusCountMap &expectedStatusCountMap) { + const StatusCountMap &expectedStatusCountMap) { StatusCountMap actualStatusCountMap; for (auto const &[filename, suitename, testname] : tests) { if (suitename == tests::Tests::ERROR_SUITE_NAME) { @@ -157,14 +157,14 @@ namespace testUtils { const auto status = testResultMap.at(filename).at(testname).status(); actualStatusCountMap[status]++; } - for (const auto& [status, count] : actualStatusCountMap) { + for (const auto &[status, count] : actualStatusCountMap) { ASSERT_GE(count, expectedStatusCountMap.at(status)); } } - int getNumberOfTests(const tests::TestsMap &tests) { + size_t getNumberOfTests(const tests::TestsMap &tests) { auto testFilePaths = CollectionUtils::getKeys(tests); - int testsCounter = 0; + size_t testsCounter = 0; for (const auto &[filename, cases] : tests) { for (const auto &[_, methodDescription] : cases.methods) { int size = methodDescription.testCases.size(); @@ -174,28 +174,57 @@ namespace testUtils { return testsCounter; } - void checkMinNumberOfTests(const tests::TestsMap &tests, int minNumber) { - int testsCounter = getNumberOfTests(tests); + size_t getNumberOfTestsForFile(const BaseTestGen &testGen, const std::string &fileName) { + auto tests = testGen.tests.find(fileName); + size_t testsCounter = 0; + if (tests != testGen.tests.end()) { + for (const auto &[methodName, methodDescription]: tests.value().methods) { + testsCounter += methodDescription.testCases.size(); + } + } + return testsCounter; + } + + void checkMinNumberOfTests(const tests::TestsMap &tests, size_t minNumber) { + size_t testsCounter = getNumberOfTests(tests); EXPECT_LE(minNumber, testsCounter) << "Number of test cases is too small"; } void checkMinNumberOfTests(const std::vector &testCases, - int minNumber) { + size_t minNumber) { EXPECT_LE(minNumber, testCases.size()) << "Number of test cases is too small"; } + void checkNumberOfTestsInFile(const BaseTestGen &testGen, std::string fileName, size_t number) { + size_t testCounter = getNumberOfTestsForFile(testGen, fileName); + EXPECT_EQ(number, testCounter) + << "Number of test cases in \"" << fileName << "\" not equal to predicate"; + } + + void + checkMinNumberOfTestsInFile(const BaseTestGen &testGen, std::string fileName, size_t number) { + size_t testCounter = getNumberOfTestsForFile(testGen, fileName); + EXPECT_LE(number, testCounter) + << "Number of test cases in \"" << fileName << "\" not equal to predicate"; + } + std::unique_ptr createProjectRequest(const std::string &projectName, const fs::path &projectPath, const std::string &buildDirRelativePath, const std::vector &srcPaths, + const std::string &targetOrSourcePath, bool useStubs, bool verbose, int kleeTimeout) { auto projectContext = GrpcUtils::createProjectContext( - projectName, projectPath, projectPath / "tests", buildDirRelativePath); - auto settingsContext = GrpcUtils::createSettingsContext(true, verbose, kleeTimeout, 0, false, useStubs); + projectName, projectPath, projectPath / "tests", buildDirRelativePath); + auto settingsContext = + GrpcUtils::createSettingsContext(true, verbose, kleeTimeout, 0, false, useStubs); + return GrpcUtils::createProjectRequest(std::move(projectContext), - std::move(settingsContext), srcPaths); + std::move(settingsContext), + srcPaths, + targetOrSourcePath); } std::unique_ptr createFileRequest(const std::string &projectName, @@ -203,34 +232,43 @@ namespace testUtils { const std::string &buildDirRelativePath, const std::vector &srcPaths, const fs::path &filePath, + const std::string &targetOrSourcePath, bool useStubs, - bool verbose) { + bool verbose, + int kleeTimeout) { auto projectRequest = createProjectRequest(projectName, projectPath, buildDirRelativePath, - srcPaths, useStubs, verbose); + srcPaths, targetOrSourcePath, useStubs, verbose, kleeTimeout); return GrpcUtils::createFileRequest(std::move(projectRequest), filePath); } - std::unique_ptr createLineRequest(const std::string &projectName, const fs::path &projectPath, - const std::string &buildDirRelativePath, - const std::vector &srcPaths, const fs::path &filePath, - int line, bool useStubs, - bool verbose, int kleeTimeout) { - auto projectRequest = createProjectRequest(projectName, projectPath, buildDirRelativePath, - srcPaths, useStubs, verbose, kleeTimeout); - auto lineInfo = GrpcUtils::createSourceInfo(filePath, line); - return GrpcUtils::createLineRequest(std::move(projectRequest), std::move(lineInfo)); - } - - std::unique_ptr createClassRequest(const std::string &projectName, + std::unique_ptr createLineRequest(const std::string &projectName, const fs::path &projectPath, const std::string &buildDirRelativePath, const std::vector &srcPaths, const fs::path &filePath, int line, + const std::string &targetOrSourcePath, + bool useStubs, bool verbose, int kleeTimeout) { + auto projectRequest = createProjectRequest(projectName, projectPath, buildDirRelativePath, + srcPaths, targetOrSourcePath, useStubs, verbose, kleeTimeout); + auto lineInfo = GrpcUtils::createSourceInfo(filePath, line); + return GrpcUtils::createLineRequest(std::move(projectRequest), std::move(lineInfo)); + } + + std::unique_ptr createClassRequest(const std::string &projectName, + const fs::path &projectPath, + const std::string &buildDirRelativePath, + const std::vector &srcPaths, + const fs::path &filePath, + int line, + const std::string &targetOrSourcePath, + bool useStubs, + bool verbose, + int kleeTimeout) { auto lineRequest = createLineRequest(projectName, projectPath, buildDirRelativePath, - srcPaths, filePath, line, false, verbose, kleeTimeout); + srcPaths, filePath, line, targetOrSourcePath, useStubs, verbose, kleeTimeout); return GrpcUtils::createClassRequest(std::move(lineRequest)); } @@ -360,11 +398,6 @@ namespace testUtils { return argv; } - void setTargetForFirstSource(ProjectTestGen &testGen) { - fs::path sourcePath = *testGen.testingMethodsSourcePaths.begin(); - testGen.setTargetForSource(sourcePath); - } - static void checkStatsCSV(const fs::path &statsPath, const std::vector &header, const std::vector &containedFiles) { EXPECT_TRUE(fs::exists(statsPath)); diff --git a/server/test/framework/TestUtils.h b/server/test/framework/TestUtils.h index 3f9079b48..e037a1ffd 100644 --- a/server/test/framework/TestUtils.h +++ b/server/test/framework/TestUtils.h @@ -3,7 +3,6 @@ #include "gtest/gtest.h" -#include "ProjectTarget.h" #include "Server.h" #include "Tests.h" #include "coverage/Coverage.h" @@ -47,12 +46,19 @@ namespace testUtils { const std::vector &tests, const StatusCountMap &expectedStatusCountMap); - int getNumberOfTests(const tests::TestsMap &tests); + size_t getNumberOfTests(const tests::TestsMap &tests); - void checkMinNumberOfTests(const tests::TestsMap &tests, int minNumber); + size_t getNumberOfTestsForFile(const BaseTestGen &testGen, const std::string &fileName); + + void checkMinNumberOfTests(const tests::TestsMap &tests, size_t minNumber); void checkMinNumberOfTests(const std::vector &testCases, - int minNumber); + size_t minNumber); + + void checkNumberOfTestsInFile(const BaseTestGen &testGen, std::string fileName, size_t number); + + void + checkMinNumberOfTestsInFile(const BaseTestGen &testGen, std::string fileName, size_t number); std::unique_ptr createSnippetRequest(const std::string &projectName, const fs::path &projectPath, @@ -62,6 +68,7 @@ namespace testUtils { const fs::path &projectPath, const std::string &buildDirRelativePath, const std::vector &srcPaths, + const std::string &targetOrSourcePath = GrpcUtils::UTBOT_AUTO_TARGET_PATH, bool useStubs = false, bool verbose = true, int kleeTimeout = 60); @@ -71,23 +78,32 @@ namespace testUtils { const std::string &buildDirRelativePath, const std::vector &srcPaths, const fs::path &filePath, + const std::string &targetOrSourcePath = GrpcUtils::UTBOT_AUTO_TARGET_PATH, bool useStubs = false, - bool verbose = true); + bool verbose = true, + int kleeTimeout = 60); - std::unique_ptr createLineRequest(const std::string &projectName, const fs::path &projectPath, + std::unique_ptr createLineRequest(const std::string &projectName, + const fs::path &projectPath, const std::string &buildDirRelativePath, - const std::vector &srcPaths, const fs::path &filePath, - int line, bool useStubs, - bool verbose, int kleeTimeout); + const std::vector &srcPaths, + const fs::path &filePath, + int line, + const std::string &targetOrSourcePath = GrpcUtils::UTBOT_AUTO_TARGET_PATH, + bool useStubs = false, + bool verbose = true, + int kleeTimeout = 60); std::unique_ptr createClassRequest(const std::string &projectName, - const fs::path &projectPath, - const std::string &buildDirRelativePath, - const std::vector &srcPaths, - const fs::path &filePath, - int line, - bool verbose = true, - int kleeTimeout = 60); + const fs::path &projectPath, + const std::string &buildDirRelativePath, + const std::vector &srcPaths, + const fs::path &filePath, + int line, + const std::string &targetOrSourcePath = GrpcUtils::UTBOT_AUTO_TARGET_PATH, + bool useStubs = false, + bool verbose = true, + int kleeTimeout = 60); std::unique_ptr createCoverageAndResultsRequest(const std::string &projectName, @@ -107,7 +123,8 @@ namespace testUtils { void tryExecGetBuildCommands( const fs::path &path, CompilationUtils::CompilerName compilerName = CompilationUtils::CompilerName::CLANG, - BuildCommandsTool buildCommandsTool = CMAKE_BUILD_COMMANDS_TOOL, bool build = true); + BuildCommandsTool buildCommandsTool = CMAKE_BUILD_COMMANDS_TOOL, + bool build = true); fs::path getRelativeTestSuitePath(const std::string &suiteName); @@ -115,9 +132,7 @@ namespace testUtils { std::string unexpectedFileMessage(const fs::path &filePath); - std::vector createArgvVector(const std::vector &args); - - void setTargetForFirstSource(ProjectTestGen &testGen); + std::vector createArgvVector(const std::vector &args); void checkGenerationStatsCSV(const fs::path &statsPath, const std::vector &containedFiles); diff --git a/server/test/framework/main.cpp b/server/test/framework/main.cpp index c3f99d813..6e900c9e0 100644 --- a/server/test/framework/main.cpp +++ b/server/test/framework/main.cpp @@ -1,5 +1,6 @@ #include "TestUtils.h" #include "utils/CLIUtils.h" +#include "printers/DefaultMakefilePrinter.h" #include "loguru.h" @@ -51,7 +52,9 @@ int main(int argc, char **argv) { for (auto const &subproject : { "executable", "static_library", "shared_library", "timeout" }) { for (auto const &compiler : { clang, gcc }) { - testUtils::tryExecGetBuildCommands(testUtils::getRelativeTestSuitePath("run") / subproject, compiler); + testUtils::tryExecGetBuildCommands( + testUtils::getRelativeTestSuitePath(printer::DefaultMakefilePrinter::TARGET_RUN) / subproject, + compiler); } } diff --git a/server/test/suites/library-project/CMakeLists.txt b/server/test/suites/library-project/CMakeLists.txt index b5f2d1e55..d6e37191f 100644 --- a/server/test/suites/library-project/CMakeLists.txt +++ b/server/test/suites/library-project/CMakeLists.txt @@ -12,4 +12,4 @@ set(CMAKE_EXPORT_LINK_COMMANDS ON) add_compile_options(-O2) add_subdirectory(lib) -add_subdirectory(src) \ No newline at end of file +add_subdirectory(src) diff --git a/server/test/suites/library-project/lib/CMakeLists.txt b/server/test/suites/library-project/lib/CMakeLists.txt index 4091512fe..f9081eeb8 100644 --- a/server/test/suites/library-project/lib/CMakeLists.txt +++ b/server/test/suites/library-project/lib/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(lib) target_include_directories(lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) file(GLOB_RECURSE ALL_SOURCES "*.c" "*.h") -target_sources(lib PRIVATE ${ALL_SOURCES}) \ No newline at end of file +target_sources(lib PUBLIC ${ALL_SOURCES}) diff --git a/server/test/suites/stub/lib/calc/CMakeLists.txt b/server/test/suites/stub/lib/calc/CMakeLists.txt index 31068f05e..f7f4c7fca 100644 --- a/server/test/suites/stub/lib/calc/CMakeLists.txt +++ b/server/test/suites/stub/lib/calc/CMakeLists.txt @@ -1,3 +1,3 @@ add_library(calc) target_include_directories(calc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_sources(calc PRIVATE sum.c mult.c PUBLIC sum.h mult.h) \ No newline at end of file +target_sources(calc PRIVATE sum.c mult.c PUBLIC sum.h mult.h) diff --git a/server/test/suites/targets/CMakeLists.txt b/server/test/suites/targets/CMakeLists.txt index 1e5832741..b2efbe687 100644 --- a/server/test/suites/targets/CMakeLists.txt +++ b/server/test/suites/targets/CMakeLists.txt @@ -13,7 +13,15 @@ add_library(parse STATIC parse.c) add_executable(ls ls.c) add_executable(cat cat.c) add_executable(dummy dummy.c) - target_link_libraries(ls parse) target_link_libraries(cat parse) -target_link_libraries(dummy parse) \ No newline at end of file +target_link_libraries(dummy parse) + +add_executable(get_10 get_10.c shared.c get_val_main.c) +add_executable(get_20 get_20x.c shared.c get_val_main.c) +add_executable(get_10_2 get_10.c shared.c get_val_main_2.c) + +add_library(shared_get SHARED get_20x.c shared.c get_val_main.c) + +add_library(static_get STATIC get_20x.c shared.c get_val_main.c) +target_compile_definitions(static_get PRIVATE TESTDEF) diff --git a/server/test/suites/targets/get_10.c b/server/test/suites/targets/get_10.c new file mode 100644 index 000000000..08b90a009 --- /dev/null +++ b/server/test/suites/targets/get_10.c @@ -0,0 +1,3 @@ +int get_any_val() { + return 10; +} diff --git a/server/test/suites/targets/get_20x.c b/server/test/suites/targets/get_20x.c new file mode 100644 index 000000000..5862d972f --- /dev/null +++ b/server/test/suites/targets/get_20x.c @@ -0,0 +1,7 @@ +int get_any_val() { +#ifndef TESTDEF + return 20; +#else + return 200; +#endif +} diff --git a/server/test/suites/targets/get_any_val.h b/server/test/suites/targets/get_any_val.h new file mode 100644 index 000000000..b90abfb65 --- /dev/null +++ b/server/test/suites/targets/get_any_val.h @@ -0,0 +1,7 @@ +#ifndef UNITTESTBOT_GET_ANY_VAL_H +#define UNITTESTBOT_GET_ANY_VAL_H + + +int get_any_val(); + +#endif // UNITTESTBOT_GET_ANY_VAL_H diff --git a/server/test/suites/targets/get_val_main.c b/server/test/suites/targets/get_val_main.c new file mode 100644 index 000000000..1bae6ae46 --- /dev/null +++ b/server/test/suites/targets/get_val_main.c @@ -0,0 +1,9 @@ +#include "shared.h" + +int get_res() { + return add_val(0); +} + +int main(void) { + return 0; +} diff --git a/server/test/suites/targets/get_val_main_2.c b/server/test/suites/targets/get_val_main_2.c new file mode 100644 index 000000000..138702d16 --- /dev/null +++ b/server/test/suites/targets/get_val_main_2.c @@ -0,0 +1,9 @@ +#include "shared.h" + +int get_res() { + return add_val(5); +} + +int main(void) { + return 0; +} diff --git a/server/test/suites/targets/shared.c b/server/test/suites/targets/shared.c new file mode 100644 index 000000000..50513f50f --- /dev/null +++ b/server/test/suites/targets/shared.c @@ -0,0 +1,5 @@ +#include "get_any_val.h" + +int add_val(int a) { + return a + get_any_val(); +} diff --git a/server/test/suites/targets/shared.h b/server/test/suites/targets/shared.h new file mode 100644 index 000000000..e60d28dbc --- /dev/null +++ b/server/test/suites/targets/shared.h @@ -0,0 +1,6 @@ +#ifndef UNITTESTBOT_SHARED_H +#define UNITTESTBOT_SHARED_H + +int add_val(int a); + +#endif // UNITTESTBOT_SHARED_H