Code Monkey home page Code Monkey logo

fff's Introduction

Fake Function Framework (fff)


Build Status Build status Gitter chat

A Fake Function Framework for C

fff is a micro-framework for creating fake C functions for tests. Because life is too short to spend time hand-writing fake functions for testing.

Running all tests

Linux / MacOS

To run all the tests and sample apps, simply call $ buildandtest. This script will call down into CMake with the following:

cmake -B build -DFFF_GENERATE=ON -DFFF_UNIT_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Hello Fake World!

Say you are testing an embedded user interface and you have a function that you want to create a fake for:

// UI.c
...
void DISPLAY_init();
...

Here's how you would define a fake function for this in your test suite:

// test.c(pp)
#include "fff.h"
DEFINE_FFF_GLOBALS;
FAKE_VOID_FUNC(DISPLAY_init);

And the unit test might look something like this:

TEST_F(GreeterTests, init_initialises_display)
{
    UI_init();
    ASSERT_EQ(DISPLAY_init_fake.call_count, 1);
}

So what has happened here? The first thing to note is that the framework is header only, all you need to do to use it is download fff.h and include it in your test suite.

The magic is in the FAKE_VOID_FUNC. This expands a macro that defines a function returning void which has zero arguments. It also defines a struct "function_name"_fake which contains all the information about the fake. For instance, DISPLAY_init_fake.call_countis incremented every time the faked function is called.

Under the hood it generates a struct that looks like this:

typedef struct DISPLAY_init_Fake {
    unsigned int call_count;
    unsigned int arg_history_len;
    unsigned int arg_histories_dropped;
    void(*custom_fake)();
} DISPLAY_init_Fake;
DISPLAY_init_Fake DISPLAY_init_fake;

Capturing Arguments

Ok, enough with the toy examples. What about faking functions with arguments?

// UI.c
...
void DISPLAY_output(char * message);
...

Here's how you would define a fake function for this in your test suite:

FAKE_VOID_FUNC(DISPLAY_output, char *);

And the unit test might look something like this:

TEST_F(UITests, write_line_outputs_lines_to_display)
{
    char msg[] = "helloworld";
    UI_write_line(msg);
    ASSERT_EQ(DISPLAY_output_fake.call_count, 1);
    ASSERT_EQ(strncmp(DISPLAY_output_fake.arg0_val, msg, 26), 0);
}

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 type (a char pointer in this example).

A variable is created for every argument in the form "function_name"fake.argN_val

Return Values

When you want to define a fake function that returns a value, you should use the FAKE_VALUE_FUNC macro. For instance:

// UI.c
...
unsigned int DISPLAY_get_line_capacity();
unsigned int DISPLAY_get_line_insert_index();
...

Here's how you would define fake functions for these in your test suite:

FAKE_VALUE_FUNC(unsigned int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC(unsigned int, DISPLAY_get_line_insert_index);

And the unit test might look something like this:

TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
    // given
    DISPLAY_get_line_insert_index_fake.return_val = 1;
    char msg[] = "helloworld";
    // when
    UI_write_line(msg);
    // then
    ASSERT_EQ(DISPLAY_clear_fake.call_count, 0);
}

Of course you can mix and match these macros to define a value function with arguments, for instance to fake:

double pow(double base, double exponent);

you would use a syntax like this:

FAKE_VALUE_FUNC(double, pow, double, double);

Resetting a Fake

Good tests are isolated tests, so it is important to reset the fakes for each unit test. All the fakes have a reset function to reset their arguments and call counts. It is good practice is to call the reset function for all the fakes in the setup function of your test suite.

void setup()
{
    // Register resets
    RESET_FAKE(DISPLAY_init);
    RESET_FAKE(DISPLAY_clear);
    RESET_FAKE(DISPLAY_output_message);
    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 functionA again, how would you do that? Well fff maintains a call history so that it is easy to assert these expectations.

Here's how it works:

FAKE_VOID_FUNC(voidfunc2, char, char);
FAKE_VALUE_FUNC(long, longfunc0);

TEST_F(FFFTestSuite, calls_in_correct_order)
{
    longfunc0();
    voidfunc2();
    longfunc0();

    ASSERT_EQ(fff.call_history[0], (void *)longfunc0);
    ASSERT_EQ(fff.call_history[1], (void *)voidfunc2);
    ASSERT_EQ(fff.call_history[2], (void *)longfunc0);
}

They are reset by calling FFF_RESET_HISTORY();

Default Argument History

The framework will by default store the arguments for the last ten calls made to a fake function.

TEST_F(FFFTestSuite, when_fake_func_called_then_arguments_captured_in_history)
{
    voidfunc2('g', 'h');
    voidfunc2('i', 'j');
    ASSERT_EQ('g', voidfunc2_fake.arg0_history[0]);
    ASSERT_EQ('h', voidfunc2_fake.arg1_history[0]);
    ASSERT_EQ('i', voidfunc2_fake.arg0_history[1]);
    ASSERT_EQ('j', voidfunc2_fake.arg1_history[1]);
}

There are two ways to find out if calls have been dropped. The first is to check the dropped histories counter:

TEST_F(FFFTestSuite, when_fake_func_called_max_times_plus_one_then_one_argument_history_dropped)
{
    int i;
    for(i = 0; i < 10; i++)
    {
        voidfunc2('1'+i, '2'+i);
    }
    voidfunc2('1', '2');
    ASSERT_EQ(1u, voidfunc2_fake.arg_histories_dropped);
}

The other is to check if the call count is greater than the history size:

ASSERT(voidfunc2_fake.arg_history_len < voidfunc2_fake.call_count);

The argument histories for a fake function are reset when the RESET_FAKE function is called

User Defined Argument History

If you wish to control how many calls to capture for argument history you can override the default by defining it before include the fff.h like this:

// Want to keep the argument history for 13 calls
#define FFF_ARG_HISTORY_LEN 13
// Want to keep the call sequence history for 17 function calls
#define FFF_CALL_HISTORY_LEN 17

#include "../fff.h"

Function Return Value Sequences

Often in testing we would like to test the behaviour of sequence of function call events. One way to do this with fff is to specify a sequence of return values 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)
{
    long myReturnVals[3] = { 3, 7, 9 };
    SET_RETURN_SEQ(longfunc0, myReturnVals, 3);
    ASSERT_EQ(myReturnVals[0], longfunc0());
    ASSERT_EQ(myReturnVals[1], longfunc0());
    ASSERT_EQ(myReturnVals[2], longfunc0());
    ASSERT_EQ(myReturnVals[2], longfunc0());
    ASSERT_EQ(myReturnVals[2], longfunc0());
}

By specifying a return value sequence using the SET_RETURN_SEQ macro, the fake will return the values given in the parameter array in sequence. When the end of the sequence is reached the fake will continue to return the last value in the sequence indefinitely.

