diff --git a/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp b/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp index faf6bbfb0..6aab07abd 100644 --- a/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp +++ b/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp @@ -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}); } } diff --git a/server/src/printers/KleePrinter.cpp b/server/src/printers/KleePrinter.cpp index 206e6f4ad..968930ac1 100644 --- a/server/src/printers/KleePrinter.cpp +++ b/server/src/printers/KleePrinter.cpp @@ -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) { diff --git a/server/src/printers/Printer.cpp b/server/src/printers/Printer.cpp index 1b1bf6cbc..774adaac3 100644 --- a/server/src/printers/Printer.cpp +++ b/server/src/printers/Printer.cpp @@ -124,7 +124,9 @@ namespace printer { types::PointerUsage usage, std::optional value, std::optional alignment, - bool complete) { + bool complete, + const types::TypesHandler* typesHandler, + bool namespaceNeeded) { auto baseType = type.baseType(); std::string arrayName{ name.data(), name.length() }; @@ -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; @@ -673,12 +679,20 @@ namespace printer { ss << Copyright::GENERATED_C_CPP_FILE_HEADER << NL; } - Printer::Stream Printer::strDeclareSetOfVars(const std::set &vars) { + Printer::Stream Printer::strDeclareSetOfVars(const std::set &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; diff --git a/server/src/printers/Printer.h b/server/src/printers/Printer.h index b677bcb8a..d9ca91b29 100644 --- a/server/src/printers/Printer.h +++ b/server/src/printers/Printer.h @@ -86,9 +86,13 @@ namespace printer { types::PointerUsage usage, std::optional value = std::nullopt, std::optional alignment = std::nullopt, - bool complete = true); + bool complete = true, + const types::TypesHandler* typesHandler = nullptr, + bool namespaceNeeded = false); - Stream strDeclareSetOfVars(const std::set &vars); + Stream strDeclareSetOfVars(const std::set &vars, + const types::TypesHandler* typesHandler, + bool namespaceNeeded); Stream strAssignVar(std::string_view name, std::string_view value); diff --git a/server/src/printers/TestsPrinter.cpp b/server/src/printers/TestsPrinter.cpp index 2f6780f62..b4cbd7b2c 100644 --- a/server/src/printers/TestsPrinter.cpp +++ b/server/src/printers/TestsPrinter.cpp @@ -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"; diff --git a/server/src/utils/PrinterUtils.cpp b/server/src/utils/PrinterUtils.cpp index 45692f0b8..a4dc1fc1a 100644 --- a/server/src/utils/PrinterUtils.cpp +++ b/server/src/utils/PrinterUtils.cpp @@ -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); } diff --git a/server/src/utils/PrinterUtils.h b/server/src/utils/PrinterUtils.h index b61e1e4a1..1bee5151f 100644 --- a/server/src/utils/PrinterUtils.h +++ b/server/src/utils/PrinterUtils.h @@ -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); diff --git a/server/test/framework/Server_Tests.cpp b/server/test/framework/Server_Tests.cpp index 2125cd134..5ba04e31e 100644 --- a/server/test/framework/Server_Tests.cpp +++ b/server/test/framework/Server_Tests.cpp @@ -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); @@ -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(); @@ -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(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, diff --git a/server/test/suites/server/globals.c b/server/test/suites/server/globals.c index d3c940e8c..073e5ed56 100644 --- a/server/test/suites/server/globals.c +++ b/server/test/suites/server/globals.c @@ -1,3 +1,5 @@ +#include "globals.h" + int counter = 0; int increment() @@ -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) @@ -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; } diff --git a/server/test/suites/server/globals.h b/server/test/suites/server/globals.h new file mode 100644 index 000000000..9dd46ead7 --- /dev/null +++ b/server/test/suites/server/globals.h @@ -0,0 +1,8 @@ +#ifndef UNITTESTBOT_GLOBALS_H +#define UNITTESTBOT_GLOBALS_H + +struct ExternStruct { + _Bool fld; +}; + +#endif // UNITTESTBOT_GLOBALS_H diff --git a/server/test/suites/server/linkage.c b/server/test/suites/server/linkage.c index 582f736fb..e44aa113f 100644 --- a/server/test/suites/server/linkage.c +++ b/server/test/suites/server/linkage.c @@ -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;