Git Product home page Git Product logo

fff's Introduction

Hi there 👋

👋 Hello! I'm Mike Long (@meekrosoft).

I am the CEO at Kosli!

 

  • 😄 Pronouns: he/him
  • 🖍️  I have a strong passion for DevOps and Startup Life
  • 💬  I like to talk about devops, regulated software, crosswords and puzzles. 
  • 🙌  Check out Kosli's site!
  • 💻  Connect with me on LinkedIn
  • 🐦  Let's talk more on Twitter
  • 📫  How to reach me [email protected]
  • 👨‍💻  Formerly the CTO of Praqma

✍️ All the latest articles, tweets and activity @ Merkely.

🐦 Twitter 💻 LinkedIn 🖥️ Kosli.com

 

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

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!

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 :-)

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.

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()?

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.

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?

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 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.

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.

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,

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).

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?

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 \

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.

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).

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?

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?

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

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

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?

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).

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,

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?

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

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

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

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?

Fake function problem

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

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?

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.

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

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!

(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;

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.

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)

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!

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.

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.

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.

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

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.

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

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.