Custom Return Value Delegate

You can specify your own function to provide the return value for the fake. This is done by setting the custom_fake member of the fake. Here's an example:

#define MEANING_OF_LIFE 42
long my_custom_value_fake(void)
{
    return MEANING_OF_LIFE;
}
TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_return_value)
{
    longfunc0_fake.custom_fake = my_custom_value_fake;
    long retval = longfunc0();
    ASSERT_EQ(MEANING_OF_LIFE, retval);
}

Custom Return Value Delegate Sequences

Say you have a function with an out parameter, and you want it to have a different behaviour on the first three calls, for example: set the value 'x' to the out parameter on the first call, the value 'y' to the out parameter on the second call, and the value 'z' to the out parameter on the third call. You can specify a sequence of custom functions to a non-variadic function using the SET_CUSTOM_FAKE_SEQ macro. Here's an example:

void voidfunc1outparam_custom_fake1(char *a)
{
    *a = 'x';
}

void voidfunc1outparam_custom_fake2(char *a)
{
    *a = 'y';
}

void voidfunc1outparam_custom_fake3(char *a)
{
    *a = 'z';
}

TEST_F(FFFTestSuite, custom_fake_sequence_not_exausthed)
{
    void (*custom_fakes[])(char *) = {voidfunc1outparam_custom_fake1,
                                      voidfunc1outparam_custom_fake2,
                                      voidfunc1outparam_custom_fake3};
    char a = 'a';

    SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3);

    voidfunc1outparam(&a);
    ASSERT_EQ('x', a);
    voidfunc1outparam(&a);
    ASSERT_EQ('y', a);
    voidfunc1outparam(&a);
    ASSERT_EQ('z', a);
}

The fake will call your custom functions in the order specified by the SET_CUSTOM_FAKE_SEQ macro. When the last custom fake is reached the fake will keep calling the last custom fake in the sequence. This macro works much like the SET_RETURN_SEQ macro.

Return Value History

Say you have two functions f1 and f2. f2 must be called to release some resource allocated by f1, but only in the cases where f1 returns zero. f1 could be pthread_mutex_trylock and f2 could be pthread_mutex_unlock. fff will save the history of returned values so this can be easily checked, even when you use a sequence of custom fakes. Here's a simple example:

TEST_F(FFFTestSuite, return_value_sequence_saved_in_history)
{
    long myReturnVals[3] = { 3, 7, 9 };
    SET_RETURN_SEQ(longfunc0, myReturnVals, 3);
    longfunc0();
    longfunc0();
    longfunc0();
    ASSERT_EQ(myReturnVals[0], longfunc0_fake.return_val_history[0]);
    ASSERT_EQ(myReturnVals[1], longfunc0_fake.return_val_history[1]);
    ASSERT_EQ(myReturnVals[2], longfunc0_fake.return_val_history[2]);
}

You access the returned values in the return_val_history field.

Variadic Functions

You can fake variadic functions using the macros FAKE_VALUE_FUNC_VARARG and FAKE_VOID_FUNC_VARARG. For instance:

FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE *, const char*, ...);

In order to access the variadic parameters from a custom fake function, declare a va_list parameter. For instance, a custom fake for fprintf() could call the real fprintf() like this:

int fprintf_custom(FILE *stream, const char *format, va_list ap) {
  if (fprintf0_fake.return_val < 0) // should we fail?
    return fprintf0_fake.return_val;
  return vfprintf(stream, format, ap);
}

Just like return value delegates, you can also specify sequences for variadic functions using SET_CUSTOM_FAKE_SEQ. See the test files for examples.

Common Questions

How do I specify calling conventions for my fake functions?

fff has a limited capability for enabling specification of Microsoft's Visual C/C++ calling conventions, but this support must be enabled when generating fff's header file fff.h.

ruby fakegen.rb --with-calling-conventions > fff.h

By enabling this support, all of fff's fake function scaffolding will necessitate the specification of a calling convention, e.g. __cdecl for each VALUE or VOID fake.

Here are some basic examples: take note that the placement of the calling convention being specified is different depending on whether the fake is a VOID or VALUE function.

FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
FAKE_VALUE_FUNC(long, __cdecl, longfunc0);

How do I fake a function that returns a value by reference?

The basic mechanism that fff provides you in this case is the custom_fake field described in the Custom Return Value Delegate example above.

You need to create a custom function (e.g. getTime_custom_fake) to produce the output optionally by use of a helper variable (e.g. getTime_custom_now) to retrieve that output from. Then some creativity to tie it all together. The most important part (IMHO) is to keep your test case readable and maintainable.

In case your project uses a C compiler that supports nested functions (e.g. GCC), or when using C++ lambdas, you can even combine all this in a single unit test function so you can easily oversee all details of the test.

#include <functional>

/* Configure FFF to use std::function, which enables capturing lambdas */
#define CUSTOM_FFF_FUNCTION_TEMPLATE(RETURN, FUNCNAME, ...) \
    std::function<RETURN (__VA_ARGS__)> FUNCNAME

#include "fff.h"

/* The time structure */
typedef struct {
   int hour, min;
} Time;

/* Our fake function */
FAKE_VOID_FUNC(getTime, Time*);

/* A test using the getTime fake function */
TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_output)
{
    Time t;
    Time getTime_custom_now = {
        .hour = 13,
        .min = 05,
    };
    getTime_fake.custom_fake = [getTime_custom_now](Time *now) {
      *now = getTime_custom_now;
    };

    /* when getTime is called */
    getTime(&t);

    /* then the specific time must be produced */
    ASSERT_EQ(t.hour, 13);
    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);
}

How do I reuse a fake across multiple test-suites?

fff functions like FAKE_VALUE_FUNC will perform both the declaration AND the definition of the fake function and the corresponding data structs. This cannot be placed in a header, since it will lead to multiple definitions of the fake functions.

The solution is to separate declaration and definition of the fakes, and place the declaration into a public header file, and the definition into a private source file.

Here is an example of how it could be done:

/* Public header file */
#include "fff.h"

DECLARE_FAKE_VALUE_FUNC(int, value_function, int, int);
DECLARE_FAKE_VOID_FUNC(void_function, int, int);
DECLARE_FAKE_VALUE_FUNC_VARARG(int, value_function_vargs, const char *, int, ...);
DECLARE_FAKE_VOID_FUNC_VARARG(void_function_vargs, const char *, int, ...);


/* Private source file file */
#include "public_header.h"

DEFINE_FAKE_VALUE_FUNC(int, value_function, int, int);
DEFINE_FAKE_VOID_FUNC(void_function, int, int);
DEFINE_FAKE_VALUE_FUNC_VARARG(int, value_function_vargs, const char *, int, ...);
DEFINE_FAKE_VOID_FUNC_VARARG(void_function_vargs, const char *, int, ...);

