4. Special Cases
4.1. Working with doubles
We are not talking about
test doubles
here, but about values of C/C++ double
type (a.k.a double float.)
Cgreen is designed to make it easy and natural to write assertions
and expectations. Many functions can be used for multiple data types,
e.g. is_equal_to()
applies to all integer type values, actually
including pointers.
But the C language has its quirks. One of them is the fact that it is
impossible to inspect the datatypes of values during runtime. This
has e.g. forced the introduction of is_equal_to_string()
to enable
string comparisons.
4.1.1. Assertions and Constraints
When it comes to double typed values this has spilled over even further. For double typed values we have
Constraint 




But there is also the special assert that you must use when asserting doubles
Assertion 

and the utility function
Utility 

And of course they are designed to go together. So, if you want to assert
an expression yeilding a double
typed value, you need to combine them:
Ensure(Doubles, can_assert_double_values) {
significant_figures_for_assert_double_are(3);
assert_that_double(3.14, is_equal_to_double(5.0));
}
You have to use assert_that_double() and is_equal_to_double()
together.

and you would get
double_tests.c:13: Failure: can_assert_double_values Expected [3.14] to [equal double] [5.0] within [3] significant figures actual value: [3.140000] expected value: [5.000000]
4.1.2. Mocks
The general mechanism Cgreen uses to transport values to and from mock functions is based on the simple idea that most types fit into a "large" integer and can be type converted to and from whatever type you need.
Since a double float
will not fit into the same memory space as an
integer Cgreen handles that by encapsulating ("boxing") the double
into an area which is represented by the pointer to it. And that
pointer can fit into the integer type value (intptr_t
) that Cgreen
uses to transport values into and out of mock()
. To get the value
back you "unbox" it.
There are two possible uses of double
that you need to be
aware of

When a parameter to the mocked function is of
double
type and needs to be matched in an constraint in anexpect
call. 
When the mock function itself should return a
double
type value.
In the test you should use the special double
type constraints and
the will_return_double()
convenience function. In the mock function
you will have to take care to box and unbox as required.
Boxing and unboxing in mock functions 
Description 

Wrap the value in an allocated memory area and return a pointer to it 

Unwrap the value by freeing the area and returning the value 
Here’s an example of that:
static double double_out(int i, double d) {
return unbox_double(mock(i, box_double(d))); (1)
}
Ensure(Doubles, can_be_arguments_to_mock_and_returned) {
expect(double_out,
when(i, is_equal_to(15)),
when(d, is_equal_to_double(31.32)), (2)
will_return_double(3.1415926)); (3)
assert_that_double(double_out(15, 31.32), is_equal_to_double(3.1415926));
}
1  We can see that the parameter d to the mock function, since it is a
double , it will have to be used as box_double(d) in the call to
mock() . 
2  The corresponding expect() uses a double constraint. 
3  The mock function in this small example also returns a double . The
expect() uses will_return_double() so the mock function needs to
unbox the return value from mock() to be able to return the double
type value. 
Strange errors may occur if you box and/or unbox or combine
double constraints incorrectly.

4.1.3. Details of floating point comparison algorithm
The number of significant digits set with
significant_figures_for_assert_double_are()
specifies a relative
tolerance. Cgreen considers two double precision numbers x and y
equal if their difference normalized by the larger of the two is
smaller than 10^(1  significant_figures)^. Mathematically, we check
that x  y < max(x, y) * 10^(1  significant_figures)^.
Well documented subtleties arise when comparing floating point numbers close to zero using this algorithm. The article Comparing Floating Point Numbers, 2012 Edition by Bruce Dawson has an excellent discussion of the issue. The essence of the problem can be appreciated if we consider the special case where y == 0. In that case, our condition reduces to x < x * 10^(1  significant_figures)^. After cancelling x this simplifies to 1 < 10^(1  significant_figures)^. But this is only true if significant_figures < 1. In words this can be summarized by saying that, in a relative sense, all numbers are very different from zero. To circumvent this difficulty we recommend to use a constraint of the following form when comparing numbers close to zero:
assert_that(fabs(x  y) < abs_tolerance);
4.2. Using Cgreen with C++
The examples in this guide uses the C langauge to shows how to use CGreen. You can also use CGreen with C++.
The following needs expansion and more details as the support for C++ is extended. 
All you have to do is

Use the
cgreen
namespace by addingusing namespace cgreen;
at the beginning of the file with your tests
There is also one extra feature when you use C++, the assert_throws
function.
If you use the runner, as described in [runner], and thus link
your tests into a shared library, don’t forget to link it with the
same C++ library that was used to create the cgreenrunner .
