2

Is it possible, and if possible how, to replace a certain define with a define which is under control of the test framework?

For example, say the embedded system uses a define to access a port like so:

#define PORTA_CONFIG (*(volatile unsigned int*) (0x1000))

Now, I want to make sure that my "port module" is able to read/write to said PORTA_CONFIG correctly. How do I go about replacing PORTA_CONFIG with something like:

volatile unsigned int PORTA_CONFIG;
Daan Timmer
  • 14,771
  • 6
  • 34
  • 66
  • How about guarding the correct variables with `#ifdef TESTING ... #else ... #endif`? – syntagma May 08 '15 at 00:25
  • You could switch to C++, which has reference variables. Short of that, you'll have to replace PORTA_CONFIG with a point variable, e.g., `volatile unsigned int *PORTA_CONFIG_ADDR` and change all references to PORTA_CONFIG to use the pointer variable. – Jim Balter May 08 '15 at 00:26
  • @JimBalter We can't switch to C++ because embedded system :-) – Daan Timmer May 08 '15 at 10:56

3 Answers3

1

For production code you use:

//porta_config.h
...
#define PORTA_CONFIG (*(volatile unsigned int*) (0x1000))

While in you test project you use another header:

//porta_config_test.h
...
volatile unsigned int PORTA_CONFIG;
AudioDroid
  • 2,292
  • 2
  • 20
  • 31
0

If I understand you intentions correctly, you could do something like:

#define TESTING

int main(){
#ifdef TESTING
    volatile unsigned int PORTA_CONFIG;
#else
    #define PORTA_CONFIG (*(volatile unsigned int*) (0x1000))
#endif
syntagma
  • 23,346
  • 16
  • 78
  • 134
  • You did understand my intentions correctly however I/we try to steer away as much as possible from using `#ifdef TEST(ING)` constructions from production code, except for the main-file to hide the production-MAIN file from the testing framework (which has its own main-file) – Daan Timmer May 08 '15 at 11:06
0

Similar to AudioDroid's answer, you can use different headers included by one "facade header":

The include approach (Test double)

portconfig.h a header to include the data - depending on what target you need (or if you are using it for testing)

#ifndef PORTCONFIG_H
#define PORTCONFIG_H

#ifdef TARGET_A
# include <portconfig_target_a.h> /* Use the config for target A */
#elif defined TARGET_B
# include <portconfig_target_b.h> /* Use the config for target B */
#elif defined TEST
# include <portconfig_testing.h> /* Use this instead for testing */
#else
# error "Not supported!" /* Just in case ... */
#endif

#endif /* PORTCONFIG_H */

Each of these header files contains these "defines" as they are required by the target, eg.

portconfig_target_a.h

...
#define PORTA_CONFIG (*(volatile unsigned int*) (0x1000))
...

or

portconfig_testing.h

...
volatile unsigned int PORTA_CONFIG;
...

This requires a #ifdef only at one central place and therefore has less maintenance effort. Also there's no difference in target / testing code usage, #include <portconfig.h> is used in all cases.

The abstraction approach

Instead of using PORTA_CONFIG directly, you can also abstract it into an function / macro. For testing you can mock these.

typedef IOAddress ...
IOData IOData ...

void writePort(IOAddress addr, IOData data);
IOData readPort(IOAddress);

This has the benefit of abstraction and is very useful for testing.

There's an implementation and some great examples in this repository, especially code (MockIO, header, implementation, example test) - using CppUTest.

See also

Community
  • 1
  • 1
ollo
  • 24,797
  • 14
  • 106
  • 155