Specifying GCC Function Attributes

You can specify GCC function attributes for your fakes using the FFF_GCC_FUNCTION_ATTRIBUTES directive.

Weak Functions

One usful attribute is the weak attribute that marks a function such that it can be overridden by a non-weak variant at link time. Using weak functions in combination with fff can help simplify your testing approach.

For example:

  • Define a library of fake functions, e.g. libfake.a.
  • Link a binary (you might have many) that defines a subset of real variants of the fake functions to the aforementioned fake library.
  • This has the benefit of allowing a binary to selectively use a subset of the required fake functions while testing the real variants without the need for many different make targets.

You can mark all fakes with the weak attribute like so:

#define FFF_GCC_FUNCTION_ATTRIBUTES __attribute__((weak))
#include "fff.h"

See the example project that demonstrates the above approach: ./examples/weak_linking.

Find Out More

Look under the examples directory for full length examples in both C and C++. There is also a test suite for the framework under the test directory.


Benefits

So whats the point?

  • To make it easy to create fake functions for testing C code.
  • It is simple - just include a header file and you are good to go.
  • To work in both C and C++ test environments

Under the Hood

  • The fff.h header file is generated by a ruby script
  • There are tests under ./test
  • There is an example for testing an embedded UI and a hardware driver under ./examples
  • There is an example of weak_linking under ./examples

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);
FAKE_VOID_FUNC_VARARG(fn [,arg_types*], ...); Define a fake variadic function returning void with type return_type taking n arguments and n variadic arguments FAKE_VOID_FUNC_VARARG(fn, const char*, ...)
FAKE_VALUE_FUNC_VARARG(return_type, fn [,arg_types*], ...); Define a fake variadic function returning a value with type return_type taking n arguments and n variadic arguments FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE*, const char*, ...)
RESET_FAKE(fn); Reset the state of fake function called fn RESET_FAKE(DISPLAY_init);

fff's People

Contributors

alvarez86 avatar aunsbjerg avatar codehearts avatar damaki avatar henningrehn avatar jakub-dudarewicz avatar meekrosoft avatar michahoiting avatar nabijaczleweli avatar oliviera9 avatar rubiot avatar stephan-cr avatar usr42 avatar wulfgarpro avatar yperess avatar zrax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fff's Issues

Attempting to FFF FreeRTOS.. getting "error: use of deleted function ... "

Hello,

I am trying to stub out some FreeRTOS API using FFF. At the moment, I am trying to stub out xTimerCreate:

FAKE_VALUE_FUNC(TimerHandle_t, xTimerCreate, const char * const, const TickType_t, const UBaseType_t, void * const, TimerCallbackFunction_t);

However, I am getting a compilation error:

error: use of deleted function 'xTimerCreate_Fake::xTimerCreate_Fake()'
     FAKE_VALUE_FUNC(void *, xTimerCreate, const char * const, const TickType_t, const UBaseType_t, void * const, TimerCallbackFunction_t);

Unfortunately, I cannot change the production code to abstract out FreeRTOS.

Any ideas how I can get around this?

Thanks

Help - looking for co-maintainer

Hi,

fff started as a small scratch-your-own-itch project, and I'm really happy to see so many people getting value from it now.

It has been quite some years since I've been working in embedded, and I have to admit I am perhaps not best suited to maintaining the project going forward. Basically I'm too busy and underqualified to make a call on many of the pull requests.

With that in mind, I'd really rather give the community the opportunity to take over.

The main concern I have is to ensure that fff doesn't introduce breaking changes, and remains a single header file.

If you are interested in contributing to the ongoing governance of the project, please drop a comment below.

Thanks!

Cannot compile in Visual Studio 2015

I'm trying to use FFF from within Visual Studio 2015 and VC++, and the example I tried (attached) does not want to compile. Here's the test file:


extern "C"
{
#include "driver.h"
#include "registers.h"
}
#include <stdint.h>
#include "CppUnitTest.h"
#include "fff.h"

DEFINE_FFF_GLOBALS;

