From e84ac213d2dd6a7f03bb303ac535d70cf9464d73 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Tue, 9 Jan 2024 20:54:21 +0800 Subject: [PATCH] Make double-reference work for dynType, and improve dynType_print robustness and coverage. --- libs/dfi/gtest/src/dyn_type_ei_tests.cc | 18 ++++++++ libs/dfi/gtest/src/dyn_type_tests.cpp | 55 +++++++++++++++++++++++-- libs/dfi/src/dyn_type.c | 53 +++++++++++++----------- libs/dfi/src/dyn_type_common.c | 4 +- 4 files changed, 102 insertions(+), 28 deletions(-) diff --git a/libs/dfi/gtest/src/dyn_type_ei_tests.cc b/libs/dfi/gtest/src/dyn_type_ei_tests.cc index 02738eb57..c52bd3e05 100644 --- a/libs/dfi/gtest/src/dyn_type_ei_tests.cc +++ b/libs/dfi/gtest/src/dyn_type_ei_tests.cc @@ -172,3 +172,21 @@ TEST_F(DynTypeErrorInjectionTestSuite, SequenceReserveError) { dynType_free(type, seq); dynType_destroy(type); } + +TEST_F(DynTypeErrorInjectionTestSuite, TextAllocateError) { + dyn_type *type = NULL; + int rc = 0; + rc = dynType_parseWithStr("t", NULL, NULL, &type); + ASSERT_EQ(0, rc); + ASSERT_EQ(DYN_TYPE_TEXT, dynType_type(type)); + + char** val = nullptr; + rc = dynType_alloc(type, (void**)&val); + ASSERT_EQ(0, rc); + celix_ei_expect_strdup((void*)dynType_text_allocAndInit, 0, nullptr); + rc = dynType_text_allocAndInit(type, val, "test"); + ASSERT_NE(0, rc); + ASSERT_STREQ("Cannot allocate memory for string", celix_err_popLastError()); + dynType_free(type, val); + dynType_destroy(type); +} \ No newline at end of file diff --git a/libs/dfi/gtest/src/dyn_type_tests.cpp b/libs/dfi/gtest/src/dyn_type_tests.cpp index cd7e266a4..b714aa7ae 100644 --- a/libs/dfi/gtest/src/dyn_type_tests.cpp +++ b/libs/dfi/gtest/src/dyn_type_tests.cpp @@ -16,8 +16,9 @@ * specific language governing permissions and limitations * under the License. */ - #include "gtest/gtest.h" +#include "celix_stdio_cleanup.h" +#include "celix_stdlib_cleanup.h" extern "C" { #include "dyn_common.h" @@ -30,6 +31,7 @@ extern "C" { //printf("\n-- example %s with descriptor string '%s' --\n", exName, descriptorStr); int status = dynType_parseWithStr(descriptorStr, exName, NULL, &type); ASSERT_EQ(0, status); + ASSERT_STREQ(exName, dynType_getName(type)); //MEM check, to try to ensure no mem leaks/corruptions occur. int i; @@ -82,11 +84,17 @@ class DynTypeTests : public ::testing::Test { #define EX15 "Tsample={jDD time val1 val2};Tresult={jDlsample; time result sample};Lresult;" #define EX16 "Tpoi={BDD id lat lon};Lpoi;" #define EX17 "{#v1=0;#v2=1;E#v1=9;#v2=10;E enum1 enum2}" +#define EX18 "Ttext=t;ltext;" +#define EX19 "Tsample={DD vala valb};Tref=lsample;;lref;" +#define EX20 "TINTEGER=I;Tsample={DlINTEGER; vala valb};Tref=lsample;;lref;" #define CREATE_EXAMPLES_TEST(DESC) \ TEST_F(DynTypeTests, ParseTestExample ## DESC) { \ runTest(DESC, #DESC); \ - } + } \ + TEST_F(DynTypeTests, ParseTestExampleNoName ## DESC) { \ + runTest(DESC, nullptr); \ + } CREATE_EXAMPLES_TEST(EX1) CREATE_EXAMPLES_TEST(EX2) @@ -101,10 +109,13 @@ CREATE_EXAMPLES_TEST(EX10) CREATE_EXAMPLES_TEST(EX11) CREATE_EXAMPLES_TEST(EX12) CREATE_EXAMPLES_TEST(EX13) -//CREATE_EXAMPLES_TEST(EX14) +CREATE_EXAMPLES_TEST(EX14) CREATE_EXAMPLES_TEST(EX15) CREATE_EXAMPLES_TEST(EX16) CREATE_EXAMPLES_TEST(EX17) +CREATE_EXAMPLES_TEST(EX18) +CREATE_EXAMPLES_TEST(EX19) +CREATE_EXAMPLES_TEST(EX20) TEST_F(DynTypeTests, ParseRandomGarbageTest) { /* @@ -223,6 +234,17 @@ TEST_F(DynTypeTests, MetaInfoTest) { ASSERT_EQ(0, rc); + auto entries = dynType_metaEntries(type); + struct meta_entry* entry = NULL; + size_t nbEntries = 0; + TAILQ_FOREACH(entry, entries, entries) { + nbEntries++; + ASSERT_STREQ("a", entry->name); + ASSERT_STREQ("t", entry->value); + } + ASSERT_EQ(1, nbEntries); + + const char *val = NULL; val = dynType_getMetaInfo(type, "a"); ASSERT_TRUE(val != NULL); @@ -399,6 +421,33 @@ TEST_F(DynTypeTests, EnumTest) { dynType_destroy(type); } + +TEST_F(DynTypeTests, PrintNullTypeTest) { + celix_autofree char* buf = nullptr; + size_t bufSize = 0; + celix_autoptr(FILE) result = open_memstream(&buf, &bufSize); + dynType_print(nullptr, result); + fflush(result); + ASSERT_STREQ("invalid type\n", buf); +} + +TEST_F(DynTypeTests, TextTest) { + dyn_type *type = NULL; + int rc = 0; + rc = dynType_parseWithStr("t", NULL, NULL, &type); + ASSERT_EQ(0, rc); + ASSERT_EQ(DYN_TYPE_TEXT, dynType_type(type)); + + char** val = nullptr; + rc = dynType_alloc(type, (void**)&val); + ASSERT_EQ(0, rc); + rc = dynType_text_allocAndInit(type, val, "test"); + ASSERT_EQ(0, rc); + ASSERT_STREQ("test", *val); + dynType_free(type, val); + dynType_destroy(type); +} + TEST_F(DynTypeTests, NrOfEntriesTest) { dyn_type *type = NULL; int rc = dynType_parseWithStr("{DD}", NULL, NULL, &type); diff --git a/libs/dfi/src/dyn_type.c b/libs/dfi/src/dyn_type.c index 474009205..be1363d68 100644 --- a/libs/dfi/src/dyn_type.c +++ b/libs/dfi/src/dyn_type.c @@ -59,11 +59,12 @@ static void dynType_printSequence(const char* name, const dyn_type* type, int de static void dynType_printSimple(const char* name, const dyn_type* type, int depth, FILE* stream); static void dynType_printEnum(const char* name, const dyn_type* type, int depth, FILE* stream); static void dynType_printTypedPointer(const char* name, const dyn_type* type, int depth, FILE* stream); +static void dynType_printText(const char* name, const dyn_type* type, int depth, FILE* stream); static void dynType_printDepth(int depth, FILE* stream); static void dynType_printTypes(const dyn_type* type, FILE* stream); -static void dynType_printComplexType(dyn_type* type, FILE* stream); -static void dynType_printSimpleType(dyn_type* type, FILE* stream); +static void dynType_printComplexType(const dyn_type* type, FILE* stream); +static void dynType_printSimpleType(const dyn_type* type, FILE* stream); static int dynType_parseText(FILE* stream, dyn_type* type); static int dynType_parseEnum(FILE* stream, dyn_type* type); @@ -534,7 +535,7 @@ const dyn_type* dynType_complex_dynTypeAt(const dyn_type* type, int index) { assert(type->type == DYN_TYPE_COMPLEX); assert(index >= 0); dyn_type* sub = type->complex.types[index]; - if (sub->type == DYN_TYPE_REF) { + while (sub->type == DYN_TYPE_REF) { sub = sub->ref.ref; } return sub; @@ -728,7 +729,7 @@ int dynType_sequence_increaseLengthAndReturnLastLoc(const dyn_type* type, void* const dyn_type* dynType_sequence_itemType(const dyn_type* type) { assert(type->type == DYN_TYPE_SEQUENCE); dyn_type *itemType = type->sequence.itemType; - if (itemType->type == DYN_TYPE_REF) { + while (itemType->type == DYN_TYPE_REF) { itemType = itemType->ref.ref; } return itemType; @@ -835,7 +836,7 @@ static unsigned short dynType_getOffset(const dyn_type* type, int index) { size_t dynType_size(const dyn_type* type) { const dyn_type* rType = type; - if (type->type == DYN_TYPE_REF) { + while (rType->type == DYN_TYPE_REF) { rType = type->ref.ref; } return rType->ffiType->size; @@ -848,7 +849,7 @@ int dynType_type(const dyn_type* type) { const dyn_type* dynType_typedPointer_getTypedType(const dyn_type* type) { assert(type->type == DYN_TYPE_TYPED_POINTER); dyn_type* typedType = type->typedPointer.typedType; - if (typedType->type == DYN_TYPE_REF) { + while (typedType->type == DYN_TYPE_REF) { typedType = typedType->ref.ref; } return typedType; @@ -857,22 +858,16 @@ const dyn_type* dynType_typedPointer_getTypedType(const dyn_type* type) { int dynType_text_allocAndInit(const dyn_type* type, void* textLoc, const char* value) { assert(type->type == DYN_TYPE_TEXT); - int status = 0; const char* str = strdup(value); char const** loc = textLoc; - if (str != NULL) { - *loc = str; - } else { - status = ERROR; + if (str == NULL) { celix_err_pushf("Cannot allocate memory for string"); + return MEM_ERROR; } - return status; + *loc = str; + return OK; } - - - - void dynType_print(const dyn_type *type, FILE *stream) { if (type != NULL) { dynType_printTypes(type, stream); @@ -893,9 +888,10 @@ static void dynType_printDepth(int depth, FILE *stream) { static void dynType_printAny(const char* name, const dyn_type* type, int depth, FILE *stream) { const dyn_type* toPrint = type; - if (toPrint->type == DYN_TYPE_REF) { + while (toPrint->type == DYN_TYPE_REF) { toPrint = toPrint->ref.ref; } + name = (name != NULL) ? name : "(unnamed)"; switch(toPrint->type) { case DYN_TYPE_COMPLEX : dynType_printComplex(name, toPrint, depth, stream); @@ -909,9 +905,14 @@ static void dynType_printAny(const char* name, const dyn_type* type, int depth, case DYN_TYPE_TYPED_POINTER : dynType_printTypedPointer(name, toPrint, depth, stream); break; + case DYN_TYPE_TEXT: + dynType_printText(name, toPrint, depth, stream); + break; +//LCOV_EXCL_START default : - fprintf(stream, "TODO Unsupported type %d\n", toPrint->type); + assert(0 && "Unexpected switch case. cannot print dyn type"); break; +//LCOV_EXCL_STOP } } @@ -990,6 +991,12 @@ static void dynType_printTypedPointer(const char* name, const dyn_type* type, in dynType_printAny(subName, type->typedPointer.typedType, depth + 1, stream); } +static void dynType_printText(const char* name, const dyn_type* type, int depth, FILE* stream) { + dynType_printDepth(depth, stream); + fprintf(stream, "%s: text type, size is %zu, alignment is %i, descriptor is '%c'.\n", + name, type->ffiType->size, type->ffiType->alignment, type->descriptor); +} + static void dynType_printTypes(const dyn_type* type, FILE* stream) { dyn_type* parent = type->parent; @@ -1006,7 +1013,7 @@ static void dynType_printTypes(const dyn_type* type, FILE* stream) { struct type_entry* entry = NULL; TAILQ_FOREACH(entry, &type->nestedTypesHead, entries) { dyn_type* toPrint = entry->type; - if (toPrint->type == DYN_TYPE_REF) { + while (toPrint->type == DYN_TYPE_REF) { toPrint = toPrint->ref.ref; } @@ -1018,7 +1025,7 @@ static void dynType_printTypes(const dyn_type* type, FILE* stream) { dynType_printSimpleType(toPrint, stream); break; default : - printf("TODO Print Type\n"); + printf("TODO Print Type %d\n", toPrint->type); break; } } @@ -1040,7 +1047,7 @@ static void dynType_printTypes(const dyn_type* type, FILE* stream) { } } -static void dynType_printComplexType(dyn_type *type, FILE *stream) { +static void dynType_printComplexType(const dyn_type *type, FILE *stream) { fprintf(stream, "type '%s': complex type, size is %zu, alignment is %i, descriptor is '%c'. fields:\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor); struct complex_type_entry *entry = NULL; @@ -1051,7 +1058,7 @@ static void dynType_printComplexType(dyn_type *type, FILE *stream) { fprintf(stream, "}\n"); } -static void dynType_printSimpleType(dyn_type *type, FILE *stream) { - fprintf(stream, "\ttype '%s': simple type, size is %zu, alignment is %i, descriptor is '%c'\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor); +static void dynType_printSimpleType(const dyn_type *type, FILE *stream) { + fprintf(stream, "type '%s': simple type, size is %zu, alignment is %i, descriptor is '%c'\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor); } diff --git a/libs/dfi/src/dyn_type_common.c b/libs/dfi/src/dyn_type_common.c index 385b14f78..885da8064 100644 --- a/libs/dfi/src/dyn_type_common.c +++ b/libs/dfi/src/dyn_type_common.c @@ -52,8 +52,8 @@ dyn_type* dynType_findType(dyn_type *type, char *name) { } ffi_type * dynType_ffiType(dyn_type * type) { - if (type->type == DYN_TYPE_REF) { - return type->ref.ref->ffiType; + while (type->type == DYN_TYPE_REF) { + type = type->ref.ref; } return type->ffiType; }