11#include < utils/stats/TestsExecutionStats.h>
2+ #include < utils/KleeUtils.h>
23#include " TestRunner.h"
34
45#include " printers/DefaultMakefilePrinter.h"
@@ -18,33 +19,37 @@ TestRunner::TestRunner(utbot::ProjectContext projectContext,
1819 std::string testFilePath,
1920 std::string testSuite,
2021 std::string testName,
22+ std::string functionName,
2123 ProgressWriter const *progressWriter)
22- : projectContext(std::move(projectContext)),
23- testFilePath(testFilePath.empty() ? std::nullopt : std::make_optional(testFilePath)),
24- testSuite(std::move(testSuite)), testName(std::move(testName)),
25- progressWriter(progressWriter) {
24+ : projectContext(std::move(projectContext)),
25+ testFilePath(testFilePath.empty() ? std::nullopt : std::make_optional(testFilePath)),
26+ testSuite(std::move(testSuite)), testName(std::move(testName)), functionName(std::move(functionName )),
27+ progressWriter(progressWriter) {
2628}
2729
2830TestRunner::TestRunner (
29- const testsgen::CoverageAndResultsRequest *coverageAndResultsRequest,
30- grpc::ServerWriter<testsgen::CoverageAndResultsResponse> *coverageAndResultsWriter,
31- std::string testFilename,
32- std::string testSuite,
33- std::string testName)
34- : TestRunner(utbot::ProjectContext(coverageAndResultsRequest->projectcontext ()),
35- std::move(testFilename),
36- std::move(testSuite),
37- std::move(testName),
38- &writer) {
31+ const testsgen::CoverageAndResultsRequest *coverageAndResultsRequest,
32+ grpc::ServerWriter<testsgen::CoverageAndResultsResponse> *coverageAndResultsWriter,
33+ std::string testFilename,
34+ std::string testSuite,
35+ std::string testName,
36+ std::string functionName)
37+ : TestRunner(utbot::ProjectContext(coverageAndResultsRequest->projectcontext ()),
38+ std::move(testFilename),
39+ std::move(testSuite),
40+ std::move(testName),
41+ std::move(functionName),
42+ &writer) {
3943 writer = ServerCoverageAndResultsWriter (coverageAndResultsWriter);
4044}
4145
4246std::vector<UnitTest> TestRunner::getTestsFromMakefile (const fs::path &makefile,
43- const fs::path &testFilePath) {
47+ const fs::path &testFilePath,
48+ const std::string &filter) {
4449 auto cmdGetAllTests = MakefileUtils::MakefileCommand (projectContext, makefile,
4550 printer::DefaultMakefilePrinter::TARGET_RUN,
46- " --gtest_list_tests" , {" GTEST_FILTER=* " });
47- auto [out, status, _] = cmdGetAllTests.run (projectContext.getBuildDirAbsPath (), false );
51+ " --gtest_list_tests" , {" GTEST_FILTER=" + filter });
52+ auto [out, status, _] = cmdGetAllTests.run (projectContext.getBuildDirAbsPath (), false );
4853 if (status != 0 ) {
4954 auto [err, _, logFilePath] = cmdGetAllTests.run (projectContext.getBuildDirAbsPath (), true );
5055 progressWriter->writeProgress (StringUtils::stringFormat (" command %s failed.\n "
@@ -55,12 +60,14 @@ std::vector<UnitTest> TestRunner::getTestsFromMakefile(const fs::path &makefile,
5560 throw ExecutionProcessException (err, logFilePath.value ());
5661 }
5762 if (out.empty ()) {
58- LOG_S (WARNING) << " Running gtest with flag --gtest_list_tests returns empty output. Does file contain main function?" ;
63+ LOG_S (WARNING)
64+ << " Running gtest with flag --gtest_list_tests returns empty output. Does file contain main function?" ;
5965 return {};
6066 }
6167 std::vector<std::string> gtestListTestsOutput = StringUtils::split (out, ' \n ' );
62- gtestListTestsOutput.erase (gtestListTestsOutput.begin ()); // GTEST prints "Running main() from /opt/gtest/googletest/src/gtest_main.cc"
63- for (std::string &s : gtestListTestsOutput) {
68+ gtestListTestsOutput.erase (
69+ gtestListTestsOutput.begin ()); // GTEST prints "Running main() from /opt/gtest/googletest/src/gtest_main.cc"
70+ for (std::string &s: gtestListTestsOutput) {
6471 StringUtils::trim (s);
6572 }
6673 std::string testSuite;
@@ -84,50 +91,65 @@ std::vector<UnitTest> TestRunner::getTestsToLaunch() {
8491 if (fs::exists (projectContext.getTestDirAbsPath ())) {
8592 FileSystemUtils::RecursiveDirectoryIterator directoryIterator (projectContext.getTestDirAbsPath ());
8693 ExecUtils::doWorkWithProgress (
87- directoryIterator, progressWriter, " Building tests" ,
88- [this , &result](fs::directory_entry const &directoryEntry) {
89- if (!directoryEntry.is_regular_file ()) {
90- return ;
91- }
92- const auto &testFilePath = directoryEntry.path ();
93- if (testFilePath.extension () == Paths::CXX_EXTENSION &&
94- StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::TEST_SUFFIX)) {
95- fs::path sourcePath = Paths::testPathToSourcePath (projectContext, testFilePath);
96- fs::path makefile =
97- Paths::getMakefilePathFromSourceFilePath (projectContext, sourcePath);
98- if (fs::exists (makefile)) {
99- try {
100- auto tests = getTestsFromMakefile (makefile, testFilePath);
101- CollectionUtils::extend (result, tests);
102- } catch (ExecutionProcessException const &e) {
103- exceptions.push_back (e);
94+ directoryIterator, progressWriter, " Building tests" ,
95+ [this , &result](fs::directory_entry const &directoryEntry) {
96+ if (!directoryEntry.is_regular_file ()) {
97+ return ;
98+ }
99+ const auto &testFilePath = directoryEntry.path ();
100+ if (testFilePath.extension () == Paths::CXX_EXTENSION &&
101+ StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::TEST_SUFFIX)) {
102+ fs::path sourcePath = Paths::testPathToSourcePath (projectContext, testFilePath);
103+ fs::path makefile =
104+ Paths::getMakefilePathFromSourceFilePath (projectContext, sourcePath);
105+ if (fs::exists (makefile)) {
106+ try {
107+ auto tests = getTestsFromMakefile (makefile, testFilePath);
108+ CollectionUtils::extend (result, tests);
109+ } catch (ExecutionProcessException const &e) {
110+ exceptions.push_back (e);
111+ }
112+ } else {
113+ LOG_S (WARNING) << StringUtils::stringFormat (
114+ " Makefile for %s not found, candidate: %s" , testFilePath, makefile);
104115 }
105116 } else {
106- LOG_S (WARNING) << StringUtils::stringFormat (
107- " Makefile for %s not found, candidate: %s" , testFilePath, makefile);
108- }
109- } else {
110- if (!StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::TEST_SUFFIX) &&
111- !StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::STUB_SUFFIX) &&
112- !StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::MAKE_WRAPPER_SUFFIX) &&
113- !StringUtils::endsWith (testFilePath.c_str (), Paths::MAKEFILE_EXTENSION)) {
114- LOG_S (WARNING) << " Found extra file in test directory: " << testFilePath;
117+ if (!StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::TEST_SUFFIX) &&
118+ !StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::STUB_SUFFIX) &&
119+ !StringUtils::endsWith (testFilePath.stem ().c_str (), Paths::MAKE_WRAPPER_SUFFIX) &&
120+ !StringUtils::endsWith (testFilePath.c_str (), Paths::MAKEFILE_EXTENSION)) {
121+ LOG_S (WARNING) << " Found extra file in test directory: " << testFilePath;
122+ }
115123 }
116- }
117- });
124+ });
118125 } else {
119126 LOG_S (WARNING) << " Test folder doesn't exist: " << projectContext.getTestDirAbsPath ();
120127 }
121128 return result;
122129 }
123- if (testName.empty ()) {
130+
131+ if (testName.empty () && functionName.empty ()) {
124132 // for file
125133 fs::path sourcePath = Paths::testPathToSourcePath (projectContext, testFilePath.value ());
126134 fs::path makefile = Paths::getMakefilePathFromSourceFilePath (projectContext, sourcePath);
127135 return getTestsFromMakefile (makefile, testFilePath.value ());
128136 }
137+
138+ if (testName.empty ()) {
139+ // for function
140+ fs::path sourcePath = Paths::testPathToSourcePath (projectContext, testFilePath.value ());
141+ fs::path makefile = Paths::getMakefilePathFromSourceFilePath (projectContext, sourcePath);
142+
143+
144+ std::string renamedMethodDescription = KleeUtils::getRenamedOperator (functionName);
145+ StringUtils::replaceColon (renamedMethodDescription);
146+
147+ std::string filter = " *." + renamedMethodDescription + Paths::TEST_SUFFIX + " *" ;
148+
149+ return getTestsFromMakefile (makefile, testFilePath.value (), filter);
150+ }
129151 // for single test
130- return { UnitTest{ testFilePath.value (), testSuite, testName } };
152+ return {UnitTest{testFilePath.value (), testSuite, testName} };
131153}
132154
133155grpc::Status TestRunner::runTests (bool withCoverage, const std::optional<std::chrono::seconds> &testTimeout) {
@@ -136,22 +158,22 @@ grpc::Status TestRunner::runTests(bool withCoverage, const std::optional<std::ch
136158
137159 const auto buildRunCommands = coverageTool->getBuildRunCommands (testsToLaunch, withCoverage);
138160 ExecUtils::doWorkWithProgress (buildRunCommands, progressWriter, " Running tests" ,
139- [this , testTimeout] (BuildRunCommand const &buildRunCommand) {
140- auto const &[unitTest, buildCommand, runCommand] =
141- buildRunCommand;
142- try {
143- auto status = runTest (buildRunCommand, testTimeout);
144- testResultMap[unitTest.testFilePath ][unitTest.testname ] = status;
145- ExecUtils::throwIfCancelled ();
146- } catch (ExecutionProcessException const &e) {
147- testsgen::TestResultObject testRes;
148- testRes.set_testfilepath (unitTest.testFilePath );
149- testRes.set_testname (unitTest.testname );
150- testRes.set_status (testsgen::TEST_FAILED);
151- testResultMap[unitTest.testFilePath ][unitTest.testname ] = testRes;
152- exceptions.emplace_back (e);
153- }
154- });
161+ [this , testTimeout](BuildRunCommand const &buildRunCommand) {
162+ auto const &[unitTest, buildCommand, runCommand] =
163+ buildRunCommand;
164+ try {
165+ auto status = runTest (buildRunCommand, testTimeout);
166+ testResultMap[unitTest.testFilePath ][unitTest.testname ] = status;
167+ ExecUtils::throwIfCancelled ();
168+ } catch (ExecutionProcessException const &e) {
169+ testsgen::TestResultObject testRes;
170+ testRes.set_testfilepath (unitTest.testFilePath );
171+ testRes.set_testname (unitTest.testname );
172+ testRes.set_status (testsgen::TEST_FAILED);
173+ testResultMap[unitTest.testFilePath ][unitTest.testname ] = testRes;
174+ exceptions.emplace_back (e);
175+ }
176+ });
155177 LOG_S (DEBUG) << " All run commands were executed" ;
156178 return Status::OK;
157179}
@@ -169,14 +191,14 @@ void TestRunner::init(bool withCoverage) {
169191 }
170192}
171193
172- bool TestRunner::buildTest (const utbot::ProjectContext& projectContext, const fs::path& sourcePath) {
194+ bool TestRunner::buildTest (const utbot::ProjectContext & projectContext, const fs::path & sourcePath) {
173195 ExecUtils::throwIfCancelled ();
174196 fs::path makefile = Paths::getMakefilePathFromSourceFilePath (projectContext, sourcePath);
175197 if (fs::exists (makefile)) {
176198 auto command = MakefileUtils::MakefileCommand (projectContext, makefile,
177199 printer::DefaultMakefilePrinter::TARGET_BUILD, " " , {});
178200 LOG_S (DEBUG) << " Try compile tests for: " << sourcePath.string ();
179- auto [out, status, logFilePath] = command.run (projectContext.getBuildDirAbsPath (), true );
201+ auto [out, status, logFilePath] = command.run (projectContext.getBuildDirAbsPath (), true );
180202 if (status != 0 ) {
181203 return false ;
182204 }
@@ -185,18 +207,18 @@ bool TestRunner::buildTest(const utbot::ProjectContext& projectContext, const fs
185207 return false ;
186208}
187209
188- size_t TestRunner::buildTests (const utbot::ProjectContext& projectContext, const tests::TestsMap& tests) {
210+ size_t TestRunner::buildTests (const utbot::ProjectContext & projectContext, const tests::TestsMap & tests) {
189211 size_t fail_count = 0 ;
190212 for (const auto &[file, _]: tests) {
191- if (!TestRunner::buildTest (projectContext, file)) {
213+ if (!TestRunner::buildTest (projectContext, file)) {
192214 fail_count++;
193215 }
194216 }
195217 return fail_count;
196218}
197219
198220testsgen::TestResultObject TestRunner::runTest (const BuildRunCommand &command,
199- const std::optional <std::chrono::seconds> &testTimeout) {
221+ const std::optional<std::chrono::seconds> &testTimeout) {
200222 fs::remove (Paths::getGTestResultsJsonPath (projectContext));
201223 auto res = command.runCommand .run (projectContext.getBuildDirAbsPath (), true , true , testTimeout);
202224 GTestLogger::log (res.output );
0 commit comments