Skip to content

Commit

Permalink
Variadic macro extensions to the FFF
Browse files Browse the repository at this point in the history
See header comment in fff.h for details -- summary extracted below:

Return value macros:

SET_RETURN_VAL_SEQ(function_name, ...)
Accepts a raw list of appropriately typed values
SET_RETURN_VAL(function_name, value)
Provided for API consistency

Assertion macros:

TEST_ASSERT_CALLS(function_name, expected_call_count)

TEST_ASSERT_CALLED(function_name)
 Only one call made to the function.

TEST_ASSERT_NOT_CALLED(function_name)
 No calls made to the function.

TEST_ASSERT_CALL(function_name, ...parameters)
 Only one call made to the function with the specified parameter values.

TEST_ASSERT_LAST_CALL(function_name, ...parameters)
 The final call to this function was made with the specified parameter values.

TEST_ASSERT_ANY_CALL(function_name, ...parameters)
 At least one call was made with the specified parameter values.

TEST_ASSERT_NO_CALL(function_name, ...parameters)
 No calls were made with the specified parameter values.

TEST_ASSERT_NTH_CALL(function_name, call_index, ...parameters)
 A specified invocation of the function used the specified parameter values.

<<Amendment 1>>
Added unit tests.
Added TEST_ASSERT_CALL(...), as couldn't get optional parameter verification for
TEST_ASSERT_CALLED to work in c99 mode.

<<Amendment 2>>
Updated generator.
Function name changes for consistency.
Initial documentation updates.

<<Amendment 3>>
FFF_RETURN: Made array declaration static to allow use in a fixture setup method

<<Amendment 4>>
FFF_RETURN
Reverted static array declaration as it prevented some types of initialisation.
Reformulated macro to use dedicated struct member for single values while still
allowing macro invocation to be prefixed with `static` keyboard when used
outside the test body.
  • Loading branch information
Cormac Cannon committed Apr 12, 2018
1 parent ef24c19 commit d6d06fd
Show file tree
Hide file tree
Showing 6 changed files with 1,230 additions and 182 deletions.
125 changes: 119 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ FAKE_VOID_FUNC(DISPLAY_init);
And the unit test might look something like this:
```c
TEST_F(GreeterTests, init_initialises_display)
{
UI_init();
FFF_ASSERT_CALLS(DISPLAY_init, 1);
}
```

... or ...

```c
TEST_F(GreeterTests, init_initialises_display)
{
Expand Down Expand Up @@ -85,6 +95,17 @@ FAKE_VOID_FUNC(DISPLAY_output, char *);

And the unit test might look something like this:

```c
TEST_F(UITests, write_line_outputs_lines_to_display)
{
char msg[] = "helloworld";
UI_write_line(msg);
FFF_ASSERT(DISPLAY_output, msg);
}
```
... or ...
```c
TEST_F(UITests, write_line_outputs_lines_to_display)
{
Expand All @@ -95,7 +116,6 @@ TEST_F(UITests, write_line_outputs_lines_to_display)
}
```

There is no more magic here, the `FAKE_VOID_FUNC` works as in the
previous example. The number of arguments that the function takes is calculated,
and the macro arguments following the function name defines the argument
Expand All @@ -104,6 +124,20 @@ type (a char pointer in this example).
A variable is created for every argument in the form
`"function_name"fake.argN_val`

### Variadic argument assertions

These are a recent addition to the framework. The range of available assertions is
listed in the cheat sheet at the foot of this page. The assertions use a simple
assertion macro defined internally. To override with a macro from some test framework,
do the following in some header you include in all your tests:

```c
// my_test_framework_header.h
...
#define _FFF_ASSERT_EQ_MSG(expected, actual, message) MY_CUSTOM_ASSERTION(expected, actual, message)
#include "fff.h"
...
```
## Return values
Expand All @@ -128,6 +162,21 @@ FAKE_VALUE_FUNC(unsigned int, DISPLAY_get_line_insert_index);
And the unit test might look something like this:
```c
TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
// given
FFF_RETURN(DISPLAY_get_line_insert_index,1);
char msg[] = "helloworld";
// when
UI_write_line(msg);
// then
FFF_ASSERT_NOT_CALLED(DISPLAY_clear);
}
```
... or ...
```c
TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
Expand All @@ -154,7 +203,34 @@ you would use a syntax like this:
FAKE_VALUE_FUNC(double, pow, double, double);
```
*N.B.* When using the variadic form (i.e. `FFF_RETURN(FN, ...)`), the hidden value sequence array
is declared locally by default. If you want to set a return sequence in a function other than
the test body (e.g. in a fixture setup method or helper function used in multiple tests), you'll
need to prefix the macro invocation with the `static` keyword. e.g.

```c
void setup(void)
{
// given
static FFF_RETURN(DISPLAY_get_line_insert_index, 1, 2, 3);
}

TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
...
//Some test logic exercising DISPLAY_get_line_insert_index
...
}

