Skip to content

Commit 28b9102

Browse files
authored
Fix generated tests with anonymous unions constructed from bytes (#624)
* Fix generation of tests with anonymous unions constructed from bytes * Differ isInitializedStruct and isDirtyInitializedStruct
1 parent d31ef09 commit 28b9102

File tree

10 files changed

+75
-63
lines changed

10 files changed

+75
-63
lines changed

server/src/Tests.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -280,16 +280,18 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
280280
size_t structEndOffset = offsetInBits + curStruct.size;
281281
size_t fieldIndex = 0;
282282
bool dirtyInitializedStruct = false;
283+
bool isInitializedStruct = curStruct.subType == types::SubType::Struct;
283284
for (const auto &field: curStruct.fields) {
284285
bool dirtyInitializedField = false;
286+
bool isInitializedField = true;
285287
size_t fieldLen = typesHandler.typeSize(field.type);
286288
size_t fieldStartOffset = offsetInBits + field.offset;
287289
size_t fieldEndOffset = fieldStartOffset + fieldLen;
288290
if (curStruct.subType == types::SubType::Union) {
289291
prevFieldEndOffset = offsetInBits;
290292
}
291293

292-
auto dirtyCheck = [&](int i) {
294+
auto dirtyCheck = [&](size_t i) {
293295
if (i >= byteArray.size()) {
294296
LOG_S(ERROR) << "Bad type size info: " << field.name << " index: " << fieldIndex;
295297
} else if (byteArray[i] == 0) {
@@ -302,15 +304,16 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
302304

303305
if (prevFieldEndOffset < fieldStartOffset) {
304306
// check an alignment gap
305-
for (int i = prevFieldEndOffset/8; i < fieldStartOffset/8; ++i) {
307+
for (size_t i = prevFieldEndOffset / 8; i < fieldStartOffset / 8; ++i) {
306308
if (dirtyCheck(i)) {
307309
break;
308310
}
309311
}
310312
}
311-
if (!dirtyInitializedField && curStruct.subType == types::SubType::Union) {
312-
// check the rest of the union
313-
for (int i = fieldEndOffset/8; i < structEndOffset/8; ++i) {
313+
if (!dirtyInitializedField && (curStruct.subType == types::SubType::Union ||
314+
fieldIndex + 1 == curStruct.fields.size())) {
315+
// check the rest of the union or the last field of the struct
316+
for (size_t i = fieldEndOffset / 8; i < structEndOffset / 8; ++i) {
314317
if (dirtyCheck(i)) {
315318
break;
316319
}
@@ -325,6 +328,7 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
325328
PrinterUtils::getFieldAccess(name, field), objects,
326329
initReferences);
327330
dirtyInitializedField |= sv->isDirtyInit();
331+
isInitializedField = sv->isInitialized();
328332
subViews.push_back(sv);
329333
}
330334
break;
@@ -392,34 +396,38 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
392396
throw NoSuchTypeException(message);
393397
}
394398

395-
if (!dirtyInitializedField && sizeOfFieldToInitUnion < fieldLen) {
399+
if (!dirtyInitializedField && sizeOfFieldToInitUnion < fieldLen &&
400+
curStruct.subType == types::SubType::Union) {
396401
fieldIndexToInitUnion = fieldIndex;
397402
sizeOfFieldToInitUnion = fieldLen;
398-
} else {
399-
dirtyInitializedStruct = true;
403+
isInitializedStruct = true;
404+
dirtyInitializedStruct = false;
405+
}
406+
if (curStruct.subType == types::SubType::Struct) {
407+
dirtyInitializedStruct |= dirtyInitializedField;
408+
isInitializedStruct &= isInitializedField;
400409
}
401410
prevFieldEndOffset = fieldEndOffset;
402411
++fieldIndex;
403412
}
404413

405414
std::optional<std::string> entryValue;
406-
if (curStruct.subType == types::SubType::Union) {
407-
if (fieldIndexToInitUnion == SIZE_MAX && !curStruct.name.empty()) {
408-
// init by memory copy
409-
entryValue = PrinterUtils::convertBytesToUnion(
410-
curStruct.name,
411-
arrayView(byteArray, lazyPointersArray,
412-
types::Type::createSimpleTypeFromName("utbot_byte"),
413-
curStruct.size,
414-
offsetInBits, usage)->getEntryValue(nullptr));
415-
dirtyInitializedStruct = false;
416-
}
417-
if (fieldIndexToInitUnion != SIZE_MAX) {
418-
dirtyInitializedStruct = false;
419-
}
415+
if (!isInitializedStruct && !curStruct.name.empty() && !anonymousField) {
416+
// init by memory copy
417+
entryValue = PrinterUtils::convertBytesToStruct(
418+
curStruct.name,
419+
arrayView(byteArray, lazyPointersArray,
420+
types::Type::createSimpleTypeFromName("utbot_byte"),
421+
curStruct.size,
422+
offsetInBits, usage)->getEntryValue(nullptr));
423+
isInitializedStruct = true;
424+
dirtyInitializedStruct = false;
425+
}
426+
if (!isInitializedStruct) {
427+
dirtyInitializedStruct = false;
420428
}
421429
return std::make_shared<StructValueView>(curStruct, subViews, entryValue,
422-
anonymousField, dirtyInitializedStruct, fieldIndexToInitUnion);
430+
anonymousField, isInitializedStruct, dirtyInitializedStruct, fieldIndexToInitUnion);
423431
}
424432

425433
std::string KTestObjectParser::primitiveCharView(const types::Type &type, std::string value) {

server/src/Tests.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,21 @@ namespace tests {
238238
std::vector<std::shared_ptr<AbstractValueView>> _subViews,
239239
std::optional<std::string> _entryValue,
240240
bool _anonymous,
241+
bool _isInit,
241242
bool _dirtyInit,
242243
size_t _fieldIndexToInitUnion)
243244
: AbstractValueView(std::move(_subViews))
244245
, entryValue(std::move(_entryValue))
245246
, structInfo(_structInfo)
246247
, anonymous(_anonymous)
248+
, isInit(_isInit)
247249
, dirtyInit(_dirtyInit)
248250
, fieldIndexToInitUnion(_fieldIndexToInitUnion){}
249251

252+
bool isInitialized() const {
253+
return isInit;
254+
}
255+
250256
bool isDirtyInit() const {
251257
return dirtyInit;
252258
}
@@ -317,6 +323,7 @@ namespace tests {
317323
std::optional<std::string> entryValue;
318324

319325
bool anonymous;
326+
bool isInit;
320327
bool dirtyInit;
321328
size_t fieldIndexToInitUnion;
322329
};

server/src/utils/PrinterUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace PrinterUtils {
1010
std::string convertToBytesFunctionName(const std::string &typeName) {
1111
return StringUtils::stringFormat("from_bytes<%s>", typeName);
1212
}
13-
std::string convertBytesToUnion(const std::string &typeName, const std::string &bytes) {
13+
std::string convertBytesToStruct(const std::string &typeName, const std::string &bytes) {
1414
return StringUtils::stringFormat("%s(%s)", convertToBytesFunctionName(typeName), bytes);
1515
}
1616

server/src/utils/PrinterUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ namespace PrinterUtils {
6262

6363
std::string convertToBytesFunctionName(std::string const &typeName);
6464

65-
std::string convertBytesToUnion(const std::string &typeName, const std::string &bytes);
65+
std::string convertBytesToStruct(const std::string &typeName, const std::string &bytes);
6666

6767
std::string wrapperName(const std::string &declName,
6868
utbot::ProjectContext const &projectContext,

server/src/visitors/AbstractValueViewVisitor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,15 @@ namespace visitor {
9393
auto subViews = view ? &view->getSubViews() : nullptr;
9494

9595
bool oldFlag = inUnion;
96-
inUnion = structInfo.subType == types::SubType::Union;
96+
inUnion |= structInfo.subType == types::SubType::Union;
9797
for (int i = 0; i < structInfo.fields.size(); ++i) {
9898
auto const &field = structInfo.fields[i];
9999
auto newName = PrinterUtils::getFieldAccess(name, field);
100100
auto const *newView = (subViews && i < subViews->size()) ? (*subViews)[i].get() : nullptr;
101101
auto newAccess = PrinterUtils::getFieldAccess(access, field);
102102
visitAny(field.type, newName, newView, newAccess, depth + 1);
103103
}
104+
inUnion = oldFlag;
104105
}
105106

106107
void AbstractValueViewVisitor::visitEnum(const types::Type &type,

server/src/visitors/VerboseAssertsReturnValueVisitor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace visitor {
3232
auto signature = processExpect(type, gtestMacro, {PrinterUtils::fillVarName(access, PrinterUtils::EXPECTED),
3333
getDecorateActualVarName(access)});
3434
signature = changeSignatureToNullCheck(signature, type, view, access);
35-
printer->strFunctionCall(signature.name, signature.args);
35+
printer->strFunctionCall(signature.name, signature.args, SCNL, std::nullopt, true, 0, std::nullopt, inUnion);
3636
}
3737

3838
void VerboseAssertsReturnValueVisitor::visitPointer(const types::Type &type,

server/test/framework/Server_Tests.cpp

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -456,35 +456,6 @@ namespace {
456456
}
457457
}
458458

459-
void checkStructWithUnion_C(BaseTestGen &testGen) {
460-
for (const auto &[methodName, methodDescription] :
461-
testGen.tests.at(struct_with_union_c).methods) {
462-
if (methodName == "struct_with_union_of_unnamed_type_as_return_type") {
463-
checkTestCasePredicates(
464-
methodDescription.testCases,
465-
std::vector<TestCasePredicate>(
466-
{[] (const tests::Tests::MethodTestCase& testCase) {
467-
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) <
468-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
469-
testCase.returnValue.view->getEntryValue(nullptr) == "{{{'\\x99', -2.530171e-98}}}";
470-
},
471-
[] (const tests::Tests::MethodTestCase& testCase) {
472-
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) ==
473-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
474-
StringUtils::startsWith(testCase.returnValue.view->getEntryValue(nullptr),
475-
"{from_bytes<StructWithUnionOfUnnamedType_un>({");
476-
},
477-
[] (const tests::Tests::MethodTestCase& testCase) {
478-
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) >
479-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
480-
testCase.returnValue.view->getEntryValue(nullptr) == "{{{'\\0', -2.530171e-98}}}";
481-
}
482-
}),
483-
methodName);
484-
}
485-
}
486-
}
487-
488459
void checkInnerBasicFunctions_C(BaseTestGen &testGen) {
489460
for (const auto &[methodName, methodDescription] :
490461
testGen.tests.at(inner_basic_functions_c).methods) {
@@ -2187,8 +2158,7 @@ namespace {
21872158
auto testGen = FileTestGen(*request, writer.get(), TESTMODE);
21882159
Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get());
21892160
ASSERT_TRUE(status.ok()) << status.error_message();
2190-
EXPECT_GE(testUtils::getNumberOfTests(testGen.tests), 3);
2191-
checkStructWithUnion_C(testGen);
2161+
EXPECT_GE(testUtils::getNumberOfTests(testGen.tests), 6);
21922162

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

@@ -2214,7 +2184,7 @@ namespace {
22142184
auto resultsMap = coverageGenerator.getTestResultMap();
22152185
auto tests = coverageGenerator.getTestsToLaunch();
22162186

2217-
StatusCountMap expectedStatusCountMap{ { testsgen::TEST_PASSED, 3 } };
2187+
StatusCountMap expectedStatusCountMap{ { testsgen::TEST_PASSED, 6 } };
22182188
testUtils::checkStatuses(resultsMap, tests);
22192189
}
22202190

server/test/framework/Syntax_Tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,7 +1882,7 @@ namespace {
18821882
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) ==
18831883
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
18841884
StringUtils::startsWith(testCase.returnValue.view->getEntryValue(nullptr),
1885-
"{from_bytes<StructWithStructInUnion::DeepUnion>({");
1885+
"{from_bytes<StructWithStructInUnion::DeepUnion>({");;
18861886
},
18871887
[] (const tests::Tests::MethodTestCase& testCase) {
18881888
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) >
@@ -1903,18 +1903,18 @@ namespace {
19031903
std::vector<TestCasePredicate>(
19041904
{[] (const tests::Tests::MethodTestCase& testCase) {
19051905
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) <
1906-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
1906+
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
19071907
testCase.returnValue.view->getEntryValue(nullptr) == "{{{'\\x99', -2.530171e-98}}}";
19081908
},
19091909
[] (const tests::Tests::MethodTestCase& testCase) {
19101910
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) ==
1911-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
1911+
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
19121912
StringUtils::startsWith(testCase.returnValue.view->getEntryValue(nullptr),
19131913
"{from_bytes<StructWithUnionOfUnnamedType_un>({");
19141914
},
19151915
[] (const tests::Tests::MethodTestCase& testCase) {
19161916
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) >
1917-
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
1917+
stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) &&
19181918
testCase.returnValue.view->getEntryValue(nullptr) == "{{{'\\0', -2.530171e-98}}}";
19191919
}
19201920
})

server/test/suites/server/struct_with_union.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,17 @@ struct StructWithUnionOfUnnamedType struct_with_union_of_unnamed_type_as_return_
1111
ans.un.ds.d = 1.0101;
1212
}
1313
return ans;
14+
}
15+
16+
struct StructWithAnonymousUnion struct_with_anonymous_union_as_return_type(int a, int b) {
17+
struct StructWithAnonymousUnion ans;
18+
if (a > b) {
19+
ans.ptr = 0;
20+
} else if (a < b) {
21+
ans.x = 153;
22+
} else {
23+
ans.c = 'k';
24+
ans.d = 1.0101;
25+
}
26+
return ans;
1427
}

server/test/suites/server/struct_with_union.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ struct StructWithUnionOfUnnamedType {
1212
} un;
1313
};
1414

15+
struct StructWithAnonymousUnion {
16+
union {
17+
int x;
18+
struct {
19+
char c;
20+
double d;
21+
};
22+
long long *ptr;
23+
};
24+
};
25+
1526
struct StructWithUnionOfUnnamedType struct_with_union_of_unnamed_type_as_return_type(int a, int b);
1627

28+
struct StructWithAnonymousUnion struct_with_anonymous_union_as_return_type(int a, int b);
29+
1730
#endif // SIMPLE_TEST_PROJECT_STRUCT_WITH_UNION_H

0 commit comments

Comments
 (0)