ThrowTheSwitch / Ceedling

Ruby-based unit testing and build system for C projects
http://throwtheswitch.org
Other
596 stars 246 forks source link

How to mock macros? #929

Closed rickymohk closed 12 hours ago

rickymohk commented 2 months ago

I am working on an IAR project. When my tests encounter micros accessing registers, segmentation fault will be raised. Are those macros mockable?

e.g.

stm32l4xx.h

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

source code file

#include "stm32l4xx.h"

void foo(void)
{
    WRITE_REG(some_register_address,some_value);
}

test code file

#include "mock_stm32l4xx.h"

void test_foo(void)
{
    foo();   //segmentation fault
}
Letme commented 2 months ago

Macros are not mockable. Segmentation fault means you are accessing something that cannot be accessed in most cases which is a strange error to get from the target or simulator.

You mock low level registers as variables in a way that you create a stm32l4xx_test.h as "CPU" and then point typeDefs to the volatile variable instead of fixed addresses.

mvandervoord commented 2 months ago

Here are some ideas towards working with registers:

https://vandervoord.net/blog/2015/5/24/unit-test-how-registers https://vandervoord.net/blog/2015/5/24/unit-test-how-faking-changing-registers https://vandervoord.net/blog/2015/5/24/unit-test-how-verifying-multiple-register-writes

To mock low-level API calls which are macros, you can perform a similar trick.

#ifdef TEST
void WRITE_REG(uint32_t REG, uint32_t VAL);
#else 
#define WRITE_REG(REG, VAL)   ((REG) = (VAL))
#endif

You never need to actually create the function in the top part. It provides a mockable interface for CMock to use. During release builds, the top portion is ignored and the macro is used.

mkarlesky commented 12 hours ago

Hi, @rickymohk. Please follow @mvandervoord's suggestions. The approaches he linked are the best options. I have mocked macros using these techniques (basically a macro can look like a mockable function using the approaches Mark pointed you to). On the backlog is writing up a Ceedling cookbook to explain the code and configuration needed for use cases like this. Eventually we'll get that pulled together and this question will be in there. For housekeeping, I am going to close this issue. If you need more support, please reply in the closed issue.