FAKE_VOID_FUNC(IO_MEM_WR8, uint32_t, uint8_t);
FAKE_VALUE_FUNC(uint8_t, IO_MEM_RD8, uint32_t);

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace FFFTestProject
{		
	TEST_CLASS(UnitTest1)
	{
	public:
    TEST_METHOD_INITIALIZE(Init)
    {
      /*RESET_FAKE(IO_MEM_WR8);
      RESET_FAKE(IO_MEM_RD8);
      FFF_RESET_HISTORY();*/
    }
		
		TEST_METHOD(TestMethod1)
		{
			// TODO: Your test code here
		}

	};
}`

The FAKE_VOID_FUNC and FAKE_VALUE_FUNC macros are generating the following warning.

Warning C4003 not enough actual parameters for macro 'PP_ARG_MINUS1_N' FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12

Trying to compile generates the following errors, all stemming from the FAKE_VOID_FUNC and FAKE_VALUE_FUNC macros.

Error C2065 'IO_MEM_WR8': undeclared identifier FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2065 'IO_MEM_WR8': undeclared identifier FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2275 'uint32_t': illegal use of this type as an expression FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2275 'uint32_t': illegal use of this type as an expression FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2275 'uint8_t': illegal use of this type as an expression FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2275 'uint8_t': illegal use of this type as an expression FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2440 'initializing': cannot convert from 'initializer list' to 'int' FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12
Error C2440 'initializing': cannot convert from 'initializer list' to 'int' FFFTestProject c:\temp\projects\ffftestproject\ffftestproject\unittest1.cpp 12

FFFTestProject.zip

Add support for the ellipsis operator (...)

Fff is a great and elegant tool to unit test (embedded) c code, but I have some APIs that use the ellipsis operator to pass variable number of arguments. I have made some modifications to fff.h to handle '...' as the last parameter.

I have an initial concept to handle minimal vararg functionality with fakes, see https://gist.github.com/4037531
In a second approach I would design it such that the custom fakes shall use a va_list (but not not saving varargs).

Conan package

Hello,
Do you know about Conan?
Conan is modern dependency manager for C++. And will be great if your library will be available via package manager for other developers.

Here you can find example, how you can create package for the library.

Also will be fine, if you will create a release of the library.

If you have any questions, just ask :-)

Unable to mock static inline functions

Hi there,
I am trying to mock a couple of functions from the linux/i2c-dev.h header, which declaration is as follows:

static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) { ... }
static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u8 value) { ... }

Unfortunately, FFF doesn't seem to be taking my mocks as valid mocks for these functions calls. I am not getting de return sequence according to what I've set. I'm always getting the same value (which I assume it's because the real functions are being called instead of the mock ones).

My mock declarations are the following:
FAKE_VALUE_FUNC( __s32, i2c_smbus_write_word_data, int, __u8, __u16);
FAKE_VALUE_FUNC( __s32, i2c_smbus_write_byte_data, int, __u8, __u8);

Does it have something to do with the way the functions are declared?

Thank you!
Regards,

Feature Request for expectations

Hi all,

imagine the following scenario:

FAKE_VOID_FUNC(__wrap_write, int, void*, ssize_t)

SOME_TEST_FUNC() {

    struct some_struct send = { ... };

    method_that_calls_write(args, that, create, a, object, like, send, on, the, stack);

    assert_mem_eq(&send, __wrap_write_fake.arg0_value, sizeof(send));

}

The method_that_calls_write create a object on the stack that look like send and writes its content. After the call to method_that_calls_write the created object on the stack is not accesible anymore, hence, I cannot check the written data.

Is there a feature planned to make expectation to a mock object and check these expectations later on?

Using FAKE_VOID_FUNC on vsyslog cause a sizeof-array-argument error

Describe the bug
FAKE_VALUE_FUNC(vsyslog, int, const char*, va_list);

is causing a sizeof of va_list which gcc turns into an error and therefore trigger the error sizeof-array-argument

To Reproduce
Compile the above

Expected behavior
detect array type and not call sizeof on them?

Screenshots
In file included from /home/ykoehler/fake_log.cpp:18:
/home/ykoehler/fake_log.cpp: In function ‘void vsyslog(int, const char*, __va_list_tag*)’:
/home/ykoehler/fff/include/fff.h:69:79: error: ‘sizeof’ on array function parameter ‘arg2’ will return size of ‘__va_list_tag*’ [-Werror=sizeof-array-argument]
memcpy((void*)&FUNCNAME##_fake.arg##n##_val, (void*)&arg##n, sizeof(arg##n));

Compiler, toolset, platform (please complete the following information):

  • OS: Ubuntu 18.10
  • Compiler: gcc (Ubuntu 8.2.0-7ubuntu1)

Additional context

Const pointer as argument causes _Wcast-qual warnings

When using the fake function framework to mock a function that takes a const pointer as Argument, e.g.

FAKE_VOID_FUNC(my_function, int *const)

I get four compiler warnings:

fff.h:66:12: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] memcpy((void*)&FUNCNAME##_fake.arg##n##_val, (void*)&arg##n, sizeof(arg##n));

fff.h:66:50: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] memcpy((void*)&FUNCNAME##_fake.arg##n##_val, (void*)&arg##n, sizeof(arg##n));

fff.h:76:12: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] memcpy((void*)&FUNCNAME##_fake.arg##ARGN##_history[FUNCNAME##_fake.call_count], (void*)&arg##ARGN, sizeof(arg##ARGN));

fff.h:76:85: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] memcpy((void*)&FUNCNAME##_fake.arg##ARGN##_history[FUNCNAME##_fake.call_count], (void*)&arg##ARGN, sizeof(arg##ARGN));

As I read through the documentation and through merged pull requests, it seems this should be possible. Am I doing something wrong, or do I have to life with the warnings?

Functions with more than 10 parameters

Hi! This is an amazing project, congratulations!

I have some functions with 15 or more parameters (legacy code nightmare) I tried rebuild the header changing $MAX_ARGS in ruby script, but it doesn't work, the new header file includes new macros for support this functions but FAKE_VOID_FUNC mapping doesn't work and i must call FAKE_VOID_FUNC15 direcly.

In other side, support for the ellipsis operator (...) seems great feature!

Issue with functions with void pointers as arguments

Hi,

I'm having issues trying to mock a function that has void pointers. It seems to be calculating the size of the argument to save to array, but this would probably cause an issue.
Is it possible to mock this kind of function? I guess we'd have to use a different function than memcpy()?

This is an example:
unsigned int SelfLib_Write(void *var_1, void *var_2, unsigned char b);

Typical error with gcc:

error: too many arguments to function '*(SelfLib_Write_fake.custom_fake_seq + ((sizetype)((long long unsigned int)SelfLib_Write_fake.custom_fake_seq_len * 8ull) + 18446744073709551608u))'
DEFINE_FAKE_VALUE_FUNC(UI_32, SelfLib_Write, void *, void *, UI_32);

Is this library still maintained?

Thanks

Fake function problem

Hi, could I still use the original function after I faked this function in my unit test?

Macro usage examples yield empty declarations

Inspired by the documentation in the readme file I created this small test program:

#include <fff.h>
DEFINE_FFF_GLOBALS; // WARNING

FAKE_VALUE_FUNC(double, pow, double, double); // WARNING

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  pow_fake.return_val = 23;
  printf("pow: %f\n", pow(2, atoi(argv[1])));
  return 0;
}

This works as expected with gcc on Fedora 25. But on Solaris 10/SPARC with the Solaris Studio 12.3 C compiler I get the following warnings:

"test.c", line 2: warning: syntax error:  empty declaration
"test.c", line 4: warning: syntax error:  empty declaration

Looking at the C pre-processor output reveals the cause:

DEFINE_FFF_GLOBALS;
FAKE_VALUE_FUNC(double, pow, double, double);

The expansion of both macros yields an extra semicolon!

Thus, removing the semicolons in the test program eliminates the warnings:

DEFINE_FFF_GLOBALS
FAKE_VALUE_FUNC(double, pow, double, double)

Thus, perhaps you want to change the macro definitions such that no superfluous semicolons are expanded anymore. This would increase the portability of this header-only library.

See also:

Empty declarators are prohibited; a declaration must be a static_assert declaration or (since C11) have at least one declarator or declare at least one struct/union/enum tag, or introduce at least one enumeration constant.

(http://en.cppreference.com/w/c/language/declarations)

Add macro to get the call count

I'd like to add a macro into FFF which returns the call count for a mock. This would allow the user to change calls from something like:

CHECK_EQUAL(1, function_to_mock_fake.call_count);
to
CHECK_EQUAL(1, GET_CALL_COUNT(function_to_mock));

This better masks the internals of the fff framework.

MACRO:

#define GET_CALL_COUNT(FUNCNAME)
FUNCNAME##_fake.call_count

Support for creating testing seams

Hi

i would like to have fff to support the dynamic exchange of the functions.

Lets say i have a function foo+bar and i want to replacy it with my fakes called fooTest+barTest. Then i would like to have expanded code like this:

In case for working with unittesting, i set the #define UNIT_TESTING
header:

extern void (*foo_TestPtr)( int a );
void foo( int a );
extern int (*bar_TestPtr)( int a );
int bar( int a );

source:

void (*foo_TestPtr)( int a ) = NULL;
void foo( int a ){
    if( foo_TestPtr ){
        foo_TestPtr( a );
        return;
    }
    // ... implementation
}

int (*bar_TestPtr)( int a ) = NULL;
int bar( int a ){
    if( bar_TestPtr ){
        return bar_TestPtr( a );
    }
    // ... implementation
}

When #define UNIT_TESTING is not set, this expands to:

header:

void foo( int a );
int bar( int a );

source:

void foo( int a ){
    // ... implementation
}

int bar( int a ){
    // ... implementation
}

And this is, how i want to write it:

header:

FUNC_DECL( void, foo,( int a ));
FUNC_DECL( int, bar,( int a ));

source:

FUNC_IMPL( void, foo,( int a )){
    FUNC_VOID_REDIR( foo, (a))

    // ... implementation
}

FUNC_IMPL( int, bar,( int a )){
    FUNC_VALUE_REDIR( bar, (a))
    // ... implementation
}

To implement, this can look like this:

#ifdef UNIT_TESTING
/**
 * Declare a function normally and a function pointer with _TestPtr postfix.
 *
 * Example:
 *   int example( char* name );
 *
 * Use of the macro:
 *   FUNC_DECL(int, example, ( char* name ));
 *
 * Expands to:
 *   int example( char* name );
 *   int (*example_TestPtr)( char* name );
 */
# define FUNC_DECL(r,n,a) \
        r n a;\
        extern r (*n##_TestPtr) a
#else
# define FUNC_DECL(r,n,a) extern r n a
#endif

#ifdef UNIT_TESTING
/**
 * Define the function pointer and the function signature
 *
 * Example:
 *   int example( char* name ){ ...
 *
 * Use of the macro:
 *   FUNC_IMPL(int, example, ( char* name )) { ...
 *
 * Expands to:
 *   int (*example_TestPtr)( char* name ) = NULL;
 *   int example( char* name ) { ...
 *
 *
 */
# define FUNC_IMPL(r,n,a) \
    r (*n##_TestPtr) a = NULL;\
    r n a
#else
# define FUNC_IMPL(r,n,a) r n a
#endif

#ifdef UNIT_TESTING
/**
 * Function redirect for functions without return value.
 *
 * FUNC_IMPL(void, example, ( char* name )) {
 *      FUNC_REDIR_VOID( example, name )
 *      ...
 * }
 *
 * Expands to:
 *   void (*example_TestPtr)( char* name ) = NULL;
 *   void example( char* name ) {
 *       if( example_TestPtr ){
 *           return example_TestPtr( name );
 *       }
 */
# define FUNC_REDIR_VOID(n,a) \
    do{ if( n##_TestPtr ){\
        n##_TestPtr a;\
        return;\
    } } while( false )
#else
# define FUNC_REDIR_VOID(n,a) \
    do{ } while( false )
#endif

#ifdef UNIT_TESTING
/**
 * Function redirect for function with return value.
 *
 * FUNC_IMPL(int, example, ( char* name )) {
 *      FUNC_REDIR_VALUE( example, name )
 *      ...
 * }
 *
 * Expands to:
 *   int (*example_TestPtr)( char* name ) = NULL;
 *   int example( char* name ) {
 *       if( example_TestPtr ){
 *           example_TestPtr( name );
 *           return;
 *       }
 */
# define FUNC_REDIR_VALUE(n,a) \
    do{ if( n##_TestPtr ){\
        return n##_TestPtr a;\
    }} while( false )
#else
# define FUNC_REDIR_VALUE(n,a) \
    do{ } while( false )
#endif

This way, you have function runtime substitution, like you discussed here:
https://meekrosoft.wordpress.com/2012/07/20/test-seams-in-c-function-pointers-vs-preprocessor-hash-defines-vs-link-time-substitution/
But the two contra arguments are removed. Now the IDE can resolve the function calls, do auto completion and do code analysis.

Finally, if there would be a way to make the FUNC_IMPL and FUNC_VOID_REDIR a single macro call, this would be super cool. But I don't know how to do that. Perhaps you?

Frank

Faking functions that take no parameters should use void in parameter list

If I use any of the FAKE_*_FUNC0 variants then fff declares functions which take any number of parameters because it uses an empty parameter list. For example, if there is a function foo which has no arguments and returns nothing then using FAKE_VOID_FUNC0(foo); eventually ends up with a function declaration:

void foo();

If I have an existing header for the code under test that declares foo as:

void foo(void);

because, really foo doesn't have any arguments and I want to ensure the compiler catches me trying to pass the wrong number of arguments instead of just accepting any and (possibly) leading to subtle runtime bugs. However that is then in conflict with the declaration from fff and you get compiler warnings (IAR by default, MSVC must enable all warnings).

Would it be possible to use void instead of an empty parameter list? This would apply to all the other no-argument functions such as the custom delegate, custom delegate sequence and reset functions.

old version fff to latest transition trouble due to extern "C"

I work at Cisco and we took a TDD class from James Grenning a while back and he introduced us to FFF. That was many years ago and we've been using an old version. We need to move to the latest because of our need for the ____VARARG fakes. However, in looking at the changes, there has been a lot of advancement since we pulled our copy - most notably there is a lot of changes regarding extern "C" declarations throughout dependent on #ifdef __cplusplus.

In particular, this is causing most of my existing unit tests to fail - probably because we took matters into our hands to address the placement of extern "C" - so as example, I have a unit under test in a C file that calls getpid. The test program is a CPP file and that is where FFF is included and getpid is faked.

On the call to FAKE_VALUE_FUNC(pid_t, getpid) it fails because of inconsistency:

In function 'pid_t getpid()': declaration of 'pid_t getpid()' with C language linkage
conflicts with previous declaration 'pid_t getpid()' due to different exception specifications

So my issue is - can you summarize what has changed in regard to extern C and how to handle that since the various upgrades through the years?

Should I be using extern C at all in my CPP test programs?

TODDL
Cisco Systems.

Version Information for FFF

Hello,

How do you know which version of FFF you are running? We are using FFF and trying to track our configurations...any support? I've done some extensive "grepping" and I haven't come up with anything

Question: Usage of __weak__

Hi!

Love this library. I have used it several places, for example in in this arduino testing frame

I am not sure how this is thought, but i usually like to make testing so that all functions are mocked, except few special. I make this by linker; i have fake-objects that contains fake implementation of all functions and before that the real ones. This works fine, but to have it even nicer, one wraps the thing to "libfakes.a" that contains all fakes. To make this work, one should mark all fakes with __attribute__((weak)).

This would make minor pull request, that i am super willing to make, but is there a reason why it has been skipped for now?

Cheers,
Pauli

Here is example of 'fixed' function:

#define DEFINE_FAKE_VOID_FUNC0(FUNCNAME) \
    FFF_EXTERN_C \
        FUNCNAME##_Fake FUNCNAME##_fake; \
        __attribute__((weak))  void FUNCNAME(void)  { \
            if(ROOM_FOR_MORE_HISTORY(FUNCNAME)){ \
            } \
            else{ \
                HISTORY_DROPPED(FUNCNAME); \
            } \
            INCREMENT_CALL_COUNT(FUNCNAME); \
            REGISTER_CALL(FUNCNAME); \
            if (FUNCNAME##_fake.custom_fake_seq_len){ /* a sequence of custom fakes */ \
                if (FUNCNAME##_fake.custom_fake_seq_idx < FUNCNAME##_fake.custom_fake_seq_len){ \
                    FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_idx++](); \
                } \
                else{ \
                    FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](); \
                } \
            } \
            if (FUNCNAME##_fake.custom_fake) FUNCNAME##_fake.custom_fake(); \
        } \
        DEFINE_RESET_FUNCTION(FUNCNAME) \
    FFF_END_EXTERN_C \

FFF_RESET_HISTORY() insufficient

Calling FFF_RESET_HISTORY doesn't work well when checking a similar call order in two sequential tests. Since the reset only moves the index, but doesn't clear the history of calls, if two functions happen to have a similar sequence of faked calls, checking the call history in the tests can erroneously succeed even when FFF_RESET_HISTORY is called in between the test runs. I hit this in the context of faking locking/unlocking functions in my code. A pseudo-code scenario that I think demonstrates what I'm talking about below:

void functionAUnderTest(void)
{
  fake1();
  //do something
  fake2();
}

void functionBUnderTest(void)
{
  /* not implemented yet, but planned as shown*/
  //fake1();
  //do something different
  //fake2();
}

void testA( void )
{
  FFF_FAKES_LIST(RESET_FAKE);
  FFF_RESET_HISTORY();
  functionAUnderTest();
  ASSERT_EQ(fff.call_history[0] == fake1);
  ASSERT_EQ(fff.call_history[1] == fake2);
}

void testB( void ) 
{
  FFF_FAKES_LIST(RESET_FAKE);
  FFF_RESET_HISTORY();
  functionBUnderTest();
  //fake1 and fake2 pass, because they are still in the history, despite the reset
  ASSERT_EQ(fff.call_history[0] == fake1); //passes even though haven't actually called the fake
  ASSERT_EQ(fff.call_history[1] == fake2); //passes even though haven't actually called the fake
}

I can't promise when I'll get to it, but would a PR to extend the reset to also actually clear the history be welcomed?

Parameter for UnityPrintFloat() different between declaration and definition

In unity.c UnityPrintFloat is defined as void UnityPrintFloat(UNITY_DOUBLE number) but it is declared in unity_internals.h as void UnityPrintFloat(const UNITY_DOUBLE number). The parameter is marked as const in the header and not in the source which results in a compile time warning from MSVC at least. Please use const in the source as well as the header.

Disable fakes between test suits (use original functions when needed)

Let's say I've 2 units (header & source) under the same C module - A (which is independent) and B (which is dependent on unit A's functions).

I want to write unit tests for both unit A and unit B.
In order to unit test unit B under it's own test suite, I need to define fakes for unit A's functions - but then I cannot use unit A's original functions in unit A's test suit...

Is there any way I can "disable" fakes between the test suits in order to be able to use the original functions, before/after "mocking" them?

Specifying calling convention

There is no way to specify a function's calling convention, void or otherwise. I'd like to fake a function that has a different convention than my project so I can't rely on the default.

document return_val is ignored when custom_fake is defined

return_val is ignored when custom_fake is defined, but that fact is not well-documented.

suppose you are going to test set_pin_direction() function, which calls a fake function read8() that is supposed to read a value from an I2C slave. set_pin_direction() returns 0 when read8() has failed for whatever reason. you would like to test the function without slave IC.

first, fakeread8() in the test.

FAKE_VALUE_FUNC(int32_t, read8,  const uint8_t, uint8_t *);

next, create a custom fake function that returns a faked register value.

static uint8_t faked_reg_value; // a global variable to set faked values in tests

void * read8_fake_custom_fake(const uint8_t reg, uint8_t *reg_value)
{
        *reg_value = faked_reg_value;
}

and the actual test.

TEST_CASE("my_test_1", component)
{
        faked_reg_value = 0xff;
        read8_fake.custom_fake = read8_fake_custom_fake;
        read8_fake.return_val = 0;
        r = set_pin_direction(1, OUTPUT);
        TEST_ASSERT_EQUAL_UINT32(0, r);
}

you expects read8() returns 0, and the passed pointer contains 0xff as value.

the above test will NOT work. because the expanded macros contains the following definition.

if (read8_fake.custom_fake) return read8_fake.custom_fake(arg0, arg1);

when custom_fake is defined as a pointer to a custom function, return_val is ignored. in this case, the return value is 1, the last evaluation in the custom function. to make the matter worse, it DOES succeed depending on values.

so, you need to returns zero in the custom_fake.

uint32_t * read8_fake_custom_fake(const uint8_t reg, uint8_t *reg_value)
{
        *reg_value = faked_reg_value;
        return 0;
}

with clear explanation, someone would save hours (or days).

Multiple definition error

This is what I have:

#include "lib/fff.h"
DEFINE_FFF_GLOBALS;
FAKE_VALUE_FUNC(bool_t, probe_is_ok, adc_probe_t);
/* List of fakes used by this unit tester */
#define FFF_FAKES_LIST(FAKE)            \
  FAKE(probe_is_ok)                    \

And this is what I get when I build

../app/middleware/libmiddleware.a(probe.c.o): In function `probe_is_ok':
~/AppProject/app/middleware/probe.c:19: multiple definition of `probe_is_ok'
CMakeFiles/unit_tests.dir/AppTest.cpp.o:~/AppProject/test/AppTestTest.cpp:16: first defined here

Limit scope of mock functions to file

Limiting functions to file scope can help selectively use the mock implementation or the actual implementation in certain cases.

For example:
The module under test is mod.c and its dependency is libdep.so. I can have test cases in 2 files, test_file1.c and test_file2.c.
In test_file1.c, I would like to use the mock functions, thus declare and define them statically in the same file. As the dependent functions get resolved before linking in case of test_file1.c, the mock functions will get used. In case of test_file2.c, the dependent functions get resolved to actual implementation (from libdep.so) at link time as mock functions are not visible to this file.

In this context, will it be useful to have the capability to define mock implementations as static, with a macro like FAKE_STATIC_VOID_FUNC() and FAKE_STATIC_VALUE_FUNC()?

Add support for fakes with const parameters

Using a fake function that has a const parameter leads to compiler errors.
For instance using a fake for the function ‘strlcpy’ see below.

  • fff_test_cpp.cpp: FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t);
  • test_cases.include: TEST_F(FFFTestSuite, when_fake_func_called_then_const_arguments_captured) { char dst[80]; strlcpy3(dst, __FUNCTION__, sizeof(__FUNCTION__)); }
  • Running gmake:
    Building file: fff_test_cpp.cpp
    Invoking: GCC C++ Compiler
    g++ -I../ -O0 -g3 -Wall -c -o "../build/fff_test_cpp.o" "fff_test_cpp.cpp"
    fff_test_cpp.cpp:23: error: structure strlcpy3_fake' with uninitialized const members fff_test_cpp.cpp: In functionint strlcpy3(char_, const char_, size_t)':
    fff_test_cpp.cpp:23: error: assignment of read-only data-member strlcpy3_Fake::arg0_val' fff_test_cpp.cpp:23: error: assignment of read-only data-memberstrlcpy3_Fake::arg1_val'
    fff_test_cpp.cpp:23: error: assignment of read-only data-member `strlcpy3_Fake::arg2_val'
    fff_test_cpp.cpp:23: error: assignment of read-only location
    fff_test_cpp.cpp:23: error: assignment of read-only location
    fff_test_cpp.cpp:23: error: assignment of read-only location
    gmake[1]: *** [../build/fff_test_cpp.o] Error 1
  • See also https://github.com/michahoiting/fff/tree/const-issue.
    The macros SAVE_ARG and SAVE_ARG_HISTORY in fff.h will need to be changed.

