cunit-testingmockingcmocka

How do I pass a double value to my C mock function with cmocka will_return()?


I am using cmocka to unit test a C project.

I want to mock a call to another modules made in my C function under test. This function in the other module deals with doubles, not ints. The will_return documentation says it passes integer values, and I can see that if I call will_return(__wrap_other_func, 42.99) then the value passed into __wrap_other_func and pulled out through double value = mock_type(double) will be 42.0, not the desired 42.99.

double __wrap_other_func(double param) {
  check_expected(param);
  double value = mock_type(double); // will_return() has converted this, effectively rounding
  fprintf(stderr, "%lf\n", value);
  return value;
}

static void test_this_func(void **state) {
  (void) state;
  expect_value(__wrap_other_func, param, 1.0);
  will_return(__wrap_other_func, 42.99);
  int result = this_func(12.34); // this_func() will call other_func()
  ...
  assert(result == 0); 
  /* the assert is failing because the double 42.99 is converted to an integer,
     then back to a double, rounding off all the decimal places. */
}

> 42.0

Has anyone figured out how to pass doubles into the mock function with will_return or some other cmocka method? I'm stuck on this.

I was expecting to be able to pass non-integer values to my mock function using cmocka.

When I tried that using will_return(), I found all double values were rounded to integer equivalents.

I have pored over the cmocka documentation and searched for cmocka examples online.

Update 2023-11-19 I have a solution.

The cmocka main repo at cryptomilk was updated by Andreas Schneider so that mocks work with real numbers (floats and doubles) as expected. Thank you Andreas!

With the 2023-11-17 head of the main branch built and installed on my system, this code now works as expected.

double __wrap_other_func(double param) {
  // verify that the expected value was passed in to the mock
  check_expected(param);
  // assign the return value
  double value = mock_float; 
// will_return_float() can deal with real numbers (doubles and floats)
  fprintf(stderr, "%lf\n", value); // this will print the real number value now
  return value;
}

static void test_this_func(void **state) {
  (void) state;
  // make sure the argument passed to the mock is correct
  expect_value(__wrap_other_func, param, 1.0);
  // tell the mock what to return
  will_return_float(__wrap_other_func, 42.99);
  // call this_func normally. The mock for other_func will get called
  int result = this_func(12.34); // this_func() will call other_func()
  ...
  assert(result == 0); 
  // the assert is now passing because the double 42.99 remains a double
}

> 42.99

Thanks to everyone who offered comments and answers.


Solution

  • The intended way is to use will_return_float and mock_float

    There are also other "assigning" macros:

    to use instead of the "casting" macros will_return and mock_type

    Side note: mock_float doesn't take macro arguments, as of now it stores the value as a double