ThrowTheSwitch / CMock

CMock - Mock/stub generator for C
http://throwtheswitch.org
MIT License
653 stars 269 forks source link

CMock doesn't allow you to store function pointer arguments #416

Open mattconway1984 opened 1 year ago

mattconway1984 commented 1 year ago

There's no sane method to store a function pointer passed to a mocked function, you are forced to use myFunction_AddCallback(myCallback) to then grab the function pointer within myCallback. Surely cMock is capable of identifying an argument that itself is a function pointer, and then adding a generated method such as myFunction_InvokeCallbackArg_<ARGNAME>.

Consider the following header file:

typedef void (*callback_fn)(int);
void registerCallback(callback_fn callback);

Code Under Test:

static void myCallback(int value)
{
  printf("I have been called, value=%d\n", value);
}

void methodUnderTest(void)
{
  // Register my callback:
  registerCallback(myCallback);
}

Test Code:

/// START: BOILER PLATE TEST CODE FOR STORING A CALLBACK PASSED TO A MOCKED METHOD
gRegisteredCallback = NULL;
void registerCallbackStub(callback_fn callback, int numCalls)
{
  (void)numCalls; // not used.

  // store the registered callback method
  gRegisteredCallback = callback;
}
/// END: BOILER PLATE TEST CODE FOR STORING A CALLBACK PASSED TO A MOCKED METHOD

void test_something(void)
{
  // setup the cmock
  registerCallback_StubWithCallback(registerCallbackStub);

  // Call the method under test, which should register a callback (which will be stored for later use in the test)
  methodUnderTest();
}
mvandervoord commented 1 year ago

Interesting. I'd not considered testing a callback function in this way. It has a certain elegance to it... in that the callback doesn't have to become public in order to test it.

I think this makes sense to be another CMock plugin. It's not a feature that would get used often, but certainly often enough to make it worth building! Thanks for the idea!

mattconway1984 commented 1 year ago

I think this also lends itself to pointer arguments which are pointers to a data structure, in some cases I've come across complex structures where the values of all members are not known or required (so the memory compare doesn't apply for this case where just several members need to be compared). This considered, maybe rather than InvokeCallback something like GetPointerArg would be better (i.e. capture the function pointer, or pointer to context data etc.), if the test knows its a function pointer it can "get" it and then call it.