Skip to content

Commit 4fe047f

Browse files
authored
Merge pull request #1 from olezhabobrov/sarifResult
First sarif push for getting realise
2 parents 780ae97 + 1c3e23d commit 4fe047f

File tree

14 files changed

+282
-7
lines changed

14 files changed

+282
-7
lines changed

.gitmodules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[submodule "klee"]
22
path = submodules/klee
3-
url = https://github.com/UnitTestBot/klee.git
3+
url = https://github.com/olezhabobrov/klee.git
4+
branch = sarif
45
[submodule "Bear"]
56
path = submodules/Bear
67
url = https://github.com/UnitTestBot/Bear.git

server/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ file(GLOB ALL_SOURCES
8181
"${PROJECT_SOURCE_DIR}/src/fetchers/*"
8282
"${PROJECT_SOURCE_DIR}/src/printers/*"
8383
"${PROJECT_SOURCE_DIR}/src/streams/*"
84+
"${PROJECT_SOURCE_DIR}/src/sarif/*"
8485
"${PROJECT_SOURCE_DIR}/src/streams/coverage/*"
8586
"${PROJECT_SOURCE_DIR}/src/streams/stubs/*"
8687
"${PROJECT_SOURCE_DIR}/src/streams/tests/*"
@@ -120,7 +121,7 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}")
120121

121122
find_package(run_klee REQUIRED)
122123

123-
add_library(UnitTestBotLib STATIC ${ALL_PROTO_GENERATED_SOURCES} ${ALL_SOURCES})
124+
add_library(UnitTestBotLib STATIC ${ALL_PROTO_GENERATED_SOURCES} ${ALL_SOURCES} src/sarif/ProjectSarif.cpp src/sarif/ProjectSarif.h)
124125
target_include_directories(UnitTestBotLib PUBLIC
125126
${CMAKE_CURRENT_SOURCE_DIR}/src
126127
resources

server/src/KleeGenerator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "utils/LogUtils.h"
1616
#include "utils/MakefileUtils.h"
1717
#include "utils/SanitizerUtils.h"
18+
#include "sarif/FileSarif.h"
1819

1920
#include "loguru.h"
2021

@@ -322,7 +323,6 @@ void KleeGenerator::parseKTestsToFinalCode(
322323
auto predicate =
323324
lineInfo ? lineInfo->predicateInfo : std::optional<LineInfo::PredicateInfo>{};
324325
testsPrinter.genCode(methodDescription, predicate, verbose);
325-
326326
}
327327

328328
printer::HeaderPrinter(Paths::getSourceLanguage(tests.sourceFilePath)).print(tests.testHeaderFilePath, tests.sourceFilePath,

server/src/KleeRunner.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "utils/FileSystemUtils.h"
1313
#include "utils/KleeUtils.h"
1414
#include "utils/LogUtils.h"
15+
#include "sarif/FileSarif.h"
1516

1617
#include "loguru.h"
1718

@@ -89,6 +90,18 @@ void KleeRunner::runKlee(const std::vector<tests::TestMethod> &testMethods,
8990

9091
testsWriter->writeTestsWithProgress(testsMap, "Running klee", projectContext.testDirPath,
9192
std::move(writeFunctor));
93+
for (auto it = testsMap.begin(); it != testsMap.end(); it++) {
94+
tests::Tests &tests = it.value();
95+
sarif::FileSarif fileSarif(tests);
96+
for (auto it = tests.methods.begin(); it != tests.methods.end(); it++) {
97+
Tests::MethodDescription &methodDescription = it.value();
98+
fileSarif.generateSarifForFunction(methodDescription, projectContext.projectPath);
99+
}
100+
fileSarif.writeSarifFile(projectContext.projectPath);
101+
}
102+
sarif::ProjectSarif projectSarif;
103+
projectSarif.joinSarifFiles(projectContext.projectPath);
104+
projectSarif.writeSarifFile(projectContext.projectPath);
92105
}
93106

94107
fs::path KleeRunner::getKleeMethodOutFile(const TestMethod &method) {
@@ -186,8 +199,14 @@ void KleeRunner::processBatch(MethodKtests &ktestChunk,
186199
kTestObjects, [](const ConcretizedObject &kTestObject) {
187200
return UTBotKTestObject{kTestObject};
188201
});
189-
190-
ktestChunk[testMethod].emplace_back(objects, status);
202+
fs::path tmp = path.filename();
203+
if (status == tests::UTBotKTest::Status::FAILED) {
204+
fs::path sarifOutput = path.parent_path() / fs::path(sarif::FileSarif::sarif_klee_prefix +
205+
path.filename_without_extension() + sarif::FileSarif::sarif_klee_extension);
206+
ktestChunk[testMethod].emplace_back(objects, status, sarifOutput);
207+
} else {
208+
ktestChunk[testMethod].emplace_back(objects, status);
209+
}
191210
}
192211
}
193212
}

