diff options
author | Arnaud Gelas <arnaud.gelas@sensefly.com> | 2019-01-15 17:33:14 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-01-22 13:24:26 +0100 |
commit | 10f50a294f876b6419bd1e297f2a84913736a35c (patch) | |
tree | 725fc1ef60bfa30edcba36e3abe63e93ebc64624 | |
parent | bd0667c6d99019843b4893393f2ab4d3e6b43468 (diff) | |
download | cmocka-10f50a294f876b6419bd1e297f2a84913736a35c.tar.gz cmocka-10f50a294f876b6419bd1e297f2a84913736a35c.tar.xz cmocka-10f50a294f876b6419bd1e297f2a84913736a35c.zip |
include: Add new assert macros to compare 2 floats given an epsilon.
assert_float_equal and assert_float_not_equal
-rw-r--r-- | include/cmocka.h | 55 | ||||
-rw-r--r-- | src/cmocka.c | 77 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/test_float_macros.c | 37 |
4 files changed, 170 insertions, 0 deletions
diff --git a/include/cmocka.h b/include/cmocka.h index 377c696..e7a3783 100644 --- a/include/cmocka.h +++ b/include/cmocka.h @@ -106,6 +106,10 @@ typedef uintmax_t LargestIntegralType; # endif /* _WIN32 */ #endif /* LargestIntegralTypePrintfFormat */ +#ifndef FloatPrintfFormat +# define FloatPrintfFormat "%f" +#endif /* FloatPrintfFormat */ + /* Perform an unsigned cast to LargestIntegralType. */ #define cast_to_largest_integral_type(value) \ ((LargestIntegralType)(value)) @@ -1235,6 +1239,51 @@ void assert_int_not_equal(int a, int b); #ifdef DOXYGEN /** + * @brief Assert that the two given float are equal given an epsilon. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the float are not equal (given an epsilon). + * + * @param[in] a The first float to compare. + * + * @param[in] b The float to compare against the first one. + * + * @param[in] epsilon The epsilon used as margin for float comparison. + */ +void assert_float_equal(float a, float b, float epsilon); +#else +#define assert_float_equal(a, b, epsilon) \ + _assert_float_equal((float)a, \ + (float)b, \ + (float)epsilon, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given float are not equal given an epsilon. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the float are not equal (given an epsilon). + * + * @param[in] a The first float to compare. + * + * @param[in] b The float to compare against the first one. + * + * @param[in] epsilon The epsilon used as margin for float comparison. + */ +void assert_float_not_equal(float a, float b, float epsilon); +#else +#define assert_float_not_equal(a, b, epsilon) \ + _assert_float_not_equal((float)a, \ + (float)b, \ + (float)epsilon, \ + __FILE__, __LINE__) +#endif + + +#ifdef DOXYGEN +/** * @brief Assert that the two given strings are equal. * * The function prints an error message to standard error and terminates the @@ -2217,6 +2266,12 @@ void _assert_return_code(const LargestIntegralType result, const char * const expression, const char * const file, const int line); +void _assert_float_equal(const float a, const float n, + const float epsilon, const char* const file, + const int line); +void _assert_float_not_equal(const float a, const float n, + const float epsilon, const char* const file, + const int line); void _assert_int_equal( const LargestIntegralType a, const LargestIntegralType b, const char * const file, const int line); diff --git a/src/cmocka.c b/src/cmocka.c index 4ae65b7..ff79161 100644 --- a/src/cmocka.c +++ b/src/cmocka.c @@ -43,6 +43,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#include <float.h> /* * This allows to add a platform specific header file. Some embedded platforms @@ -1122,6 +1123,62 @@ void _expect_function_call( list_add_value(&global_call_ordering_head, ordering, count); } +/* Returns 1 if the specified float values are equal, else returns 0. */ +static int float_compare(const float left, + const float right, + const float epsilon) { + float absLeft; + float absRight; + float largest; + float relDiff; + + float diff = left - right; + diff = (diff >= 0.f) ? diff : -diff; + + // Check if the numbers are really close -- needed + // when comparing numbers near zero. + if (diff <= epsilon) { + return 1; + } + + absLeft = (left >= 0.f) ? left : -left; + absRight = (right >= 0.f) ? right : -right; + + largest = (absRight > absLeft) ? absRight : absLeft; + relDiff = largest * FLT_EPSILON; + + if (diff > relDiff) { + return 0; + } + return 1; +} + +/* Returns 1 if the specified float values are equal. If the values are not equal + * an error is displayed and 0 is returned. */ +static int float_values_equal_display_error(const float left, + const float right, + const float epsilon) { + const int equal = float_compare(left, right, epsilon); + if (!equal) { + cm_print_error(FloatPrintfFormat " != " + FloatPrintfFormat "\n", left, right); + } + return equal; +} + +/* Returns 1 if the specified float values are different. If the values are equal + * an error is displayed and 0 is returned. */ +static int float_values_not_equal_display_error(const float left, + const float right, + const float epsilon) { + const int not_equal = (float_compare(left, right, epsilon) == 0); + if (!not_equal) { + cm_print_error(FloatPrintfFormat " == " + FloatPrintfFormat "\n", left, right); + } + return not_equal; +} + /* Returns 1 if the specified values are equal. If the values are not equal * an error is displayed and 0 is returned. */ static int values_equal_display_error(const LargestIntegralType left, @@ -1714,6 +1771,26 @@ void _assert_return_code(const LargestIntegralType result, } } +void _assert_float_equal(const float a, + const float b, + const float epsilon, + const char * const file, + const int line) { + if (!float_values_equal_display_error(a, b, epsilon)) { + _fail(file, line); + } +} + +void _assert_float_not_equal(const float a, + const float b, + const float epsilon, + const char * const file, + const int line) { + if (!float_values_not_equal_display_error(a, b, epsilon)) { + _fail(file, line); + } +} + void _assert_int_equal( const LargestIntegralType a, const LargestIntegralType b, const char * const file, const int line) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f7ea00b..1e93940 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ set(CMOCKA_TESTS test_fixtures test_group_fixtures test_groups + test_float_macros test_assert_macros test_assert_macros_fail test_basics diff --git a/tests/test_float_macros.c b/tests/test_float_macros.c new file mode 100644 index 0000000..38dcb6d --- /dev/null +++ b/tests/test_float_macros.c @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Arnaud Gelas <arnaud.gelas@sensefly.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Use the unit test allocators */ +#define UNIT_TESTING 1 + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +/* A test case that does check if float is equal. */ +static void float_test_success(void **state) { + assert_float_equal(0.5f, 1.f / 2.f, 0.000001f); + assert_float_not_equal(0.5, 0.499f, 0.000001f); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(float_test_success), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |