ThrowTheSwitch / Ceedling

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

How to mock macros? #929

Open rickymohk opened 1 month ago

rickymohk commented 1 month 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 1 month 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 1 month 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.