TEST_F(UITests, when_empty_lines_write_line_bla)
{
...
//Some more test logic exercising DISPLAY_get_line_insert_index
...
}
```
The static keyword is not necessary when specifying a single value, as the macro uses the dedicated struct member in this case.
## Resetting a fake
Expand Down Expand Up @@ -226,6 +302,18 @@ They are reset by calling `FFF_RESET_HISTORY();`
The framework will by default store the arguments for the last ten calls made
to a fake function.

```c
TEST_F(FFFTestSuite, when_fake_func_called_then_arguments_captured_in_history)
{
voidfunc2('g', 'h');
voidfunc2('i', 'j');
FFF_ASSERT_NTH(voidfunc2, 1, 'g', 'h');
FFF_ASSERT_NTH(voidfunc2, 2, 'i', 'j');
}
```
... or ...
```c
TEST_F(FFFTestSuite, when_fake_func_called_then_arguments_captured_in_history)
{
Expand Down Expand Up @@ -288,6 +376,21 @@ with for the fake function. It is probably easier to describe with an example:
// faking "long longfunc();"
FAKE_VALUE_FUNC(long, longfunc0);

TEST_F(FFFTestSuite, return_value_sequences_exhausted)
{
FFF_RETURN(longfunc0, myReturnVals, 3, 7, 9);
ASSERT_EQ(3, longfunc0());
ASSERT_EQ(7, longfunc0());
ASSERT_EQ(9, longfunc0());
ASSERT_EQ(9, longfunc0());
ASSERT_EQ(9, longfunc0());
}
```
... or ...
```c
// faking "long longfunc();"
FAKE_VALUE_FUNC(long, longfunc0);
TEST_F(FFFTestSuite, return_value_sequences_exhausted)
{
long myReturnVals[3] = { 3, 7, 9 };
Expand Down Expand Up @@ -579,8 +682,18 @@ So whats the point?
## Cheat Sheet
| Macro | Description | Example |
|-------|-------------|---------|
| FAKE_VOID_FUNC(fn [,arg_types*]); | Define a fake function named fn returning void with n arguments | FAKE_VOID_FUNC(DISPLAY_output_message, const char*); |
| FAKE_VALUE_FUNC(return_type, fn [,arg_types*]); | Define a fake function returning a value with type return_type taking n arguments | FAKE_VALUE_FUNC(int, DISPLAY_get_line_insert_index); |
| RESET_FAKE(fn); | Reset the state of fake function called fn | RESET_FAKE(DISPLAY_init); |
| Macro | Description | Example |
|-------------------------------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------|
| FAKE_VOID_FUNC(fn [,arg_types*]); | Define a fake function named fn returning void with n arguments | FAKE_VOID_FUNC(DISPLAY_output_message, const char*); |
| FAKE_VALUE_FUNC(return_type, fn [,arg_types*]); | Define a fake function returning a value with type return_type taking n arguments | FAKE_VALUE_FUNC(int, DISPLAY_get_line_insert_index); |
| RESET_FAKE(fn); | Reset the state of fake function called fn | RESET_FAKE(DISPLAY_init); |
| FFF_RETURN(fn, ...return_value(s)*); | Set one or more return values (final value repeated if calls > values) | FFF_RETURN(DISPLAY_init, 1, 2, 3); |
| FFF_ASSERT_CALLED(fn); | Assert that a function was called once and only once. | FFF_ASSERT_CALLED(DISPLAY_init); |
| FFF_ASSERT_NOT_CALLED(fn); | Assert that a function was not called. | FFF_ASSERT_NOT_CALLED(DISPLAY_init); |
| FFF_ASSERT_CALLS(fn, call_count); | Assert that a function was called the specified number of times. | FFF_ASSERT_CALLS(DISPLAY_init, 3); |
| FFF_ASSERT(fn, ...arg_value(s)) | Assert that a function was called only once with the specified argument values. | FFF_ASSERT(DISPLAY_output_message, my_message_ptr); |
| FFF_ASSERT_LAST(fn, ...arg_value(s)) | Assert that the last call to a function had the specified argument values. | FFF_ASSERT_LAST(DISPLAY_output_message, my_message_ptr); |
| FFF_ASSERT_ANY(fn, ...arg_value(s)) | Assert that any call to a function had the specified argument values. | FFF_ASSERT_ANY(DISPLAY_output_message, my_message_ptr); |
| FFF_ASSERT_NONE(fn, ...arg_value(s)) | Assert that no calls to a function had the specified argument values. | FFF_ASSERT_NONE(DISPLAY_output_message, my_message_ptr); |
*N.B.* All of the function argument assertions support partial specification of arguments. I.e. Given a function taking 3 args, you may just specify the first argument for verification. Any arguments that are specified must be specified from left to right however. i.e. it is possibly to specify arguments 0 and 1, but not arguments 0 and 2 (ignoring the value of 1).
Loading

0 comments on commit d6d06fd

Please sign in to comment.