diff --git a/server/proto/testgen.proto b/server/proto/testgen.proto index e70d3f30..d030d656 100644 --- a/server/proto/testgen.proto +++ b/server/proto/testgen.proto @@ -183,6 +183,7 @@ message TestFilter { string testFilePath = 1; string testName = 2; string testSuite = 3; + string functionName = 4; } message CoverageAndResultsRequest { diff --git a/server/src/commands/Commands.cpp b/server/src/commands/Commands.cpp index ce9a398b..e40dd503 100644 --- a/server/src/commands/Commands.cpp +++ b/server/src/commands/Commands.cpp @@ -443,6 +443,7 @@ Commands::RunTestsCommands::RunTestsCommands(Commands::MainCommands &commands) { runCommand = commands.getRunTestsCommand(); runTestCommand = runCommand->add_subcommand("test", "Run specified test"); + runFunctionCommand = runCommand->add_subcommand("function", "Run specified function tests"); runFileCommand = runCommand->add_subcommand("file", "Run all tests in specified file"); runProjectCommand = runCommand->add_subcommand("project", "Run all tests for this project"); } @@ -459,10 +460,18 @@ CLI::App *Commands::RunTestsCommands::getRunTestCommand() { return runTestCommand; } +CLI::App *Commands::RunTestsCommands::getRunFunctionCommand() { + return runFunctionCommand; +} + bool Commands::RunTestsCommands::gotRunTestCommand() { return runCommand->got_subcommand(runTestCommand); } +bool Commands::RunTestsCommands::gotRunFunctionCommand() { + return runCommand->got_subcommand(runFunctionCommand); +} + bool Commands::RunTestsCommands::gotRunFileCommand() { return runCommand->got_subcommand(runFileCommand); } @@ -477,13 +486,23 @@ Commands::RunTestsCommandOptions::RunTestsCommandOptions(Commands::RunTestsComma commands.getRunTestCommand() ->add_option("--file-path", filePath, "Path to test file") ->required(); + commands.getRunTestCommand()->add_flag("--no-coverage", noCoverage, + "Flag that controls coverage generation."); + + + commands.getRunFunctionCommand() + ->add_option("--file-path", filePath, "Path to test file") + ->required(); + commands.getRunFunctionCommand()->add_option("--function-name", functionName, "Test name")->required(); + commands.getRunFunctionCommand()->add_flag("--no-coverage", noCoverage, + "Flag that controls coverage generation."); + commands.getRunFileCommand() ->add_option("--file-path", filePath, "Path to test file") ->required(); - commands.getRunTestCommand()->add_flag("--no-coverage", noCoverage, - "Flag that controls coverage generation."); commands.getRunFileCommand()->add_flag("--no-coverage", noCoverage, "Flag that controls coverage generation."); + commands.getRunProjectCommand()->add_flag("--no-coverage", noCoverage, "Flag that controls coverage generation."); } @@ -500,6 +519,10 @@ std::string Commands::RunTestsCommandOptions::getTestName() { return testName; } +std::string Commands::RunTestsCommandOptions::getFunctionName() { + return functionName; +} + bool Commands::RunTestsCommandOptions::withCoverage() const { return !noCoverage; } diff --git a/server/src/commands/Commands.h b/server/src/commands/Commands.h index fbe32124..ab8057ab 100644 --- a/server/src/commands/Commands.h +++ b/server/src/commands/Commands.h @@ -177,12 +177,16 @@ namespace Commands { CLI::App *getRunTestCommand(); + CLI::App *getRunFunctionCommand(); + CLI::App *getRunFileCommand(); CLI::App *getRunProjectCommand(); bool gotRunTestCommand(); + bool gotRunFunctionCommand(); + bool gotRunFileCommand(); bool gotRunProjectCommand(); @@ -191,6 +195,7 @@ namespace Commands { CLI::App *runCommand; CLI::App *runTestCommand; + CLI::App *runFunctionCommand; CLI::App *runFileCommand; CLI::App *runProjectCommand; }; @@ -204,12 +209,15 @@ namespace Commands { std::string getTestName(); + std::string getFunctionName(); + [[nodiscard]] bool withCoverage() const; private: fs::path filePath; std::string testSuite; std::string testName; + std::string functionName; bool noCoverage = false; }; diff --git a/server/src/coverage/CoverageAndResultsGenerator.cpp b/server/src/coverage/CoverageAndResultsGenerator.cpp index dda5c819..c5983089 100644 --- a/server/src/coverage/CoverageAndResultsGenerator.cpp +++ b/server/src/coverage/CoverageAndResultsGenerator.cpp @@ -18,6 +18,7 @@ CoverageAndResultsGenerator::CoverageAndResultsGenerator( coverageAndResultsRequest->testfilter().testfilepath(), coverageAndResultsRequest->testfilter().testsuite(), coverageAndResultsRequest->testfilter().testname(), + coverageAndResultsRequest->testfilter().functionname(), coverageAndResultsWriter), coverageAndResultsWriter(coverageAndResultsWriter) { } diff --git a/server/src/coverage/TestRunner.cpp b/server/src/coverage/TestRunner.cpp index bbe59af8..18cab6da 100644 --- a/server/src/coverage/TestRunner.cpp +++ b/server/src/coverage/TestRunner.cpp @@ -1,4 +1,5 @@ #include +#include #include "TestRunner.h" #include "printers/DefaultMakefilePrinter.h" @@ -18,33 +19,37 @@ TestRunner::TestRunner(utbot::ProjectContext projectContext, std::string testFilePath, std::string testSuite, std::string testName, + std::string functionName, ProgressWriter const *progressWriter) - : projectContext(std::move(projectContext)), - testFilePath(testFilePath.empty() ? std::nullopt : std::make_optional(testFilePath)), - testSuite(std::move(testSuite)), testName(std::move(testName)), - progressWriter(progressWriter) { + : projectContext(std::move(projectContext)), + testFilePath(testFilePath.empty() ? std::nullopt : std::make_optional(testFilePath)), + testSuite(std::move(testSuite)), testName(std::move(testName)), functionName(std::move(functionName)), + progressWriter(progressWriter) { } TestRunner::TestRunner( - const testsgen::CoverageAndResultsRequest *coverageAndResultsRequest, - grpc::ServerWriter *coverageAndResultsWriter, - std::string testFilename, - std::string testSuite, - std::string testName) - : TestRunner(utbot::ProjectContext(coverageAndResultsRequest->projectcontext()), - std::move(testFilename), - std::move(testSuite), - std::move(testName), - &writer) { + const testsgen::CoverageAndResultsRequest *coverageAndResultsRequest, + grpc::ServerWriter *coverageAndResultsWriter, + std::string testFilename, + std::string testSuite, + std::string testName, + std::string functionName) + : TestRunner(utbot::ProjectContext(coverageAndResultsRequest->projectcontext()), + std::move(testFilename), + std::move(testSuite), + std::move(testName), + std::move(functionName), + &writer) { writer = ServerCoverageAndResultsWriter(coverageAndResultsWriter); } std::vector TestRunner::getTestsFromMakefile(const fs::path &makefile, - const fs::path &testFilePath) { + const fs::path &testFilePath, + const std::string &filter) { auto cmdGetAllTests = MakefileUtils::MakefileCommand(projectContext, makefile, printer::DefaultMakefilePrinter::TARGET_RUN, - "--gtest_list_tests", {"GTEST_FILTER=*"}); - auto[out, status, _] = cmdGetAllTests.run(projectContext.getBuildDirAbsPath(), false); + "--gtest_list_tests", {"GTEST_FILTER=" + filter}); + auto [out, status, _] = cmdGetAllTests.run(projectContext.getBuildDirAbsPath(), false); if (status != 0) { auto [err, _, logFilePath] = cmdGetAllTests.run(projectContext.getBuildDirAbsPath(), true); progressWriter->writeProgress(StringUtils::stringFormat("command %s failed.\n" @@ -55,12 +60,14 @@ std::vector TestRunner::getTestsFromMakefile(const fs::path &makefile, throw ExecutionProcessException(err, logFilePath.value()); } if (out.empty()) { - LOG_S(WARNING) << "Running gtest with flag --gtest_list_tests returns empty output. Does file contain main function?"; + LOG_S(WARNING) + << "Running gtest with flag --gtest_list_tests returns empty output. Does file contain main function?"; return {}; } std::vector gtestListTestsOutput = StringUtils::split(out, '\n'); - gtestListTestsOutput.erase(gtestListTestsOutput.begin()); //GTEST prints "Running main() from /opt/gtest/googletest/src/gtest_main.cc" - for (std::string &s : gtestListTestsOutput) { + gtestListTestsOutput.erase( + gtestListTestsOutput.begin()); //GTEST prints "Running main() from /opt/gtest/googletest/src/gtest_main.cc" + for (std::string &s: gtestListTestsOutput) { StringUtils::trim(s); } std::string testSuite; @@ -84,50 +91,65 @@ std::vector TestRunner::getTestsToLaunch() { if (fs::exists(projectContext.getTestDirAbsPath())) { FileSystemUtils::RecursiveDirectoryIterator directoryIterator(projectContext.getTestDirAbsPath()); ExecUtils::doWorkWithProgress( - directoryIterator, progressWriter, "Building tests", - [this, &result](fs::directory_entry const &directoryEntry) { - if (!directoryEntry.is_regular_file()) { - return; - } - const auto &testFilePath = directoryEntry.path(); - if (testFilePath.extension() == Paths::CXX_EXTENSION && - StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX)) { - fs::path sourcePath = Paths::testPathToSourcePath(projectContext, testFilePath); - fs::path makefile = - Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); - if (fs::exists(makefile)) { - try { - auto tests = getTestsFromMakefile(makefile, testFilePath); - CollectionUtils::extend(result, tests); - } catch (ExecutionProcessException const &e) { - exceptions.push_back(e); + directoryIterator, progressWriter, "Building tests", + [this, &result](fs::directory_entry const &directoryEntry) { + if (!directoryEntry.is_regular_file()) { + return; + } + const auto &testFilePath = directoryEntry.path(); + if (testFilePath.extension() == Paths::CXX_EXTENSION && + StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX)) { + fs::path sourcePath = Paths::testPathToSourcePath(projectContext, testFilePath); + fs::path makefile = + Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); + if (fs::exists(makefile)) { + try { + auto tests = getTestsFromMakefile(makefile, testFilePath); + CollectionUtils::extend(result, tests); + } catch (ExecutionProcessException const &e) { + exceptions.push_back(e); + } + } else { + LOG_S(WARNING) << StringUtils::stringFormat( + "Makefile for %s not found, candidate: %s", testFilePath, makefile); } } else { - LOG_S(WARNING) << StringUtils::stringFormat( - "Makefile for %s not found, candidate: %s", testFilePath, makefile); - } - } else { - if (!StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX) && - !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::STUB_SUFFIX) && - !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::MAKE_WRAPPER_SUFFIX) && - !StringUtils::endsWith(testFilePath.c_str(), Paths::MAKEFILE_EXTENSION)) { - LOG_S(WARNING) << "Found extra file in test directory: " << testFilePath; + if (!StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX) && + !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::STUB_SUFFIX) && + !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::MAKE_WRAPPER_SUFFIX) && + !StringUtils::endsWith(testFilePath.c_str(), Paths::MAKEFILE_EXTENSION)) { + LOG_S(WARNING) << "Found extra file in test directory: " << testFilePath; + } } - } - }); + }); } else { LOG_S(WARNING) << "Test folder doesn't exist: " << projectContext.getTestDirAbsPath(); } return result; } - if (testName.empty()) { + + if (testName.empty() && functionName.empty()) { //for file fs::path sourcePath = Paths::testPathToSourcePath(projectContext, testFilePath.value()); fs::path makefile = Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); return getTestsFromMakefile(makefile, testFilePath.value()); } + + if (testName.empty()) { + //for function + fs::path sourcePath = Paths::testPathToSourcePath(projectContext, testFilePath.value()); + fs::path makefile = Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); + + + std::string renamedMethodDescription = KleeUtils::getRenamedOperator(functionName); + StringUtils::replaceColon(renamedMethodDescription); + + std::string filter = "*." + renamedMethodDescription + Paths::TEST_SUFFIX + "*"; + + return getTestsFromMakefile(makefile, testFilePath.value(), filter); + } //for single test - return { UnitTest{ testFilePath.value(), testSuite, testName } }; + return {UnitTest{testFilePath.value(), testSuite, testName}}; } grpc::Status TestRunner::runTests(bool withCoverage, const std::optional &testTimeout) { @@ -136,22 +158,22 @@ grpc::Status TestRunner::runTests(bool withCoverage, const std::optionalgetBuildRunCommands(testsToLaunch, withCoverage); ExecUtils::doWorkWithProgress(buildRunCommands, progressWriter, "Running tests", - [this, testTimeout] (BuildRunCommand const &buildRunCommand) { - auto const &[unitTest, buildCommand, runCommand] = - buildRunCommand; - try { - auto status = runTest(buildRunCommand, testTimeout); - testResultMap[unitTest.testFilePath][unitTest.testname] = status; - ExecUtils::throwIfCancelled(); - } catch (ExecutionProcessException const &e) { - testsgen::TestResultObject testRes; - testRes.set_testfilepath(unitTest.testFilePath); - testRes.set_testname(unitTest.testname); - testRes.set_status(testsgen::TEST_FAILED); - testResultMap[unitTest.testFilePath][unitTest.testname] = testRes; - exceptions.emplace_back(e); - } - }); + [this, testTimeout](BuildRunCommand const &buildRunCommand) { + auto const &[unitTest, buildCommand, runCommand] = + buildRunCommand; + try { + auto status = runTest(buildRunCommand, testTimeout); + testResultMap[unitTest.testFilePath][unitTest.testname] = status; + ExecUtils::throwIfCancelled(); + } catch (ExecutionProcessException const &e) { + testsgen::TestResultObject testRes; + testRes.set_testfilepath(unitTest.testFilePath); + testRes.set_testname(unitTest.testname); + testRes.set_status(testsgen::TEST_FAILED); + testResultMap[unitTest.testFilePath][unitTest.testname] = testRes; + exceptions.emplace_back(e); + } + }); LOG_S(DEBUG) << "All run commands were executed"; return Status::OK; } @@ -169,14 +191,14 @@ void TestRunner::init(bool withCoverage) { } } -bool TestRunner::buildTest(const utbot::ProjectContext& projectContext, const fs::path& sourcePath) { +bool TestRunner::buildTest(const utbot::ProjectContext &projectContext, const fs::path &sourcePath) { ExecUtils::throwIfCancelled(); fs::path makefile = Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); if (fs::exists(makefile)) { 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.getBuildDirAbsPath(), true); + auto [out, status, logFilePath] = command.run(projectContext.getBuildDirAbsPath(), true); if (status != 0) { return false; } @@ -185,10 +207,10 @@ bool TestRunner::buildTest(const utbot::ProjectContext& projectContext, const fs return false; } -size_t TestRunner::buildTests(const utbot::ProjectContext& projectContext, const tests::TestsMap& tests) { +size_t TestRunner::buildTests(const utbot::ProjectContext &projectContext, const tests::TestsMap &tests) { size_t fail_count = 0; for (const auto &[file, _]: tests) { - if(!TestRunner::buildTest(projectContext, file)) { + if (!TestRunner::buildTest(projectContext, file)) { fail_count++; } } @@ -196,7 +218,7 @@ size_t TestRunner::buildTests(const utbot::ProjectContext& projectContext, const } testsgen::TestResultObject TestRunner::runTest(const BuildRunCommand &command, - const std::optional &testTimeout) { + const std::optional &testTimeout) { fs::remove(Paths::getGTestResultsJsonPath(projectContext)); auto res = command.runCommand.run(projectContext.getBuildDirAbsPath(), true, true, testTimeout); GTestLogger::log(res.output); diff --git a/server/src/coverage/TestRunner.h b/server/src/coverage/TestRunner.h index 88790540..a2b1c6e6 100644 --- a/server/src/coverage/TestRunner.h +++ b/server/src/coverage/TestRunner.h @@ -20,6 +20,7 @@ class TestRunner { const std::optional testFilePath; const std::string testSuite; const std::string testName; + const std::string functionName; ProgressWriter const *progressWriter; std::unique_ptr coverageTool{}; @@ -36,13 +37,15 @@ class TestRunner { std::string testFilePath, std::string testSuite, std::string testName, + std::string functionName, ProgressWriter const *progressWriter); TestRunner(const testsgen::CoverageAndResultsRequest *coverageAndResultsRequest, grpc::ServerWriter *coverageAndResultsWriter, std::string testFilename, std::string testSuite, - std::string testName); + std::string testName, + std::string functionName); void init(bool withCoverage); @@ -56,22 +59,23 @@ class TestRunner { /** * Try compile test for source file and return true if succeed, else false */ - static bool buildTest(const utbot::ProjectContext& projectContext, const fs::path& sourcePath); + static bool buildTest(const utbot::ProjectContext &projectContext, const fs::path &sourcePath); /** * Try compile tests for files in tests and return count of failed attempts */ - static size_t buildTests(const utbot::ProjectContext& projectContext, const tests::TestsMap& tests); + static size_t buildTests(const utbot::ProjectContext &projectContext, const tests::TestsMap &tests); private: std::vector getTestsFromMakefile(const fs::path &makefile, - const fs::path &testFilePath); + const fs::path &testFilePath, + const std::string &filter="*"); testsgen::TestResultObject runTest(const BuildRunCommand &command, const std::optional &testTimeout); - ServerCoverageAndResultsWriter writer{ nullptr }; + ServerCoverageAndResultsWriter writer{nullptr}; void cleanCoverage(); }; diff --git a/server/src/utils/CLIUtils.cpp b/server/src/utils/CLIUtils.cpp index 13577979..eeba4436 100644 --- a/server/src/utils/CLIUtils.cpp +++ b/server/src/utils/CLIUtils.cpp @@ -71,9 +71,9 @@ std::vector getSourcePaths(const ProjectContextOptionGroup &projectCon const std::string &sourcePathsString) { if (!sourcePathsString.empty()) { return CollectionUtils::transformTo>( - StringUtils::split(sourcePathsString, ','), [](std::string const &file) { - return Paths::normalizedTrimmed(fs::absolute(fs::path(file))); - }); + StringUtils::split(sourcePathsString, ','), [](std::string const &file) { + return Paths::normalizedTrimmed(fs::absolute(fs::path(file))); + }); } else if (!projectContextOptions.getProjectPath().empty()) { return FileSystemUtils::recursiveDirectories(projectContextOptions.getProjectPath()); } @@ -115,15 +115,15 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { if (app.got_subcommand(mainCommands.getGenerateCommand())) { auto sourcePaths = - getSourcePaths(projectGenerateContext, generateCommandsOptions.getSrcPaths()); + getSourcePaths(projectGenerateContext, generateCommandsOptions.getSrcPaths()); auto projectContext = createProjectContextByOptions(projectGenerateContext); auto settingsContext = createSettingsContextByOptions(settingsGenerateContext); if (generateCommands.gotSnippetCommand()) { fs::path filePath = - Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); + Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); auto snippetRequest = GrpcUtils::createSnippetRequest( - std::move(projectContext), std::move(settingsContext), filePath); + std::move(projectContext), std::move(settingsContext), filePath); createTestsAndWriteStatus(snippetRequest.get(), ctx.get()); return; @@ -131,7 +131,7 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { auto target = generateCommandsOptions.getTarget(); auto projectRequest = GrpcUtils::createProjectRequest( - std::move(projectContext), std::move(settingsContext), sourcePaths, target); + std::move(projectContext), std::move(settingsContext), sourcePaths, target); if (generateCommands.gotProjectCommand()) { createTestsAndWriteStatus(projectRequest.get(), @@ -139,25 +139,25 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { } else if (generateCommands.gotFolderCommand()) { fs::path folderPath = - Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFolderPath())); + Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFolderPath())); auto folderRequest = - GrpcUtils::createFolderRequest(std::move(projectRequest), folderPath); + GrpcUtils::createFolderRequest(std::move(projectRequest), folderPath); createTestsAndWriteStatus(folderRequest.get(), ctx.get()); } else if (generateCommands.gotFileCommand()) { fs::path filePath = - Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); + Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); auto fileRequest = GrpcUtils::createFileRequest(std::move(projectRequest), filePath); createTestsAndWriteStatus(fileRequest.get(), ctx.get()); } else if (generateCommands.gotLineCommand() || generateCommands.gotFunctionCommand() || generateCommands.gotPredicateCommand() || generateCommands.gotAssertionCommand() || generateCommands.gotClassCommand()) { fs::path filePath = - Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); + Paths::normalizedTrimmed(fs::absolute(generateCommandsOptions.getFilePath())); auto lineInfo = GrpcUtils::createSourceInfo( - filePath, static_cast(generateCommandsOptions.getLineNumber())); + filePath, static_cast(generateCommandsOptions.getLineNumber())); auto lineRequest = - GrpcUtils::createLineRequest(std::move(projectRequest), std::move(lineInfo)); + GrpcUtils::createLineRequest(std::move(projectRequest), std::move(lineInfo)); if (generateCommands.gotLineCommand()) { createTestsAndWriteStatus(lineRequest.get(), ctx.get()); @@ -170,19 +170,19 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { auto assertionRequest = GrpcUtils::createAssertionRequest(std::move(lineRequest)); createTestsAndWriteStatus( - assertionRequest.get(), ctx.get()); + assertionRequest.get(), ctx.get()); } else if (generateCommands.gotPredicateCommand()) { auto predicateInfo = - GrpcUtils::createPredicateInfo(generateCommandsOptions.getPredicate(), - generateCommandsOptions.getReturnValue(), - generateCommandsOptions.getValidationType()); + GrpcUtils::createPredicateInfo(generateCommandsOptions.getPredicate(), + generateCommandsOptions.getReturnValue(), + generateCommandsOptions.getValidationType()); auto predicateRequest = GrpcUtils::createPredicateRequest(std::move(lineRequest), std::move(predicateInfo)); createTestsAndWriteStatus( - predicateRequest.get(), ctx.get()); + predicateRequest.get(), ctx.get()); } else if (mainCommands.getGenerateCommand()->got_subcommand( - generateCommands.getClassCommand())) { + generateCommands.getClassCommand())) { auto classRequest = GrpcUtils::createClassRequest(std::move(lineRequest)); createTestsAndWriteStatus(classRequest.get(), ctx.get()); @@ -196,28 +196,36 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { auto settingsContext = createSettingsContextByOptions(settingsRunContext); if (runCommands.gotRunTestCommand()) { auto testFilter = GrpcUtils::createTestFilterForTest( - runTestCommandsOptions.getFilePath(), runTestCommandsOptions.getTestSuite(), - runTestCommandsOptions.getTestName()); + runTestCommandsOptions.getFilePath(), runTestCommandsOptions.getTestSuite(), + runTestCommandsOptions.getTestName()); auto coverageAndResultRequest = GrpcUtils::createCoverageAndResultRequest( - std::move(projectContext), std::move(testFilter)); + std::move(projectContext), std::move(testFilter)); GenerationUtils::generateCoverageAndResultsAndWriteStatus( - std::move(coverageAndResultRequest), std::move(settingsContext), - runTestCommandsOptions.withCoverage()); + std::move(coverageAndResultRequest), std::move(settingsContext), + runTestCommandsOptions.withCoverage()); + } else if (runCommands.gotRunFunctionCommand()) { + auto testFilter = GrpcUtils::createTestFilterForFunction( + runTestCommandsOptions.getFilePath(), runTestCommandsOptions.getFunctionName()); + auto coverageAndResultRequest = GrpcUtils::createCoverageAndResultRequest( + std::move(projectContext), std::move(testFilter)); + GenerationUtils::generateCoverageAndResultsAndWriteStatus( + std::move(coverageAndResultRequest), std::move(settingsContext), + runTestCommandsOptions.withCoverage()); } else if (runCommands.gotRunFileCommand()) { auto testFilter = - GrpcUtils::createTestFilterForFile(runTestCommandsOptions.getFilePath()); + GrpcUtils::createTestFilterForFile(runTestCommandsOptions.getFilePath()); auto coverageAndResultRequest = GrpcUtils::createCoverageAndResultRequest( - std::move(projectContext), std::move(testFilter)); + std::move(projectContext), std::move(testFilter)); GenerationUtils::generateCoverageAndResultsAndWriteStatus( - std::move(coverageAndResultRequest), std::move(settingsContext), - runTestCommandsOptions.withCoverage()); + std::move(coverageAndResultRequest), std::move(settingsContext), + runTestCommandsOptions.withCoverage()); } else if (runCommands.gotRunProjectCommand()) { auto testFilter = GrpcUtils::createTestFilterForProject(); auto coverageAndResultRequest = GrpcUtils::createCoverageAndResultRequest( - std::move(projectContext), std::move(testFilter)); + std::move(projectContext), std::move(testFilter)); GenerationUtils::generateCoverageAndResultsAndWriteStatus( - std::move(coverageAndResultRequest), std::move(settingsContext), - runTestCommandsOptions.withCoverage()); + std::move(coverageAndResultRequest), std::move(settingsContext), + runTestCommandsOptions.withCoverage()); } else { // intentionally left blank } @@ -225,21 +233,21 @@ void CLIUtils::parse(int argc, char **argv, CLI::App &app) { auto sourcePaths = getSourcePaths(projectAllContext, allCommandsOptions.getSrcPaths()); auto target = allCommandsOptions.getTarget(); auto projectRequest = GrpcUtils::createProjectRequest( - std::move(createProjectContextByOptions(projectAllContext)), - std::move(createSettingsContextByOptions(settingsAllContext)), sourcePaths, target); + std::move(createProjectContextByOptions(projectAllContext)), + std::move(createSettingsContextByOptions(settingsAllContext)), sourcePaths, target); auto [testGen, statusTests] = - createTestsByRequest(*projectRequest, ctx.get()); + createTestsByRequest(*projectRequest, ctx.get()); if (!statusTests.error_message().empty()) { LOG_S(ERROR) << statusTests.error_message(); return; } auto coverageAndResultsRequest = GrpcUtils::createCoverageAndResultRequest( - std::move(createProjectContextByOptions(projectAllContext)), - GrpcUtils::createTestFilterForProject()); + std::move(createProjectContextByOptions(projectAllContext)), + GrpcUtils::createTestFilterForProject()); auto [_, statusResults] = generateCoverageAndResults( - std::move(coverageAndResultsRequest), - std::move(createSettingsContextByOptions(settingsAllContext)), - allCommandsOptions.withCoverage()); + std::move(coverageAndResultsRequest), + std::move(createSettingsContextByOptions(settingsAllContext)), + allCommandsOptions.withCoverage()); if (!statusResults.error_message().empty()) { LOG_S(ERROR) << statusTests.error_message(); return; @@ -288,6 +296,7 @@ void CLIUtils::setOptPath(int argc, char **argv, const std::string &option, fs:: } } } + void CLIUtils::setupLogger(int argc, char **argv, bool threadView) { setStderrVerbosity(loguru::Verbosity_WARNING); loguru::g_preamble_uptime = false; diff --git a/server/src/utils/GrpcUtils.cpp b/server/src/utils/GrpcUtils.cpp index 16481434..967e81e6 100644 --- a/server/src/utils/GrpcUtils.cpp +++ b/server/src/utils/GrpcUtils.cpp @@ -150,6 +150,14 @@ namespace GrpcUtils { return testFilter; } + std::unique_ptr createTestFilterForFunction(const fs::path &testFilePath, + std::string functionName) { + auto testFilter = std::make_unique(); + testFilter->set_testfilepath(testFilePath); + testFilter->set_functionname(functionName); + return testFilter; + } + std::unique_ptr createTestFilterForTest(const fs::path &testFilePath, std::string testSuite, std::string testName) { diff --git a/server/src/utils/GrpcUtils.h b/server/src/utils/GrpcUtils.h index 87f6d307..29a39cf5 100644 --- a/server/src/utils/GrpcUtils.h +++ b/server/src/utils/GrpcUtils.h @@ -90,6 +90,9 @@ namespace GrpcUtils { std::unique_ptr createTestFilterForFile(const fs::path &testFilePath); + std::unique_ptr createTestFilterForFunction(const fs::path &testFilePath, + std::string functionName); + std::unique_ptr createTestFilterForTest(const fs::path &testFilePath, std::string testSuite, std::string testName); @@ -103,13 +106,14 @@ namespace GrpcUtils { testsgen::ProjectTarget createAutoTarget(); - template + template using has_projectrequest = decltype(std::declval().projectrequest()); - template + template using has_linerequest = decltype(std::declval().linerequest()); - template bool synchronizeCode(Request const &request) { + template + bool synchronizeCode(Request const &request) { if constexpr (std::is_same_v) { return true; } else if constexpr (std::is_same_v) {