server/src/Tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ void KTestObjectParser::parseTestCases(const UTBotKTestList &cases,
711711
swap(testCase.objects, testCaseDescription.objects);
712712
swap(testCase.fromAddressToName, testCaseDescription.fromAddressToName);
713713
swap(testCase.lazyReferences, testCaseDescription.lazyReferences);
714+
testCase.errorDescriptionInJson = case_.errorDescriptionInJson;
714715
if (filterByLineFlag) {
715716
auto view = testCaseDescription.kleePathFlagSymbolicValue.view;
716717
if (!view || view->getEntryValue() != "1") {

server/src/Tests.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,15 @@ namespace tests {
5454
};
5555
vector<UTBotKTestObject> objects;
5656
Status status;
57+
std::optional<fs::path> errorDescriptionInJson;
5758

5859
UTBotKTest(const std::vector<UTBotKTestObject> &objects, const Status &status) : objects(objects), status(status) {}
60+
UTBotKTest(const std::vector<UTBotKTestObject> &objects, const Status &status, fs::path errorJson) :
61+
objects(objects), status(status), errorDescriptionInJson(std::move(errorJson)) {
62+
if (!exists(errorDescriptionInJson.value())) {
63+
LOG_S(ERROR) << "Sarif file not found";
64+
}
65+
}
5966
};
6067
using UTBotKTestList = vector<UTBotKTest>;
6168

@@ -383,6 +390,7 @@ namespace tests {
383390
shared_ptr<AbstractValueView> returnValueView;
384391
std::optional<TestCaseParamValue> classPreValues;
385392
std::optional<TestCaseParamValue> classPostValues;
393+
std::optional<fs::path> errorDescriptionInJson;
386394

387395
bool isError() const;
388396
};

server/src/printers/TestsPrinter.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
#include "TestsPrinter.h"
66

77
#include "Paths.h"
8+
#include "sarif/FileSarif.h"
89
#include "utils/ArgumentsUtils.h"
910
#include "utils/Copyright.h"
11+
#include "utils/JsonUtils.h"
1012
#include "visitors/ParametrizedAssertsVisitor.h"
1113
#include "visitors/VerboseAssertsParamVisitor.h"
1214
#include "visitors/VerboseAssertsReturnValueVisitor.h"
1315
#include "visitors/VerboseParameterVisitor.h"
1416
#include "utils/KleeUtils.h"
1517

18+
19+
using json = nlohmann::json;
1620
using printer::TestsPrinter;
1721

1822
TestsPrinter::TestsPrinter(const types::TypesHandler *typesHandler, utbot::Language srcLanguage) : Printer(srcLanguage) , typesHandler(typesHandler) {
@@ -58,7 +62,47 @@ void TestsPrinter::joinToFinalCode(Tests &tests, const fs::path& generatedHeader
5862
tests.regressionMethodsNumber = printSuiteAndReturnMethodsCount(Tests::DEFAULT_SUITE_NAME, tests.methods);
5963
tests.errorMethodsNumber = printSuiteAndReturnMethodsCount(Tests::ERROR_SUITE_NAME, tests.methods);
6064
ss << RB();
61-
tests.code = ss.str();
65+
printFinalCodeAndAlterJson(tests);
66+
}
67+
68+
void TestsPrinter::printFinalCodeAndAlterJson(Tests &tests) {
69+
int line_count = 0;
70+
string line;
71+
while (getline(ss, line)) {
72+
if (line.rfind(sarif::FileSarif::prefix_for_json_path, 0) == 0) {
73+
fs::path json_path = line.substr(sarif::FileSarif::prefix_for_json_path.size());
74+
if (!exists(json_path)) {
75+
LOG_S(ERROR) << "Json from klee not found";
76+
continue;
77+
}
78+
json location = R"(
79+
{
80+
"location" : {
81+
"physicalLocation" : {
82+
"artifactLocation" : {
83+
"uri" : {}
84+
},
85+
"region" : {
86+
"startLine" : {}
87+
}
88+
}
89+
}
90+
}
91+
)"_json;
92+
location.at("location").at("physicalLocation").at("artifactLocation").at("uri") =
93+
tests.testSourceFilePath;
94+
location.at("location").at("physicalLocation").at("region").at("startLine") = line_count;
95+
json sarifResultFromFile = JsonUtils::getJsonFromFile(json_path);
96+
auto &arr = sarifResultFromFile.at("codeFlows").at(0).at("threadFlows").at(0).
97+
at("locations");
98+
arr.insert(arr.begin(), location);
99+
JsonUtils::writeJsonToFile(json_path, sarifResultFromFile);
100+
} else {
101+
tests.code.append(line);
102+
tests.code.append("\n");
103+
line_count++;
104+
}
105+
}
62106
}
63107

64108
std::uint32_t TestsPrinter::printSuiteAndReturnMethodsCount(const string &suiteName, const Tests::MethodsMap &methods) {
@@ -510,11 +554,19 @@ void TestsPrinter::parametrizedAsserts(const Tests::MethodDescription &methodDes
510554
const std::optional<LineInfo::PredicateInfo>& predicateInfo) {
511555
auto visitor = visitor::ParametrizedAssertsVisitor(typesHandler, this, predicateInfo, testCase.isError());
512556
visitor.visit(methodDescription, testCase);
557+
printJsonPathFromKlee(testCase);
513558
globalParamsAsserts(methodDescription, testCase);
514559
classAsserts(methodDescription, testCase);
515560
changeableParamsAsserts(methodDescription, testCase);
516561
}
517562

563+
void TestsPrinter::printJsonPathFromKlee(const Tests::MethodTestCase &testCase) {
564+
if (!testCase.errorDescriptionInJson) {
565+
return;
566+
}
567+
ss << sarif::FileSarif::prefix_for_json_path << testCase.errorDescriptionInJson.value().string() << NL;
568+
}
569+
518570
std::vector<string> TestsPrinter::methodParametersListParametrized(const Tests::MethodDescription &methodDescription,
519571
const Tests::MethodTestCase &testCase) {
520572
std::vector<string> args;

server/src/printers/TestsPrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ namespace printer {
107107
const Tests::MethodTestCase &testCase,
108108
const std::optional<LineInfo::PredicateInfo>& predicateInfo);
109109

110+
void printJsonPathFromKlee(const Tests::MethodTestCase &testCase);
111+
112+
void printFinalCodeAndAlterJson(Tests &tests);
113+
110114
static std::vector<string>
111115
methodParametersListParametrized(const tests::Tests::MethodDescription &methodDescription,
112116
const Tests::MethodTestCase &testCase);

server/src/sarif/FileSarif.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include "FileSarif.h"
2+
#include "gtest/gtest.h"
3+
#include "utils/JsonUtils.h"
4+
#include "Paths.h"
5+
#include "loguru.h"
6+
7+
namespace sarif {
8+
9+
FileSarif::FileSarif(const tests::Tests &tests) : ProjectSarif(tests.sourceFileNameNoExt, tests.relativeFileDir),
10+
sourcePath(tests.sourceFilePath) {}
11+
12+
13+
14+
int FileSarif::generateSarifForFunction(const tests::Tests::MethodDescription &methodDescription,
15+
const fs::path &projectPath) {
16+
int errorTestCases = 0;
17+
for (const auto &testCase : methodDescription.testCases) {
18+
if (testCase.isError()) {
19+
errorTestCases++;
20+
if (!testCase.errorDescriptionInJson.has_value()) {
21+
LOG_S(ERROR) << "Test Case is error but doesn't have json from klee";
22+
continue;
23+
}
24+
fs::path jsonPath = testCase.errorDescriptionInJson.value();
25+
json testCaseJson = JsonUtils::getJsonFromFile(jsonPath);
26+
string errorLocationStr = getUriFromLocation(testCaseJson.at("locations").at(0));
27+
if (projectPath / errorLocationStr != sourcePath) {
28+
LOG_S(ERROR) << "Found error location not in project: " << errorLocationStr;
29+
continue;
30+
}
31+
deleteExternalFilesFromResult(testCaseJson.at("codeFlows").at(0).at("threadFlows").at(0),
32+
projectPath);
33+
addResultToSarif(testCaseJson);
34+
}
35+
}
36+
LOG_S(INFO) << "Found " << errorTestCases << " error test cases for " << methodDescription.name << " in " << sourcePath;
37+
return errorTestCases;
38+
}
39+
40+
41+
42+
json &FileSarif::getUriFromLocation(json &location) {
43+
return location.at("physicalLocation").at("artifactLocation").at("uri");
44+
}
45+
46+
void FileSarif::deleteExternalFilesFromResult(json &result, const fs::path &projectRoot) {
47+
for (int i = 0; i < result.at("locations").size(); ++i) {
48+
json &location = result.at("locations").at(i).at("location");
49+
string location_path = fs::path((string)getUriFromLocation(location));
50+
if (Paths::isSubPathOf(projectRoot, location_path)) {
51+
getUriFromLocation(location) = location_path.substr(projectRoot.string().size() + 1);
52+
}
53+
}
54+
auto it = std::remove_if(result.at("locations").begin(), result.at("locations").end(),
55+
[&](json &location) {
56+
return !fs::exists(projectRoot / (string)getUriFromLocation(location.at("location")));
57+
});
58+
result.at("locations").erase(it, result.at("locations").end());
59+
}
60+
61+
void FileSarif::addResultToSarif(const json &result) {
62+
sarifJson.at("runs").at(0).at("results").push_back(result);
63+
}
64+
}

server/src/sarif/FileSarif.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef UNITTESTBOT_FILESARIF_H
2+
#define UNITTESTBOT_FILESARIF_H
3+
4+
#include <string>
5+
#include "utils/JsonUtils.h"
6+
#include "utils/path/FileSystemPath.h"
7+
#include "Tests.h"
8+
#include "ProjectContext.h"
9+
#include "ProjectSarif.h"
10+
#include "loguru.h"
11+
12+
using json = nlohmann::json;
13+
namespace sarif {
14+
struct FileSarif : ProjectSarif {
15+
private:
16+
const fs::path sourcePath;
17+
18+
void deleteExternalFilesFromResult(json &result, const fs::path &projectRoot);
19+
json &getUriFromLocation(json &location);
20+
void addResultToSarif(const json &result);
21+
22+
public:
23+
const static inline std::string sarif_klee_prefix = "__sarif_";
24+
const static inline std::string sarif_klee_extension = ".json";
25+
const static inline std::string prefix_for_json_path = "// THIS LINE SHOULDN'T BE AT END, path of klee-sarif: ";
26+
27+
explicit FileSarif(const tests::Tests &tests);
28+
int generateSarifForFunction(const tests::Tests::MethodDescription &methodDescription, const fs::path &projectRoot);
29+
};
30+
}
31+
32+
#endif //UNITTESTBOT_FILESARIF_H

0 commit comments

Comments
 (0)