11#include " KleeRunner.h"
22
33#include " Paths.h"
4+ #include " TimeExecStatistics.h"
45#include " exceptions/FileNotPresentedInArtifactException.h"
56#include " exceptions/FileNotPresentedInCommandsException.h"
67#include " tasks/RunKleeTask.h"
78#include " utils/ExecUtils.h"
89#include " utils/FileSystemUtils.h"
910#include " utils/KleeUtils.h"
1011#include " utils/LogUtils.h"
11- #include " TimeExecStatistics.h"
1212
1313#include " loguru.h"
1414
15+ #include < fstream>
1516#include < utility>
1617
1718using namespace tests ;
@@ -92,13 +93,6 @@ void KleeRunner::runKlee(const std::vector<tests::TestMethod> &testMethods,
9293 std::move (writeFunctor));
9394}
9495
95- fs::path KleeRunner::getKleeMethodOutFile (const TestMethod &method) {
96- fs::path kleeOutDir = Paths::getKleeOutDir (projectTmpPath);
97- fs::path relative =
98- Paths::removeExtension (fs::relative (method.sourceFilePath , projectContext.projectPath ));
99- return kleeOutDir / relative / (" klee_out_" + method.methodName );
100- }
101-
10296namespace {
10397 void clearUnusedData (const fs::path &kleeDir) {
10498 fs::remove (kleeDir / " assembly.ll" );
@@ -119,56 +113,10 @@ namespace {
119113 }
120114}
121115
122- void KleeRunner::processBatchWithoutInteractive (MethodKtests &ktestChunk,
123- const TestMethod &testMethod,
124- Tests &tests) {
125- if (!tests.isFilePresentedInArtifact ) {
126- return ;
127- }
128- if (testMethod.sourceFilePath != tests.sourceFilePath ) {
129- std::string message = StringUtils::stringFormat (
130- " While generating tests for source file: %s tried to generate tests for method %s "
131- " from another source file: %s. This can cause invalid generation.\n " ,
132- tests.sourceFilePath , testMethod.methodName , testMethod.sourceFilePath );
133- LOG_S (WARNING) << message;
134- }
135-
136- std::string entryPoint = KleeUtils::entryPointFunction (tests, testMethod.methodName , true );
137- std::string entryPointFlag = StringUtils::stringFormat (" --entry-point=%s" , entryPoint);
138- auto kleeOut = getKleeMethodOutFile (testMethod);
139- fs::create_directories (kleeOut.parent_path ());
140- std::string outputDir = " --output-dir=" + kleeOut.string ();
141- std::vector<std::string> argvData = { " klee" ,
142- entryPointFlag,
143- " --libc=klee" ,
144- " --posix-runtime" ,
145- " --fp-runtime" ,
146- " --only-output-states-covering-new" ,
147- " --allocate-determ" ,
148- " --external-calls=all" ,
149- " --timer-interval=1000ms" ,
150- " --bcov-check-interval=6s" ,
151- " -istats-write-interval=5s" ,
152- " --disable-verify" ,
153- " --check-div-zero=false" ,
154- " --check-overshift=false" ,
155- " --skip-not-lazy-and-symbolic-pointers" ,
156- outputDir };
157- if (settingsContext.useDeterministicSearcher ) {
158- argvData.emplace_back (" --search=dfs" );
159- }
160- argvData.push_back (testMethod.bitcodeFilePath );
161- argvData.emplace_back (" --sym-stdin" );
162- argvData.emplace_back (std::to_string (types::Type::symStdinSize));
163- std::vector<char *> cargv, cenvp;
164- std::vector<std::string> tmp;
165- ExecUtils::toCArgumentsPtr (argvData, tmp, cargv, cenvp, false );
166- LOG_S (DEBUG) << " Klee command :: " + StringUtils::joinWith (argvData, " " );
167- MEASURE_FUNCTION_EXECUTION_TIME
168- RunKleeTask task (cargv.size (), cargv.data (), settingsContext.timeoutPerFunction );
169- ExecUtils::ExecutionResult result __attribute__ ((unused)) = task.run ();
170- ExecUtils::throwIfCancelled ();
171-
116+ static void processMethod (MethodKtests &ktestChunk,
117+ tests::Tests &tests,
118+ const fs::path &kleeOut,
119+ const tests::TestMethod &method) {
172120 if (fs::exists (kleeOut)) {
173121 clearUnusedData (kleeOut);
174122 bool hasTimeout = false ;
@@ -198,32 +146,90 @@ void KleeRunner::processBatchWithoutInteractive(MethodKtests &ktestChunk,
198146 return UTBotKTestObject{ kTestObject };
199147 });
200148
201- ktestChunk[testMethod ].emplace_back (objects, status);
149+ ktestChunk[method ].emplace_back (objects, status);
202150 }
203151 }
204152 }
205153 if (hasTimeout) {
206154 std::string message = StringUtils::stringFormat (
207155 " Some tests for function '%s' were skipped, as execution of function is "
208156 " out of timeout." ,
209- testMethod .methodName );
157+ method .methodName );
210158 tests.commentBlocks .emplace_back (std::move (message));
211159 }
212160 if (hasError) {
213161 std::string message = StringUtils::stringFormat (
214162 " Some tests for function '%s' were skipped, as execution of function leads "
215163 " KLEE to the internal error. See console log for more details." ,
216- testMethod .methodName );
164+ method .methodName );
217165 tests.commentBlocks .emplace_back (std::move (message));
218166 }
167+
219168 writeKleeStats (kleeOut);
169+
170+ if (!CollectionUtils::containsKey (ktestChunk, method) || ktestChunk.at (method).empty ()) {
171+ tests.commentBlocks .emplace_back (StringUtils::stringFormat (
172+ " Tests for %s were not generated. Maybe the function is too complex." ,
173+ method.methodName ));
174+ }
220175 }
176+ }
221177
222- if (!CollectionUtils::containsKey (ktestChunk, testMethod) ||
223- ktestChunk.at (testMethod).empty ()) {
224- tests.commentBlocks .emplace_back (StringUtils::stringFormat (
225- " Tests for %s were not generated. Maybe the function is too complex." ,
226- testMethod.methodName ));
178+ void KleeRunner::processBatchWithoutInteractive (MethodKtests &ktestChunk,
179+ const TestMethod &testMethod,
180+ Tests &tests) {
181+ if (!tests.isFilePresentedInArtifact ) {
182+ return ;
183+ }
184+ if (testMethod.sourceFilePath != tests.sourceFilePath ) {
185+ std::string message = StringUtils::stringFormat (
186+ " While generating tests for source file: %s tried to generate tests for method %s "
187+ " from another source file: %s. This can cause invalid generation.\n " ,
188+ tests.sourceFilePath , testMethod.methodName , testMethod.sourceFilePath );
189+ LOG_S (WARNING) << message;
190+ }
191+
192+ std::string entryPoint = KleeUtils::entryPointFunction (tests, testMethod.methodName , true );
193+ std::string entryPointFlag = StringUtils::stringFormat (" --entry-point=%s" , entryPoint);
194+ auto kleeOut = Paths::kleeOutDirForEntrypoints (projectContext, projectTmpPath, testMethod.sourceFilePath ,
195+ testMethod.methodName );
196+ fs::create_directories (kleeOut.parent_path ());
197+ std::string outputDir = " --output-dir=" + kleeOut.string ();
198+ std::vector<std::string> argvData = { " klee" ,
199+ entryPointFlag,
200+ " --libc=klee" ,
201+ " --posix-runtime" ,
202+ " --fp-runtime" ,
203+ " --only-output-states-covering-new" ,
204+ " --allocate-determ" ,
205+ " --external-calls=all" ,
206+ " --timer-interval=1000ms" ,
207+ " --bcov-check-interval=6s" ,
208+ " -istats-write-interval=5s" ,
209+ " --disable-verify" ,
210+ " --check-div-zero=false" ,
211+ " --check-overshift=false" ,
212+ " --skip-not-lazy-and-symbolic-pointers" ,
213+ outputDir };
214+ if (settingsContext.useDeterministicSearcher ) {
215+ argvData.emplace_back (" --search=dfs" );
216+ }
217+ argvData.push_back (testMethod.bitcodeFilePath );
218+ argvData.emplace_back (" --sym-stdin" );
219+ argvData.emplace_back (std::to_string (types::Type::symStdinSize));
220+
221+ {
222+ std::vector<char *> cargv, cenvp;
223+ std::vector<std::string> tmp;
224+ ExecUtils::toCArgumentsPtr (argvData, tmp, cargv, cenvp, false );
225+ LOG_S (DEBUG) << " Klee command :: " + StringUtils::joinWith (argvData, " " );
226+ MEASURE_FUNCTION_EXECUTION_TIME
227+
228+ RunKleeTask task (cargv.size (), cargv.data (), settingsContext.timeoutPerFunction );
229+ ExecUtils::ExecutionResult result __attribute__ ((unused)) = task.run ();
230+ ExecUtils::throwIfCancelled ();
231+
232+ processMethod (ktestChunk, tests, kleeOut, testMethod);
227233 }
228234}
229235
@@ -238,7 +244,7 @@ void KleeRunner::processBatchWithInteractive(const std::vector<tests::TestMethod
238244 if (method.sourceFilePath != tests.sourceFilePath ) {
239245 std::string message = StringUtils::stringFormat (
240246 " While generating tests for source file: %s tried to generate tests for method %s "
241- " from another source file: %s. This can cause invalid generation.\n " ,
247+ " from another source file: %s. This can cause invalid generation.\n " ,
242248 tests.sourceFilePath , method.methodName , method.sourceFilePath );
243249 LOG_S (WARNING) << message;
244250 }
@@ -247,7 +253,7 @@ void KleeRunner::processBatchWithInteractive(const std::vector<tests::TestMethod
247253 TestMethod testMethod = testMethods[0 ];
248254 std::string entryPoint = KleeUtils::entryPointFunction (tests, testMethod.methodName , true );
249255 std::string entryPointFlag = StringUtils::stringFormat (" --entry-point=%s" , entryPoint);
250- auto kleeOut = getKleeMethodOutFile (testMethod );
256+ auto kleeOut = Paths::kleeOutDirForEntrypoints (projectContext, projectTmpPath, tests. sourceFilePath );
251257 fs::create_directories (kleeOut.parent_path ());
252258
253259 fs::path entrypoints = kleeOut.parent_path () / " entrypoints.txt" ;
@@ -287,86 +293,31 @@ void KleeRunner::processBatchWithInteractive(const std::vector<tests::TestMethod
287293 argvData.push_back (testMethod.bitcodeFilePath );
288294 argvData.emplace_back (" --sym-stdin" );
289295 argvData.emplace_back (std::to_string (types::Type::symStdinSize));
290- std::vector<char *> cargv, cenvp;
291- std::vector<std::string> tmp;
292- ExecUtils::toCArgumentsPtr (argvData, tmp, cargv, cenvp, false );
293-
294- LOG_S (DEBUG) << " Klee command :: " + StringUtils::joinWith (argvData, " " );
295- MEASURE_FUNCTION_EXECUTION_TIME
296- if (settingsContext.timeoutPerFunction .has_value ()) {
297- RunKleeTask task (cargv.size (), cargv.data (), settingsContext.timeoutPerFunction .value () * testMethods.size ());
298- ExecUtils::ExecutionResult result __attribute__ ((unused)) = task.run ();
299- } else {
300- RunKleeTask task (cargv.size (), cargv.data (), settingsContext.timeoutPerFunction );
301- ExecUtils::ExecutionResult result __attribute__ ((unused)) = task.run ();
302- }
303-
304- ExecUtils::throwIfCancelled ();
305296
306- for (const auto &method : testMethods) {
307- std::string kleeMethodName = KleeUtils::entryPointFunction (tests, method.methodName , true );
308- fs::path newKleeOut = kleeOut / kleeMethodName;
309- MethodKtests ktestChunk;
310- if (fs::exists (newKleeOut)) {
311- clearUnusedData (newKleeOut);
312- bool hasTimeout = false ;
313- bool hasError = false ;
314- for (auto const &entry : fs::directory_iterator (newKleeOut)) {
315- auto const &path = entry.path ();
316- if (Paths::isKtestJson (path)) {
317- if (Paths::hasEarly (path)) {
318- hasTimeout = true ;
319- } else if (Paths::hasInternalError (path)) {
320- hasError = true ;
321- } else {
322- std::unique_ptr<TestCase, decltype (&TestCase_free)> ktestData{
323- TC_fromFile (path.c_str ()), TestCase_free
324- };
325- if (ktestData == nullptr ) {
326- LOG_S (WARNING) << " Unable to open .ktestjson file" ;
327- continue ;
328- }
329- UTBotKTest::Status status = Paths::hasError (path)
330- ? UTBotKTest::Status::FAILED
331- : UTBotKTest::Status::SUCCESS;
332- std::vector<ConcretizedObject> kTestObjects (
333- ktestData->objects , ktestData->objects + ktestData->n_objects );
297+ {
298+ std::vector<char *> cargv, cenvp;
299+ std::vector<std::string> tmp;
300+ ExecUtils::toCArgumentsPtr (argvData, tmp, cargv, cenvp, false );
334301
335- std::vector<UTBotKTestObject> objects = CollectionUtils::transform (
336- kTestObjects , [](const ConcretizedObject &kTestObject ) {
337- return UTBotKTestObject{ kTestObject };
338- });
302+ LOG_S (DEBUG) << " Klee command :: " + StringUtils::joinWith (argvData, " " );
303+ MEASURE_FUNCTION_EXECUTION_TIME
339304
340- ktestChunk[method].emplace_back (objects, status);
341- }
342- }
343- }
344- if (hasTimeout) {
345- std::string message = StringUtils::stringFormat (
346- " Some tests for function '%s' were skipped, as execution of function is "
347- " out of timeout." ,
348- method.methodName );
349- tests.commentBlocks .emplace_back (std::move (message));
350- }
351- if (hasError) {
352- std::string message = StringUtils::stringFormat (
353- " Some tests for function '%s' were skipped, as execution of function leads "
354- " KLEE to the internal error. See console log for more details." ,
355- method.methodName );
356- tests.commentBlocks .emplace_back (std::move (message));
357- }
358- }
305+ RunKleeTask task (cargv.size (),
306+ cargv.data (),
307+ settingsContext.timeoutPerFunction .has_value ()
308+ ? settingsContext.timeoutPerFunction .value () * testMethods.size ()
309+ : settingsContext.timeoutPerFunction );
310+ ExecUtils::ExecutionResult result __attribute__ ((unused)) = task.run ();
359311
360- if (fs::exists (kleeOut)) {
361- writeKleeStats (kleeOut);
362- }
312+ ExecUtils::throwIfCancelled ();
363313
364- if (!CollectionUtils::containsKey (ktestChunk, method) ||
365- ktestChunk.at (method).empty ()) {
366- tests.commentBlocks .emplace_back (StringUtils::stringFormat (
367- " Tests for %s were not generated. Maybe the function is too complex." ,
368- method.methodName ));
314+ for (const auto &method : testMethods) {
315+ std::string kleeMethodName =
316+ KleeUtils::entryPointFunction (tests, method.methodName , true );
317+ fs::path newKleeOut = kleeOut / kleeMethodName;
318+ MethodKtests ktestChunk;
319+ processMethod (ktestChunk, tests, newKleeOut, method);
320+ ktests.push_back (ktestChunk);
369321 }
370- ktests.push_back (ktestChunk);
371322 }
372323}
0 commit comments