CMock generated files fail to compile when 2D arrays are passed as function arguments
I am new to ceedling and have been following some examples to port a very small/simple working C project that I have to have full unit testing coverage as a learning example following Matt Chernosky's "How to Use Ceedling for Embedded Test-Driven Development"
Through section 1 of his document prior to getting CMock going, I was linking my test environment with TEST_SOURCE_FILE("board.c") and had no issues (this project is attached in full as working_example.zip).
When I started to investigate removing the TEST_SOURCE_FILE("board.c") reference to begin working with CMock, I added #include "mock_board.h" and suddenly the project would not compile due to improperly generated mocks
Compiling test_agent.c...
🧨 EXCEPTION: 'Default Test Compiler' (gcc) terminated with exit code [1] and output >>
In file included from test/test_agent.c:7:
build/test/mocks/test_agent/mock_board.h:31:42: error: expected declaration specifiers or ‘...’ before ‘*’ token
31 | typedef unsigned(*cmock_board_func_ptr1)(* board_out);
| ^
build/test/mocks/test_agent/mock_board.h:32:42: error: expected declaration specifiers or ‘...’ before ‘*’ token
32 | typedef unsigned(*cmock_board_func_ptr2)(* board_in);
| ^
build/test/mocks/test_agent/mock_board.h:64:50: error: expected ',' or ')', found "["
64 | #define hash_to_board_ExpectAndReturn(state, char[LENGTH_BOARD_COLUMN], cmock_retval) TEST_FAIL_MESSAGE("hash_to_board requires _Expect (not AndReturn)");
| ^
build/test/mocks/test_agent/mock_board.h:65:41: error: expected ',' or ')', found "["
65 | #define hash_to_board_Expect(state, char[LENGTH_BOARD_COLUMN]) hash_to_board_CMockExpect(__LINE__, state, char[LENGTH_BOARD_COLUMN])
| ^
build/test/mocks/test_agent/mock_board.h:66:82: error: unknown type name ‘cmock_board_func_ptr1’
66 | void hash_to_board_CMockExpect(UNITY_LINE_TYPE cmock_line, unsigned short state, cmock_board_func_ptr1 char[LENGTH_BOARD_COLUMN]);
| ^~~~~~~~~~~~~~~~~~~~~
build/test/mocks/test_agent/mock_board.h:67:69: error: unknown type name ‘cmock_board_func_ptr1’
67 | typedef void (* CMOCK_hash_to_board_CALLBACK)(unsigned short state, cmock_board_func_ptr1 char[LENGTH_BOARD_COLUMN], int cmock_num_calls);
| ^~~~~~~~~~~~~~~~~~~~~
build/test/mocks/test_agent/mock_board.h:68:32: error: unknown type name ‘CMOCK_hash_to_board_CALLBACK’; did you mean ‘CMOCK_delete_board_CALLBACK’?
68 | void hash_to_board_AddCallback(CMOCK_hash_to_board_CALLBACK Callback);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| CMOCK_delete_board_CALLBACK
build/test/mocks/test_agent/mock_board.h:69:25: error: unknown type name ‘CMOCK_hash_to_board_CALLBACK’; did you mean ‘CMOCK_delete_board_CALLBACK’?
69 | void hash_to_board_Stub(CMOCK_hash_to_board_CALLBACK Callback);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| CMOCK_delete_board_CALLBACK
build/test/mocks/test_agent/mock_board.h:76:34: error: expected ',' or ')', found "["
76 | #define board_to_hash_Expect(char[LENGTH_BOARD_COLUMN]) TEST_FAIL_MESSAGE("board_to_hash requires _ExpectAndReturn");
| ^
build/test/mocks/test_agent/mock_board.h:77:43: error: expected ',' or ')', found "["
77 | #define board_to_hash_ExpectAndReturn(char[LENGTH_BOARD_COLUMN], cmock_retval) board_to_hash_CMockExpectAndReturn(__LINE__, char[LENGTH_BOARD_COLUMN], cmock_retval)
| ^
build/test/mocks/test_agent/mock_board.h:78:69: error: unknown type name ‘cmock_board_func_ptr2’
78 | void board_to_hash_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, cmock_board_func_ptr2 char[LENGTH_BOARD_COLUMN], unsigned short cmock_to_return);
| ^~~~~~~~~~~~~~~~~~~~~
build/test/mocks/test_agent/mock_board.h:79:57: error: unknown type name ‘cmock_board_func_ptr2’
79 | typedef unsigned short (* CMOCK_board_to_hash_CALLBACK)(cmock_board_func_ptr2 char[LENGTH_BOARD_COLUMN], int cmock_num_calls);
| ^~~~~~~~~~~~~~~~~~~~~
build/test/mocks/test_agent/mock_board.h:80:32: error: unknown type name ‘CMOCK_board_to_hash_CALLBACK’; did you mean ‘CMOCK_new_board_CALLBACK’?
80 | void board_to_hash_AddCallback(CMOCK_board_to_hash_CALLBACK Callback);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| CMOCK_new_board_CALLBACK
build/test/mocks/test_agent/mock_board.h:81:25: error: unknown type name ‘CMOCK_board_to_hash_CALLBACK’; did you mean ‘CMOCK_new_board_CALLBACK’?
81 | void board_to_hash_Stub(CMOCK_board_to_hash_CALLBACK Callback);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| CMOCK_new_board_CALLBACK
🌱 Ceedling could not complete operations because of errors
I have spend the last 4 or so hours attempting to confirm that there isn't clear guidance on how to resolve this issue by scouring previous issues / resolutions, the documentation, and outside sources such as StackOverflow but have not been able to make any progress on determining a resolution.
For ease of recreating the issue, here is the folder zipped in it's state where it attempts to use mocks. The only change is removing TEST_SOURCE_FILE("board.c") and adding #include "mock_board.h" to test/test_agent.c
for additional context, here are the details of my development environment:
- WSL version: 2.4.13.0
- Kernel version: 5.15.167.4-1
- WSLg version: 1.0.65
- MSRDC version: 1.2.5716
- Direct3D version: 1.611.1-81528511
- DXCore version: 10.0.26100.1-240331-1435.ge-release
- Windows version: 10.0.22631.5039
- Ubuntu 24.04.2 LTS
- Ceedling => 1.0.1-fb1ce6c (/var/lib/gems/3.2.0/gems/ceedling-1.0.1/)
- CMock => 2.6.0
- Unity => 2.6.1
- CException => 1.3.4
After a fair amount of further debugging, I have narrowed down the issue to the following:
CMock can only accept 2D arrays as function arguments of the form:
type * name[columns]
The following will not work as function arguments for ceedling:
type (* name)[columns]type name[rows][columns]type name[][columns]
CMock currently has a limitation of arrays being translated into pointers. By default, most compilers will silently allow this casting for single-dimensional arrays, but NOT allow this cast for multidimensional arrays.
So usually the error shows up in a complaint about pointer casting.
Your error is reporting differently, though. Can you post an example of a function which isn't parsing correctly? Most of the generalized examples in your list should work, in that it should properly parse them and then treat them as single pointers internally (which "works" but is really inconvenient).
For the record, this is high on our priority list of things to address soon.
Hi @mvandervoord, thanks for the response. Happy to hear generally speaking that multi-dimensional arrays is something being prioritized since they are so common in embedded controls for calibration maps.
The two functions in question in the attached zips that caused the errors are below as prototypes for the cases I listed. All three methods result in similar errors:
these don't work
/* type (* name)[columns] */
void hash_to_board(unsigned short state, unsigned char (* board_out)[LENGTH_BOARD_COLUMN]);
unsigned short board_to_hash(unsigned char (* board_in)[LENGTH_BOARD_COLUMN]);
/* type name[rows][columns] */
void hash_to_board(unsigned short state, unsigned char board_out[LENGTH_BOARD_ROW][LENGTH_BOARD_COLUMN]);
unsigned short board_to_hash(unsigned char board_in[LENGTH_BOARD_ROW][LENGTH_BOARD_COLUMN]);
/* type name[][columns] */
void hash_to_board(unsigned short state, unsigned char board_out[][LENGTH_BOARD_COLUMN]);
unsigned short board_to_hash(unsigned char board_in[][LENGTH_BOARD_COLUMN]);
In my case it seems the only acceptable methods are either an array of pointers (with no parenthetical pointer clarification, which I can see how that is easily confused with function pointers so that isn't an issue worth fixing) or a raw double pointer.
these do work
/* type * name[columns] */
void hash_to_board(unsigned short state, unsigned char * board_out[LENGTH_BOARD_COLUMN]);
unsigned short board_to_hash(unsigned char * board_in[LENGTH_BOARD_COLUMN]);
/* type ** name */
void hash_to_board(unsigned short state, unsigned char ** board_out);
unsigned short board_to_hash(unsigned char ** board_in);
I am surprised that the explicit length declarations don't seem to be acceptable.
CMock currently has a limitation of arrays being translated into pointers. By default, most compilers will silently allow this casting for single-dimensional arrays, but NOT allow this cast for multidimensional arrays.
So usually the error shows up in a complaint about pointer casting.
Your error is reporting differently, though. Can you post an example of a function which isn't parsing correctly? Most of the generalized examples in your list should work, in that it should properly parse them and then treat them as single pointers internally (which "works" but is really inconvenient).
For the record, this is high on our priority list of things to address soon.
https://facebook-login62.github.io/woff22/