Setting and getting a function pointer on a mock

2,529 views
Skip to first unread message

Mikkel Jakobsen

unread,
Feb 23, 2016, 10:55:58 AM2/23/16
to cpputest
I have a problem with setting and getting a callback from a mock. The code under test will inject a callback into a submodul which I have mocked, and I need get that callback function so I can use it to inject data into the code under test. The following code snippet is a simplified version of my setup.

 // In a header file:
 
typedef struct
 
{
     uint8_t
*data;
     uint16_t data_length
;
 
} network_dto;

 
typedef void (*net_rx_callback)(network_dto dto);

 
void network_setup(net_rx_callback cb);



 
// In my mock file:
 
void network_setup(net_rx_callback cb)
 
{
     mock
("network").setData("cb", (void*)cb);
     mock
("network").actualCall("network_setup");
 
}



 
// In my test:
 net_rx_callback callback_pointer
;

 TEST
(network, callback_test)
 
{
     mock
("network")
         
.expectOneCall("network_setup")
         
.ignoreOtherParameters();

     network_setup
(test_callback);

     callback_pointer
= (net_rx_callback)(mock("network").getData("cb").getPointerValue());
 
}

 
void test_callback(network_dto dto)
 
{
     
// whatever
 
}

When I run the test, I get a failed test from MockNamedValue.cpp:184 stating that the type is not a "void*" as expected, but rather "int". I'm having difficulty understanding this, as I'm explicitly casting the input to setData to void*.

It's probably something simple I'm not seeing, but I could use some help in getting on with this issue. 

Regards,
Mikkel

Mikkel Jakobsen

unread,
Feb 23, 2016, 11:26:05 AM2/23/16
to cpputest
The plot thickens.

When I run my test suite, which is purely C++ code, the provided example actually works just fine and the test passes. However, when I add in the tests for my actual codeproject, which is written purely in C, things go bad and the tests fail.

I only have a limited knowledge of C++, so I'm just guessing here, but it seems that the function pointers that are passed to the mock from my C code are treated as integers instead of void pointers, where as this is not the case for function pointers passed from C++.

A. Robert S.

unread,
Feb 26, 2016, 8:45:28 AM2/26/16
to cpputest
Hi Mikkel,

I couldn't take time to look at this in detail. However, from my own experience I know that the type of a MockNamedValue defaults to "int", so its being "int" when it shouldn't be often suggests that it has not been initialized. Off-hand, I can't think of a reason why that should be so, but maybe it helps.

Regards,
Robert

Bas Vodde

unread,
Feb 26, 2016, 6:10:57 PM2/26/16
to cppu...@googlegroups.com

HI Mikkel,

You mean, exactly the same files? You only changed project?

I put all the code you send in one C++ file and it worked fine :P Could you make a minimal failing example and send that?

Thanks!

Bas


--
You received this message because you are subscribed to the Google Groups "cpputest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Mikkel Jakobsen

unread,
Mar 10, 2016, 10:23:46 AM3/10/16
to cpputest
I'm probably doing something wrong then. 

I managed to work around my problems, but I will try to reproduce my pain sometime next weekend when schedule allows it.

/Mikkel

A. Robert S.

unread,
Mar 17, 2016, 2:49:36 AM3/17/16
to cpputest
#include "CppUTest/CommandLineTestRunner.h"
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"


// In a header file:
 
typedef struct
 
{
     uint8_t
*data;
     uint16_t data_length
;
 
} network_dto;

 
typedef void (*net_rx_callback)(network_dto dto);

 
void network_setup(net_rx_callback cb);

 
// In my mock file:
 
void network_setup(net_rx_callback cb)
 
{
     mock
("network").setData("cb", (void*)cb);
     mock
("network").actualCall("network_setup");
 
}

// In my test:
net_rx_callback callback_pointer
;
 
void test_callback(network_dto)
{
     
// whatever
}

TEST_GROUP
(network) {};

 
TEST
(network, callback_test)
{
    mock
("network")
         
.expectOneCall("network_setup")
         
.ignoreOtherParameters();

    network_setup
(test_callback);


    callback_pointer
= (net_rx_callback)(mock("network").getData("cbx").getPointerValue());
   
    mock
().clear();
}
 
int main(int argc, char** argv) {
   
return RUN_ALL_TESTS(argc, argv);
}

I put all your code into one file as above. I can provoke the error by misspelling the name in getData() as "cbx" (see my comment above). I believe there is a very strong possibility that you are calling getData() on an entity you didn't set. I have run into this myself on various occasions.

@basvodde when this happens, wouldn't it be better to let getData fail with a message such as "Error: getData(): Attempt to retrieve data that wasn't set" ?
Reply all
Reply to author
Forward
0 new messages