Skip to content

Commit fc4839d

Browse files
committed
Add class mutation tracking
1 parent ef3ce99 commit fc4839d

18 files changed

+260
-91
lines changed

server/CMakeLists.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
cmake_minimum_required(VERSION 3.10)
22
project(UnitTestBot)
33

4-
if(UNIX)
4+
if (UNIX)
55
add_compile_definitions(_LINUX)
6-
endif()
6+
endif ()
77

88
set(CMAKE_CXX_STANDARD 17)
99
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -30,7 +30,7 @@ set(GRPC_PATH $ENV{GRPC_PATH})
3030
set(CMAKE_PREFIX_PATH ${GRPC_PATH}/lib/cmake/grpc ${GRPC_PATH}/lib/cmake/protobuf)
3131
if (NOT DEFINED _GRPC_CPP_PLUGIN_EXECUTABLE)
3232
set(_GRPC_CPP_PLUGIN_EXECUTABLE ${GRPC_PATH}/bin/grpc_cpp_plugin)
33-
endif()
33+
endif ()
3434
include_directories(${GRPC_PATH}/include)
3535

3636
find_package(Threads REQUIRED)
@@ -99,7 +99,7 @@ set(PROTO_COMPILE_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf")
9999
file(GLOB PROTO_FILES "${PROTO_DIR}/*.proto")
100100
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobuf)
101101

