-
-
Notifications
You must be signed in to change notification settings - Fork 295
Description
CMock erroneously assumes all function arguments are pointers under specific conditions
Issue Description
CMock seems to get extremely confused by typedefs which are arrays of other typedefs. The net result seems to be that all function arguments are interpreted as array types IGNORING THE treat_as TYPES IN THE project.yml FILE
Reproduceable Example Project
as a minimal example to reproduce, execute the following:
$ ceedling new treat_as_issue_demo
$ cd treat_as_issue_demo/
$ ceedling module:create[demo]
$ ceedling module:create[issue]Then edit src/issue.h to be as follows:
#ifndef ISSUE_H
#define ISSUE_H
typedef float F32;
typedef F32 F32ArrType[2];
void issue_function(F32, F32);
void another_function(F32ArrType, F32);
#endif // ISSUE_Hand add #include "mock_issue.h" to test/test_demo.c
#ifdef TEST
#include "unity.h"
#include "demo.h"
#include "mock_issue.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_demo_NeedToImplement(void)
{
TEST_IGNORE_MESSAGE("Need to Implement demo");
}
#endif // TESTFinally, edit the project.yml to have it's cmock section include the following:
:treat_as: # optionally add additional types to map custom types
uint8: HEX8
uint16: HEX16
uint32: UINT32
int8: INT8
bool: UINT8
F32: FLOAT
:treat_as_array: # hint to cmock that these types are pointers to something
F32ArrTypeDangerous Implications
If you were to do the same but with an unsigned integer type, CEEDLING WOULD COMPILE WITHOUT SHOWING THE USER WARNINGS because it would implicitly case the U32 arg to a pointer with a warning, and ceedling would suppress the warning under successful compilation.
the generated mock file
The function has a non-pointer arg, but does an array memory compare on arg2
void another_function(F32ArrType cmock_arg1, F32 cmock_arg2)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_another_function_CALL_INSTANCE* cmock_call_instance;
UNITY_SET_DETAIL(CMockString_another_function);
cmock_call_instance = (CMOCK_another_function_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.another_function_CallInstance);
Mock.another_function_CallInstance = CMock_Guts_MemNext(Mock.another_function_CallInstance);
if (Mock.another_function_IgnoreBool)
{
UNITY_CLR_DETAILS();
return;
}
if (!Mock.another_function_CallbackBool &&
Mock.another_function_CallbackFunctionPointer != NULL)
{
Mock.another_function_CallbackFunctionPointer(cmock_arg1, cmock_arg2, Mock.another_function_CallbackCalls++);
UNITY_CLR_DETAILS();
return;
}
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);
cmock_line = cmock_call_instance->LineNumber;
if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)
UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);
if (cmock_call_instance->CallOrder < GlobalVerifyOrder)
UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);
{
UNITY_SET_DETAILS(CMockString_another_function,CMockString_cmock_arg1);
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(cmock_call_instance->Expected_cmock_arg1), (void*)(cmock_arg1), sizeof(F32ArrType), cmock_line, CMockStringMismatch);
}
{
UNITY_SET_DETAILS(CMockString_another_function,CMockString_cmock_arg2);
if (cmock_call_instance->Expected_cmock_arg2 == NULL)
{ UNITY_TEST_ASSERT_NULL(cmock_arg2, cmock_line, CMockStringExpNULL); }
else
{ UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(cmock_call_instance->Expected_cmock_arg2, cmock_arg2, 1, cmock_line, CMockStringMismatch); }
}
if (Mock.another_function_CallbackFunctionPointer != NULL)
{
Mock.another_function_CallbackFunctionPointer(cmock_arg1, cmock_arg2, Mock.another_function_CallbackCalls++);
}
UNITY_CLR_DETAILS();
}The structs that are generated are also assuming the F32 is a pointer
typedef struct _CMOCK_another_function_CALL_INSTANCE
{
UNITY_LINE_TYPE LineNumber;
int CallOrder;
F32ArrType* Expected_cmock_arg1;
F32* Expected_cmock_arg2;
} CMOCK_another_function_CALL_INSTANCE;What if it wasn't a typedef of a typedef?
We can fix this problem with only changes to the header file being mocked (leaving the project.yml as is)
#ifndef ISSUE_H
#define ISSUE_H
typedef float F32ArrType[2];
void issue_function(float, float);
void another_function(F32ArrType, float);
#endif // ISSUE_H