Skip to content

Commit

Permalink
Added the tips from Micha into the readme
Browse files Browse the repository at this point in the history
  • Loading branch information
meekrosoft committed Jul 20, 2013
1 parent 3612b9e commit 2afa727
Showing 1 changed file with 105 additions and 1 deletion.
106 changes: 105 additions & 1 deletion README.md
Expand Up @@ -150,7 +150,27 @@ fakes in the setup function of your test suite.
RESET_FAKE(DISPLAY_get_line_capacity);
RESET_FAKE(DISPLAY_get_line_insert_index);
}


You might want to define a macro to do this:

```
/* List of fakes used by this unit tester */
#define FFF_FAKES_LIST(FAKE) \
FAKE(DISPLAY_init) \
FAKE(DISPLAY_clear) \
FAKE(DISPLAY_output_message) \
FAKE(DISPLAY_get_line_capacity) \
FAKE(DISPLAY_get_line_insert_index)
void setup()
{
/* Register resets */
FFF_FAKES_LIST(RESET_FAKE);
/* reset common FFF internal structures */
FFF_RESET_HISTORY();
}
```

## Call history
Say you want to test that a function calls functionA, then functionB, then
Expand Down Expand Up @@ -304,6 +324,90 @@ In case your project uses a C99 compliant C compiler you can even combine all th
ASSERT_EQ(t.min, 05);
}

## How do I fake a function with a function pointer parameter?
Using FFF to stub functions that have function pointer parameter can cause problems when trying to stub them. Presented here is an example how to deal with this situation.

If you need to stub a function that has a function pointer parameter, e.g. something like:

```
/* timer.h */
typedef int timer_handle;
extern int timer_start(timer_handle handle, long delay, void (*cb_function) (int arg), int arg);
```

Then creating a fake like below will horribly fail when trying to compile because the FFF macro will internally expand into an illegal variable ```int (*)(int) arg2_val```.

```
/* The fake, attempt one */
FAKE_VALUE_FUNC(int,
timer_start,
timer_handle,
long,
void (*) (int argument),
int);
```

The solution to this problem is to create a bridging type that needs only to be visible in the unit tester. The fake will use that intermediate type. This way the compiler will not complain because the types match.

```
/* Additional type needed to be able to use callback in FFF */
typedef void (*timer_cb) (int argument);
/* The fake, attempt two */
FAKE_VALUE_FUNC(int,
timer_start,
timer_handle,
long,
timer_cb,
int);
```

Here are some ideas how to create a test case with callbacks.

```
/* Unit test */
TEST_F(FFFTestSuite, test_fake_with_function_pointer)
{
int cb_timeout_called = 0;
int result = 0;
void cb_timeout(int argument)
{
cb_timeout_called++;
}
int timer_start_custom_fake(timer_handle handle,
long delay,
void (*cb_function) (int arg),
int arg)
{
if (cb_function) cb_function(arg);
return timer_start_fake.return_val;
}
/* given the custom fake for timer_start */
timer_start_fake.return_val = 33;
timer_start_fake.custom_fake = timer_start_custom_fake;
/* when timer_start is called
* (actually you would call your own function-under-test
* that would then call the fake function)
*/
result = timer_start(10, 100, cb_timeout, 55);
/* then the timer_start fake must have been called correctly */
ASSERT_EQ(result, 33);
ASSERT_EQ(timer_start_fake.call_count, 1);
ASSERT_EQ(timer_start_fake.arg0_val, 10);
ASSERT_EQ(timer_start_fake.arg1_val, 100);
ASSERT_EQ(timer_start_fake.arg2_val, cb_timeout); /* callback provided by unit tester */
ASSERT_EQ(timer_start_fake.arg3_val, 55);
/* and ofcourse our custom fake correctly calls the registered callback */
ASSERT_EQ(cb_timeout_called, 1);
}
```

## Find out more...

Look under the examlples directory for full length examples in both C and C++.
Expand Down

0 comments on commit 2afa727

Please sign in to comment.