102-
foreach(proto_file ${PROTO_FILES})
102+
foreach (proto_file ${PROTO_FILES})
103103
get_filename_component(proto_src ${proto_file} PATH)
104104
get_filename_component(proto_filename ${proto_file} NAME_WE)
105105
execute_process(
@@ -149,6 +149,7 @@ add_executable(
149149
UTBot_UnitTests
150150
${ALL_TESTS}
151151
)
152+
152153
target_include_directories(UTBot_UnitTests PUBLIC src src/include $ENV{UTBOT_ALL}/gtest/googletest)
153154
target_link_libraries(
154155
UTBot_UnitTests
@@ -157,7 +158,7 @@ target_link_libraries(
157158
UnitTestBotLib
158159
)
159160

160-
add_test(UTBot_UnitTests UTBot_UnitTests)
161+
add_test(NAME test COMMAND UTBot_UnitTests)
161162

162163
install(TARGETS utbot
163164
DESTINATION ${CMAKE_INSTALL_PREFIX}

server/src/KleeGenerator.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ vector<fs::path> KleeGenerator::buildKleeFiles(const tests::TestsMap &testsMap,
256256
for (const auto &[methodName, methodDescription] : tests.methods) {
257257
fs::path currentKleeFilePath = kleePrinter.writeTmpKleeFile(
258258
tests, projectTmpPath, pathSubstitution, std::nullopt,
259-
methodDescription.name, methodDescription.className, true, false);
259+
methodDescription.name,
260+
methodDescription.getClassName(),
261+
true, false);
260262
auto currentKleeBitcodeFile =
261263
defaultBuild(filename, currentKleeFilePath, buildDirPath, includeFlags);
262264
if (currentKleeBitcodeFile.isSuccess()) {
@@ -308,8 +310,8 @@ void KleeGenerator::parseKTestsToFinalCode(
308310
Tests::MethodDescription &methodDescription = it.value();
309311
if (lineInfo) {
310312
bool methodNotMatch = lineInfo->forMethod && methodName != lineInfo->methodName;
311-
bool classNotMatch = lineInfo->forClass &&
312-
methodDescription.className.value() != lineInfo->scopeName;
313+
bool classNotMatch = lineInfo->forClass && methodDescription.isClassMethod() &&
314+
methodDescription.getClassName().value() != lineInfo->scopeName;
313315
if (methodNotMatch || classNotMatch) {
314316
continue;
315317
}

server/src/Server.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen,
226226
lineInfo = std::make_shared<LineInfo>(classFinder.getLineInfo());
227227
lineInfo->filePath = lineTestGen->testingMethodsSourcePaths[0];
228228
CollectionUtils::erase_if(testGen.tests.at(lineInfo->filePath).methods,
229-
[&lineInfo](const auto &methodDescription) {
230-
return methodDescription.className != lineInfo->scopeName;
229+
[&lineInfo](const tests::Tests::MethodDescription &methodDescription) {
230+
return methodDescription.isClassMethod() &&
231+
methodDescription.classObj->type.typeName() != lineInfo->scopeName;
231232
});
232233
} else {
233234
lineInfo = getLineInfo(*lineTestGen);
@@ -321,7 +322,7 @@ shared_ptr<LineInfo> Server::TestsGenServiceImpl::getLineInfo(LineTestGen &lineT
321322
auto &methods = lineTestGen.tests.at(lineInfo->filePath).methods;
322323
CollectionUtils::erase_if(methods, [&lineInfo](auto const &method) {
323324
return (lineInfo->forMethod && method.name != lineInfo->methodName) ||
324-
(lineInfo->forClass && method.className != lineInfo->scopeName);
325+
(lineInfo->forClass && method.isClassMethod() && method.classObj->type.typeName() != lineInfo->scopeName);
325326
});
326327
return lineInfo;
327328
}

server/src/Tests.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@ void KTestObjectParser::parseTestCases(const UTBotKTestList &cases,
692692
// if all of the data characters are not printable the case is skipped
693693
continue;
694694
}
695+
swap(testCase.classPreValues, testCaseDescription.classPreValues);
696+
swap(testCase.classPostValues, testCaseDescription.classPostValues);
695697
swap(testCase.globalPreValues, testCaseDescription.globalPreValues);
696698
swap(testCase.globalPostValues, testCaseDescription.globalPostValues);
697699
swap(testCase.paramPostValues, testCaseDescription.paramPostValues);
@@ -794,6 +796,25 @@ KTestObjectParser::parseTestCaseParams(const UTBotKTest &ktest,
794796
}
795797

796798
const RawKleeParam emptyKleeParam = {"", {}};
799+
800+
if (methodDescription.isClassMethod()) {
801+
auto methodParam = methodDescription.classObj.value();
802+
shared_ptr<AbstractValueView> testParamView;
803+
auto paramType = methodParam.type.maybeJustPointer() ? methodParam.type.baseTypeObj() : methodParam.type;
804+
if (CollectionUtils::containsKey(methodDescription.functionPointers, methodParam.name)) {
805+
testParamView = testParameterView(
806+
emptyKleeParam, { paramType, methodParam.name }, PointerUsage::PARAMETER, testCaseDescription.fromAddressToName,
807+
testCaseDescription.lazyReferences, methodDescription);
808+
} else {
809+
const auto kleeParam = getKleeParamOrThrow(rawKleeParams, methodParam.name);
810+
testParamView = testParameterView(kleeParam, {paramType, methodParam.name }, PointerUsage::PARAMETER,
811+
testCaseDescription.fromAddressToName, testCaseDescription.lazyReferences,
812+
methodDescription);
813+
}
814+
testCaseDescription.classPreValues = { methodParam.name, methodParam.alignment, testParamView };
815+
processClassPostValue(testCaseDescription, methodParam, rawKleeParams);
816+
}
817+
797818
for (auto &methodParam : methodDescription.params) {
798819
shared_ptr<AbstractValueView> testParamView;
799820
auto paramType = methodParam.type.maybeJustPointer() ? methodParam.type.baseTypeObj() : methodParam.type;
@@ -898,6 +919,20 @@ void KTestObjectParser::processGlobalParamPostValue(Tests::TestCaseDescription &
898919
testCaseDescription.globalPostValues.emplace_back( globalParam.name, globalParam.alignment, testParamView );
899920
}
900921

922+
void KTestObjectParser::processClassPostValue(Tests::TestCaseDescription &testCaseDescription,
923+
const Tests::MethodParam &param,
924+
vector<RawKleeParam> &rawKleeParams) {
925+
const auto usage = types::PointerUsage::PARAMETER;
926+
auto symbolicVariable = KleeUtils::postSymbolicVariable(param.name);
927+
auto kleeParam = getKleeParamOrThrow(rawKleeParams, symbolicVariable);
928+
types::Type paramType = param.type.arrayCloneMultiDim(usage);
929+
auto type = typesHandler.getReturnTypeToCheck(paramType);
930+
Tests::TypeAndVarName typeAndVarName{ type, param.name };
931+
auto testParamView = testParameterView(kleeParam, typeAndVarName, usage, testCaseDescription.fromAddressToName,
932+
testCaseDescription.lazyReferences);
933+
testCaseDescription.classPostValues = { param.name, param.alignment, testParamView };
934+
}
935+
901936
void KTestObjectParser::processParamPostValue(Tests::TestCaseDescription &testCaseDescription,
902937
const Tests::MethodParam &param,
903938
vector<RawKleeParam> &rawKleeParams) {
@@ -961,9 +996,10 @@ shared_ptr<AbstractValueView> KTestObjectParser::testParameterView(
961996
return arrayView(rawData, paramType.baseTypeObj(), rawData.size(), 0, usage);
962997
}
963998
case TypeKind::FUNCTION_POINTER:
964-
if (!testingMethod.has_value())
999+
if (!testingMethod.has_value()) {
9651000
return functionPointerView(std::nullopt, "", param.varName);
966-
return functionPointerView(testingMethod->className, testingMethod->name, param.varName);
1001+
}
1002+
return functionPointerView(testingMethod->getClassTypeName(), testingMethod->name, param.varName);
9671003
case TypeKind::ENUM:
9681004
enumInfo = typesHandler.getEnumInfo(paramType);
9691005
return enumView(rawData, enumInfo, 0, rawData.size());

server/src/Tests.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <memory>
2323
#include <utility>
2424
#include <queue>
25+
#include <optional>
2526

2627
namespace tests {
2728
using std::string;
@@ -355,6 +356,8 @@ namespace tests {
355356
TestCaseParamValue functionReturnNotNullValue;
356357
TestCaseParamValue kleePathFlagSymbolicValue;
357358
std::optional <TestCaseParamValue> stdinValue = std::nullopt;
359+
std::optional<TestCaseParamValue> classPreValues;
360+
std::optional<TestCaseParamValue> classPostValues;
358361
};
359362

360363
struct MethodTestCase {
@@ -378,6 +381,8 @@ namespace tests {
378381
vector<TestCaseParamValue> stubParamValues;
379382
vector<MethodParam> stubParamTypes;
380383
shared_ptr<AbstractValueView> returnValueView;
384+
std::optional<TestCaseParamValue> classPreValues;
385+
std::optional<TestCaseParamValue> classPostValues;
381386

382387
bool isError() const;
383388
};
@@ -389,18 +394,18 @@ namespace tests {
389394
};
390395

391396
struct MethodDescription {
392-
std::optional<string> className;
393-
string name;
394-
string code;
395-
string paramsString;
397+
std::optional<MethodParam> classObj;
398+
std::string name;
399+
std::string code;
400+
std::string paramsString;
396401

397402
types::Type returnType;
398403
bool hasIncompleteReturnType = false;
399404

400405
std::optional<string> sourceBody;
401406
Modifiers modifiers;
402407
bool isVariadic = false;
403-
vector<MethodParam> globalParams;
408+
std::vector<MethodParam> globalParams;
404409
std::vector<MethodParam> params;
405410

406411
typedef std::unordered_map<string, std::shared_ptr<types::FunctionInfo>> FPointerMap;
@@ -442,10 +447,6 @@ namespace tests {
442447
return method;
443448
}
444449

445-
bool isClassMethod() const {
446-
return className.has_value();
447-
}
448-
449450
bool hasChangeable() const {
450451
for(const auto& i : params) {
451452
if (i.isChangeable()) {
@@ -454,6 +455,24 @@ namespace tests {
454455
}
455456
return false;
456457
}
458+
459+
bool isClassMethod() const {
460+
return classObj.has_value();
461+
}
462+
463+
std::optional<std::string> getClassName() const {
464+
if (isClassMethod()) {
465+
return std::make_optional(classObj->name);
466+
}
467+
return std::nullopt;
468+
}
469+
470+
std::optional<std::string> getClassTypeName() const {
471+
if (isClassMethod()) {
472+
return std::make_optional(classObj->type.typeName());
473+
}
474+
return std::nullopt;
475+
}
457476
};
458477

459478
struct MethodDescriptionToStringEqual {
@@ -659,6 +678,10 @@ namespace tests {
659678
const Tests::MethodParam &globalParam,
660679
vector<RawKleeParam> &rawKleeParams);
661680

681+
void processClassPostValue(Tests::TestCaseDescription &testCaseDescription,
682+
const Tests::MethodParam &param,
683+
vector<RawKleeParam> &rawKleeParams);
684+
662685
void processParamPostValue(Tests::TestCaseDescription &testCaseDescription,
663686
const Tests::MethodParam &param,
664687
vector<RawKleeParam> &rawKleeParams);

server/src/building/Linker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,9 @@ vector<tests::TestMethod> Linker::getTestMethods() {
305305
}
306306
for (const auto &[methodName, method] : tests.methods) {
307307
if (methodName == lineInfo->methodName ||
308-
(lineInfo->forClass && method.className == lineInfo->scopeName)) {
308+
(lineInfo->forClass &&
309+
method.classObj.has_value() &&
310+
method.classObj->type.typeName() == lineInfo->scopeName)) {
309311
auto compilationUnitInfo =
310312
testGen.buildDatabase->getClientCompilationUnitInfo(fileName);
311313
if (compilationUnitInfo->kleeFilesInfo->isCorrectMethod(methodName)) {

server/src/fetchers/FunctionDeclsMatchCallback.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) {
6060
auto *nodeParent = (CXXRecordDecl *)FS->getParent();
6161
if (FS->isCXXClassMember()) {
6262
string className = nodeParent->getNameAsString();
63-
methodDescription.className = className;
63+
const clang::QualType clangClassType = nodeParent->getTypeForDecl()->getCanonicalTypeInternal();
64+
auto classType = ParamsHandler::getType(clangClassType, clangClassType, sourceManager);
65+
methodDescription.classObj = { classType,
66+
classType.typeName() + "_obj",
67+
std::nullopt };
6468
}
6569
methodDescription.returnType = ParamsHandler::getType(realReturnType, realReturnType, sourceManager);
6670
methodDescription.hasIncompleteReturnType = ClangUtils::isIncomplete(realReturnType);

server/src/printers/KleeConstraintsPrinter.cpp

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,39 @@ printer::KleeConstraintsPrinter::KleeConstraintsPrinter(const types::TypesHandle
1414
: Printer(srcLanguage), typesHandler(typesHandler) {}
1515

1616
printer::KleeConstraintsPrinter::Stream
17-
KleeConstraintsPrinter::genConstraints(const Tests::MethodParam &param, const string &methodName) {
18-
19-
ConstraintsState state = { "&" + param.name, param.name, param.type, true };
20-
auto paramType = param.type;
21-
if (param.type.maybeJustPointer()) {
22-
state.curType = paramType = param.type.baseTypeObj();
17+
KleeConstraintsPrinter::genConstraints(const string &name, const types::Type& type) {
18+
ConstraintsState state = { "&" + name, name, type, true };
19+
auto paramType = type;
20+
if (type.maybeJustPointer()) {
21+
state.curType = paramType = type.baseTypeObj();
2322
}
2423
switch (typesHandler->getTypeKind(paramType)) {
25-
case TypeKind::OBJECT_POINTER:
26-
case TypeKind::ARRAY:
27-
state = { param.name, param.name, paramType, state.endString };
28-
genConstraintsForPointerOrArray(state);
29-
break;
30-
case TypeKind::STRUCT:
31-
genConstraintsForStruct(state);
32-
break;
33-
case TypeKind::ENUM:
34-
genConstraintsForEnum(state);
35-
break;
36-
case TypeKind::UNION:
37-
genConstraintsForUnion(state);
38-
break;
39-
default:
40-
genConstraintsForPrimitive(state);
24+
case TypeKind::OBJECT_POINTER:
25+
case TypeKind::ARRAY:
26+
state = { name, name, paramType, state.endString };
27+
genConstraintsForPointerOrArray(state);
28+
break;
29+
case TypeKind::STRUCT:
30+
genConstraintsForStruct(state);
31+
break;
32+
case TypeKind::ENUM:
33+
genConstraintsForEnum(state);
34+
break;
35+
case TypeKind::UNION:
36+
genConstraintsForUnion(state);
37+
break;
38+
default:
39+
genConstraintsForPrimitive(state);
4140
}
4241

4342
return ss;
4443
}
4544

45+
printer::KleeConstraintsPrinter::Stream
46+
KleeConstraintsPrinter::genConstraints(const Tests::MethodParam &param) {
47+
return genConstraints(param.name, param.type);
48+
}
49+
4650
void KleeConstraintsPrinter::genConstraintsForPrimitive(const ConstraintsState &state) {
4751
const auto &cons = cexConstraints(state.curElement, state.curType);
4852
if (!cons.empty()) {

server/src/printers/KleeConstraintsPrinter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ namespace printer {
1919

2020
utbot::Language getLanguage() const override;
2121

22-
Stream genConstraints(const Tests::MethodParam &param, const string& methodName = "");
22+
Stream genConstraints(const string &name, const types::Type& type);
23+
24+
Stream genConstraints(const Tests::MethodParam &param);
2325

2426
void setTabsDepth(const size_t depth) {
2527
tabsDepth = depth;

0 commit comments

Comments
 (0)