Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix test generation for extern variables #611

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/src/fetchers/GlobalVariableUsageMatchCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void GlobalVariableUsageMatchCallback::handleUsage(const clang::FunctionDecl *fu
const std::string usedParamTypeString = varDecl->getType().getAsString();
types::Type paramType = types::Type(realParamType, usedParamTypeString, sourceManager);
method.globalParams.emplace_back(paramType, usage.variableName, AlignmentFetcher::fetch(varDecl));
if (varDecl->isExternC() && !varDecl->isKnownToBeDefined()) {
if (varDecl->isExternC() && !varDecl->isKnownToBeDefined() && !paramType.isPointerToFunction()) {
tests.externVariables.insert({paramType, usage.variableName});
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/src/printers/KleePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fs::path KleePrinter::writeTmpKleeFile(
return filter && forThisFunction && forThisClass;
});

strDeclareSetOfVars(tests.externVariables);
strDeclareSetOfVars(tests.externVariables, typesHandler, false);
ss << NL;

for (const auto &[methodName, testMethod]: tests.methods) {
Expand Down
22 changes: 18 additions & 4 deletions server/src/printers/Printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ namespace printer {
types::PointerUsage usage,
std::optional<std::string_view> value,
std::optional<uint64_t> alignment,
bool complete) {
bool complete,
const types::TypesHandler* typesHandler,
bool namespaceNeeded) {
auto baseType = type.baseType();
std::string arrayName{ name.data(), name.length() };

Expand All @@ -133,6 +135,10 @@ namespace printer {
arrayName = NameDecorator::decorate(arrayName);
}

if (namespaceNeeded && typesHandler) {
PrinterUtils::decorateTypeNameWithNamespace(type.baseTypeObj().getId(), baseType, typesHandler);
}

ss << LINE_INDENT();
printAlignmentIfExists(alignment);
ss << baseType << " " << arrayName;
Expand Down Expand Up @@ -673,12 +679,20 @@ namespace printer {
ss << Copyright::GENERATED_C_CPP_FILE_HEADER << NL;
}

Printer::Stream Printer::strDeclareSetOfVars(const std::set<Tests::TypeAndVarName> &vars) {
Printer::Stream Printer::strDeclareSetOfVars(const std::set<Tests::TypeAndVarName> &vars,
const types::TypesHandler* typesHandler,
bool namespaceNeeded) {
for (const auto &var : vars) {
ss << "extern ";
if (var.type.isArray()) {
strDeclareArrayVar(var.type, var.varName, types::PointerUsage::KNOWN_SIZE);
strDeclareArrayVar(var.type, var.varName, types::PointerUsage::KNOWN_SIZE,
std::nullopt, std::nullopt, true, typesHandler, namespaceNeeded);
} else {
strDeclareVar(var.type.mTypeName(), var.varName);
types::TypeName typeName = var.type.mTypeName();
if (namespaceNeeded && typesHandler) {
PrinterUtils::decorateTypeNameWithNamespace(var.type.baseTypeObj().getId(), typeName, typesHandler);
}
strDeclareVar(typeName, var.varName);
}
}
return ss;
Expand Down
8 changes: 6 additions & 2 deletions server/src/printers/Printer.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,13 @@ namespace printer {
types::PointerUsage usage,
std::optional<std::string_view> value = std::nullopt,
std::optional<uint64_t> alignment = std::nullopt,
bool complete = true);
bool complete = true,
const types::TypesHandler* typesHandler = nullptr,
bool namespaceNeeded = false);

Stream strDeclareSetOfVars(const std::set<Tests::TypeAndVarName> &vars);
Stream strDeclareSetOfVars(const std::set<Tests::TypeAndVarName> &vars,
const types::TypesHandler* typesHandler,
bool namespaceNeeded);

Stream strAssignVar(std::string_view name, std::string_view value);

Expand Down
3 changes: 2 additions & 1 deletion server/src/printers/TestsPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ void TestsPrinter::joinToFinalCode(Tests &tests, const fs::path& generatedHeader
genHeaders(tests, generatedHeaderPath);
ss << NL;

strDeclareSetOfVars(tests.externVariables);
strDeclareSetOfVars(tests.externVariables, typesHandler, true);
ss << NL;

ss << "namespace " << PrinterUtils::TEST_NAMESPACE << " {\n";

Expand Down
18 changes: 18 additions & 0 deletions server/src/utils/PrinterUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,24 @@ namespace PrinterUtils {
return "enum " + getReturnMangledTypeName(methodName);
}

void decorateBaseTypeNameWithNamespace(types::TypeName &typeName,
const types::TypeName &baseTypeName) {
types::TypeName newBaseTypeName =
StringUtils::stringFormat("%s::%s", PrinterUtils::TEST_NAMESPACE, baseTypeName);
StringUtils::replaceFirst(typeName, baseTypeName, newBaseTypeName);
}

void decorateTypeNameWithNamespace(uint64_t id, types::TypeName &typeName,
const types::TypesHandler* typesHandler) {
if (typesHandler->isEnum(id)) {
types::TypeName baseTypeName = typesHandler->getEnumInfo(id).name;
decorateBaseTypeNameWithNamespace(typeName, baseTypeName);
} else if (typesHandler->isStructLike(id)) {
types::TypeName baseTypeName = typesHandler->getStructInfo(id).name;
decorateBaseTypeNameWithNamespace(typeName, baseTypeName);
}
}

std::string getEqualString(const std::string& lhs, const std::string& rhs) {
return StringUtils::stringFormat("%s == %s", lhs, rhs);
}
Expand Down
5 changes: 5 additions & 0 deletions server/src/utils/PrinterUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ namespace PrinterUtils {
std::string getReturnMangledTypeName(const std::string& methodName);
std::string getEnumReturnMangledTypeName(const std::string& methodName);

void decorateBaseTypeNameWithNamespace(types::TypeName &typeName,
const types::TypeName &baseTypeName);
void decorateTypeNameWithNamespace(uint64_t id, types::TypeName &typeName,
const types::TypesHandler* typesHandler);

std::string getEqualString(const std::string &lhs, const std::string &rhs);
std::string getDereferencePointer(const std::string &name, const size_t depth);
std::string getExpectedVarName(const std::string &varName);
Expand Down
51 changes: 41 additions & 10 deletions server/test/framework/Server_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,8 +635,8 @@ namespace {
stoi(preValue) + 1 == stoi(postValue);
} }));
} else if (md.name == "use_globals") {
EXPECT_GE(md.testCases.size(), 3);
EXPECT_EQ(md.globalParams.size(), 3);
EXPECT_GE(md.testCases.size(), 5);
EXPECT_EQ(md.globalParams.size(), 5);
} else if (md.name == "use_global_array") {
EXPECT_GE(md.testCases.size(), 3);
EXPECT_EQ(md.globalParams.size(), 1);
Expand Down Expand Up @@ -962,14 +962,6 @@ namespace {
checkLinkage(testGen);
}

TEST_F(Server_Test, Globals) {
auto [testGen, status] = performFeatureFileTestsRequest(globals_c);
ASSERT_TRUE(status.ok()) << status.error_message();
auto testFilePaths = CollectionUtils::getKeys(testGen.tests);
EXPECT_TRUE(!testFilePaths.empty()) << "Generated test files are missing.";
checkGlobals(testGen);
}

TEST_F(Server_Test, Keywords) {
auto [testGen, status] = performFeatureFileTestsRequest(keywords_c);
ASSERT_TRUE(status.ok()) << status.error_message();
Expand Down Expand Up @@ -2065,6 +2057,45 @@ namespace {
testUtils::checkStatusesCount(resultMap, tests, expectedStatusCountMap);
}

TEST_F(Server_Test, Run_Tests_For_Globals) {
fs::path globals_c = getTestFilePath("globals.c");
auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath,
srcPaths, globals_c,
GrpcUtils::UTBOT_AUTO_TARGET_PATH, true, false);
auto testGen = FileTestGen(*request, writer.get(), TESTMODE);
Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get());
ASSERT_TRUE(status.ok()) << status.error_message();
EXPECT_GE(testUtils::getNumberOfTests(testGen.tests), 16);
checkGlobals(testGen);

fs::path testsDirPath = getTestFilePath("tests");

fs::path globals_test_cpp = Paths::sourcePathToTestPath(
utbot::ProjectContext(projectName, suitePath, testsDirPath, buildDirRelativePath, clientProjectPath),
struct_with_union_c);
auto testFilter = GrpcUtils::createTestFilterForFile(globals_test_cpp);
auto runRequest = testUtils::createCoverageAndResultsRequest(
projectName, suitePath, testsDirPath, buildDirRelativePath, std::move(testFilter));

static auto coverageAndResultsWriter =
std::make_unique<ServerCoverageAndResultsWriter>(nullptr);
CoverageAndResultsGenerator coverageGenerator{ runRequest.get(),
coverageAndResultsWriter.get() };
utbot::SettingsContext settingsContext{
true, false, 45, 0, false, false, ErrorMode::FAILING, false
};
coverageGenerator.generate(false, settingsContext);

EXPECT_FALSE(coverageGenerator.hasExceptions());
ASSERT_TRUE(coverageGenerator.getCoverageMap().empty());

auto resultsMap = coverageGenerator.getTestResultMap();
auto tests = coverageGenerator.getTestsToLaunch();

StatusCountMap expectedStatusCountMap{ { testsgen::TEST_PASSED, 16 } };
testUtils::checkStatuses(resultsMap, tests);
}

TEST_F(Server_Test, Run_Tests_For_Hard_Linked_List) {
fs::path hard_linked_list_c = getTestFilePath("hard_linked_list.c");
auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath,
Expand Down
11 changes: 10 additions & 1 deletion server/test/suites/server/globals.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "globals.h"

int counter = 0;

int increment()
Expand All @@ -12,7 +14,8 @@ static _Bool static_global = 0;
static const _Bool const_global = 0;
_Bool non_static_global = 0;
extern _Bool externed_global;
extern _Bool externed_global;
extern _Bool externed_array[1];
extern struct ExternStruct extern_struct;
extern int externed_int_no_def;

static int use_globals(int default_value)
Expand All @@ -38,6 +41,12 @@ static int use_globals(int default_value)
if (externed_global) {
return 4;
}
if (externed_array[0]) {
return 5;
}
if (extern_struct.fld) {
return 6;
}
return default_value;
}

Expand Down
8 changes: 8 additions & 0 deletions server/test/suites/server/globals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef UNITTESTBOT_GLOBALS_H
#define UNITTESTBOT_GLOBALS_H

struct ExternStruct {
_Bool fld;
};

#endif // UNITTESTBOT_GLOBALS_H
6 changes: 6 additions & 0 deletions server/test/suites/server/linkage.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#include "globals.h"

_Bool externed_global = 0;
_Bool externed_array[1] = {0};
struct ExternStruct extern_struct = {
.fld = 0
};

int ordinary_sum(int a, int b) {
return a + b;
Expand Down
Loading