Possibility to modify custom_fake internal variables

Hello,
imagine I would like to fake fgets (http://www.cplusplus.com/reference/cstdio/fgets/), so I declare:
FAKE_VALUE_FUNC(char *, fgets, char *, int, FILE *);

Thus, I declare a custom_fake, e.g.:
char *custom_fgets_coolmate(char *str, int n, FILE *f)
{
char *out = "mystring1";
strcpy(str, out);
return out;
}
and assign it to the fake function.

Now, is there a convenient way to change the out variable in the custom_fake? Otherwise, whenever I would like to change the fake returning string, I would need to declare a new custom_fake and assign it as a custom_fake.

Isn't there the possibility to overcome this? Maybe it should be an option to define a global variable within the fake function which can be used within the custom_fake and can be easilly accessed in order to dynamically modify the custom_fake behavior.

Thanks!

EXTERN_C clashes with macro of same name in winnt.h

We have a few files in our unit-tests that need fff.h but also need to include windows.h. Unfortunately, both define a macro EXTERN_C so we get warnings about macro redefinitions:

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(359) : warning C4005: 'EXTERN_C' : macro redefinition
W:\dyn_view\common\interface\unittest/fff.h(86) : see previous definition of 'EXTERN_C'

I suggest that the EXTERN_C/END_EXTERN_C in fff.h be prefixed with FFF_ to avoid this clash. (This is the change we've made locally with search-and-replace and it has resolved the issue.)

Regards,

Steve.

error: overloaded function with no contextual type information

When trying to run make on a unit test using fff.h to fake a function initSerialCommDevice i get the following error:

In file included from /home/zanev/mbed/AFDAU_0_01/UNITTESTS/app/drivers/test_rockair.cpp:6:0:
/home/zanev/mbed/AFDAU_0_01/UNITTESTS/app/drivers/test_rockair.cpp: In function ‘int initSerialCommDevice(uint8_t, uint32_t, uint8_t, serialParity_e, uint8_t)’:
/home/zanev/mbed/AFDAU_0_01/UNITTESTS/app/drivers/test_rockair.cpp:10:22: error: overloaded function with no contextual type information
 FAKE_VALUE_FUNC(int, initSerialCommDevice, uint8_t, uint32_t, uint8_t, serialParity_e, uint8_t);

my test file is as follows (initSerialCommDevice is prototyped in _hal_serial.h):

#include <stdint.h>
#include "../../app/drivers/rockair.h"
#include "../../app/peripherals/_hal_serial.h"
#include <gtest/gtest.h>
#include "fff.h"

DEFINE_FFF_GLOBALS;

FAKE_VALUE_FUNC(int, initSerialCommDevice, uint8_t, uint32_t, uint8_t, serialParity_e, uint8_t);
class RockairDriverTest : public ::testing::Test
{
public:
  void SetUp()
  {
    //RESET_FAKE(initSerialCommDevice);
    FFF_RESET_HISTORY();
  }
};


TEST_F(RockairDriverTest, initializes_rockair_driver_successfully) {
  uint8_t port_id = 1;
  uint32_t baud = 9600;
  uint8_t data_bits = 8;
  serialParity_e parity = NONE;
  uint8_t stop_bits = 1;

  rockair_initDriver(port_id, baud, data_bits, parity, stop_bits);
  //ASSERT_EQ(initSerialCommDevice_fake.call_count, 1);
}

From the digging I have done on the issue it appears that the compiler is seeing the function in the _hal_serial.h file and also seeing the function that the macro is creating and is having an issue. I have looked over the example code and tried to see where I have gone wrong but everything seems to be as it should. Can anybody point me in the right direction here?

Const pointer to const generates a wrong mock

I'm using ceedling and fff framework.

When generating mock for functions like the one below there some errors.
Function to generate mock for:
void test(const void * const test_t);
Generated mock:
DECLARE_FAKE_VALUE_FUNC1(void, const const void*);
It should be:
DECLARE_FAKE_VALUE_FUNC1(void, const void* const);

This error generated warnings like this one, when using IAR compiler Arm 8.32.1:
Warning[Pe083]: type qualifier specified more than once

Thanks.

Code License

What license is this code released under?

This is a great framework and I'd like to use it for unit testing. But I can't get it into my company's development environment unless I know the license terms.

gtest conflicting

Describe the bug
Because gtest is embedded in the root of the respository under the gtest directory, if this repository is included in a unit testing CMakeLists.txt using include_directories, and googletest is also used in the same project then #include "gtest/gtest.h" could include either header. As the gtest.h in this project is very old, this causes problems.

To Reproduce
Steps to reproduce the behavior:

  1. Create a unit testing project
  2. Include this repository directory
  3. Also add googletest
  4. From a unit test, include gtest/gtest.h

Selective Mocking

In c++ project is it possible to used mocked and non-mocked headers?

I have two test suites which overlap.

Test Suite 1
Mock: drivers.h
pump_calc.h
Test: pump_move.h/c

Test Suite 2:
Mock: pump_math.h
Test: pump_calc.c/h

The issue is that in suite 2 calling functions from pump_calc is calling the mocked ones.
Is it possible to call the real functions in test suite 2 but the fake ones in test suite 1?
This happenes whether I use DECLARE_FAKE_VALUE_FUNC and DEFINE_FAKE_VALUE_FUNC.
Also happens with FAKE_VALUE_FUNC. It doesn't seem to matter which is used.

Issue faking out variadic printf

I'm trying to fake out printf's in my production code, but any statements without arguments are printed out. Here's an example file:

#include "CppUTest/TestHarness.h"
#include <stdio.h>
#include "fff.h"

DECLARE_FAKE_VALUE_FUNC_VARARG(int, printf, const char *, ...);

int mock_printf(const char * format, va_list arg)
{
    int result = vfprintf(stdout, format, arg);
    fprintf(stdout, "Goodbye\n");
    return(result);
}

TEST_GROUP(printf_mocks)
{
      void setup() {
      }
      void teardown() {
            RESET_FAKE(printf);
      }
};  

TEST(printf_mocks, printf_test)
{
    fprintf(stdout, "PRINTF_MOCKS (Tests 1 & 2):\n");
    printf("%d:",1); // This is not seen (mock works)
    printf("2:\n");  // This hits normal printf()
    printf_fake.custom_fake = mock_printf;
    fprintf(stdout, "FAKE PRINTF INSTALLED (Tests 3 & 4):\n");
    printf("%d:",3); // This hits mock_printf() - See Goodbye
    printf("4:\n");  // This hits normal printf()
}

When run, I see the following:

user@linux:UnitTest >$ ./platform_unit_tests_tests -n printf_test
PRINTF_MOCKS (Tests 1 & 2):
2:
FAKE PRINTF INSTALLED (Tests 3 & 4):
3:: Goodbye
4:
.
OK (23 tests, 1 ran, 0 checks, 0 ignored, 22 filtered out, 0 ms)

Test cases 2 and 4 are not being handled by FFF, instead going to stdio's printf(). Is there a way to handle this?

GCC warning for variadic with no arguments when compiling ISO c11 strict

I'm mocking several functions with declarations similar to this:

void SCHEMAinitialize();

using:
FAKE_VOID_FUNC(SCHEMAinitialize)

currently results in a compiler warning:

/home/chorler/projects/src/stepcode/src/express/test/test_express.c:56:32: warning: ISO C99 requires at least one argument for the "..." in a variadic macro
 FAKE_VOID_FUNC(SCHEMAinitialize)
                                ^

current workaround:
FAKE_VOID_FUNC0(SCHEMAinitalize)

as the FAKE_VOID_FUNC is declared as
#define FAKE_VOID_FUNC(...) EXPAND(FUNC_VOID_(PP_NARG_MINUS1(__VA_ARGS__), __VA_ARGS__))

I guess the preprocessor warning applies to a macro definition deeper in fff.h, possibly an unintended consequence of the EXPAND macro?

Add documentation and tests for VARARG fakes

FFF also supports faking VARARG functions, e.g.
void voidfunc3var(const char *fmt, int argc, ...);
could be faked with
FAKE_VOID_FUNC_VARARG(voidfunc3var, char *, int, ...);

But how to use this is not described in the readme.
Additionally the unit tests for VARARGs are not sufficient. There are no assertions. I think there should be at least be a test for argument capturing. Also the custom_fake for VARARGs should be covered by unit tests.

Dealing with reference/pointer arguments?

What's the best way to mock functions that take references/pointer arguments that usually point to temporary (stack allocated) variables? If you have a lot of this in your code, making custom fakes for everything lowers the value of using FFF in the first place...

Can you see a way to support dereferencing pointer arguments and copying the actual values to the history? It would have to be on a per-argument basis because often you also don't want to deref the pointer (i.e. an out-pointer).

FUNCNAME##_reset() conflicts with existing functions

Describe the bug
I have two functions: foobar_testcli() and foobar_testcli_reset() in my foobar.h

fff will generate below fake functions:
DECLARE_FAKE_VALUE_FUNC3(int, foobar_testcli, foo_info_t*, int, int);
DECLARE_FAKE_VOID_FUNC1(foobar_testcli_reset, foo_info_t*);

But first DECLARE_FAKE_VALUE_FUNC3() internally has a FUNCNAME##_reset() that conflicts with my existing foobar_testcli_reset().

Am I missing some options to bypass this?

(Feature request) Change call_history type to a function pointer

Could fff be changed so that instead of fff_globals_t.call_history being an array of void pointers it is an array of function pointers? The reason for asking is that I am using fff in an embedded project which uses IAR for msp430, although I think you'd come across this with other compilers/architectures too. The particular processor architecture I'm using can address 20 bits but the data pointer size varies (16/16 or 32 bits) with the model selected (Small/Medium or Large respectively) in the project options whereas the function pointer size is always 32 bits. The function pointers in the call history get truncated in Small/Medium models because void * is treated as a data pointer and therefore its size changes with the model.

Changing from void *call_history[FFF_CALL_HISTORY_LEN]; to something like:

typedef void (*fft_function_t)(void);

typedef struct { 
    fff_function_t call_history[FFF_CALL_HISTORY_LEN];

would allow this to work correctly for this scenario and maintain compliance with C99 (section 6.3.2.3, paragraph 8 - I assume also other versions of the standard but haven't checked). The user would then cast their mock functions to (fff_function_t) when comparing to the call history elements.

Also the definition of REGISTER_CALL(function) would have to change to e.g.

#define REGISTER_CALL(function) \
   if(fff.call_history_idx < FFF_CALL_HISTORY_LEN) \
       fff.call_history[fff.call_history_idx++] = (fff_function_t)function;

Readme describes nested function example as standard conforming

This statement from the README isn't accurate:

In case your project uses a C99 compliant C compiler you can even combine all this in a single unit test function so you can easily oversee all details of the test.

in the context of the code example that follows the paragraph:

// ...
TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_output)
{
    Time t;
    Time getTime_custom_now;
    void getTime_custom_fake(Time *now) {
        *now = getTime_custom_now;
    }
   // ...
}

ISO C99 doesn't specify nested functions. Nested functions aren't included in C11, as well. They are a GCC extension.

Perhaps you want to change this sentence to something like: In case your project uses a C compiler that supports nested functions (e.g. GCC) you can even combine all this in a single unit test function so you can easily oversee all details of the test.

Unable to mock ioctl

Hello,
I am trying to create a fake for the ioctl function, but I'm getting the following error when compiling (but not linking) my test.cpp file:
$ g++ -c -I../ -I$GTEST_DIR/include/ test.cpp
test.cpp:12:22: error: 'ioctl' has not been declared
test.cpp:12:64: error: expected constructor, destructor, or type conversion before ';' token

Line 12 of the test.cpp file contains the following:
FAKE_VALUE_FUNC(int, ioctl, int, unsigned long, unsigned long*);

Every other fake function has been declared successfully, except for ioctl. They have all been written in the same manner. These functions were implemented in another file of my own, the only "system" function mocked is ioctl.

Is there a special way to mock system or basic functions like this one?

Thank you.
Regards,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.