From b22ae661b4dc4d09acb3d80dce4cb49dd823b89f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 6 Nov 2024 15:29:07 +0100 Subject: [PATCH] Move other ASSERT_EQUAL_XXX macros to a header too Prepare for reusing them from other source files. Note that this requires using test_context from test-assert.h, which now has to include test-context.h. --- tests/common/test-common.cpp | 68 -------------------------------- tests/test-assert.h | 75 +++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 69 deletions(-) diff --git a/tests/common/test-common.cpp b/tests/common/test-common.cpp index d45b5b5f..13f27ff4 100644 --- a/tests/common/test-common.cpp +++ b/tests/common/test-common.cpp @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include #include @@ -47,7 +45,6 @@ #include "soci-mktime.h" #include "test-assert.h" -#include "test-context.h" #include "test-myint.h" // Although SQL standard mandates right padding CHAR(N) values to their length @@ -187,71 +184,6 @@ template<> struct type_conversion namespace tests { -// Compare doubles for approximate equality. This has to be used everywhere -// where we write "3.14" (or "6.28") to the database as a string and then -// compare the value read back with the literal 3.14 floating point constant -// because they are not the same. -// -// It is also used for the backends which currently don't handle doubles -// correctly. -// -// Notice that this function is normally not used directly but rather from the -// macro below. -inline bool are_doubles_approx_equal(double const a, double const b) -{ - // The formula taken from CATCH test framework - // https://github.com/philsquared/Catch/ - // Thanks to Richard Harris for his help refining this formula - double const epsilon(std::numeric_limits::epsilon() * 100); - double const scale(1.0); - return std::fabs(a - b) < epsilon * (scale + (std::max)(std::fabs(a), std::fabs(b))); -} - -// This is a macro to ensure we use the correct line numbers. The weird -// do/while construction is used to make this a statement and the even weirder -// condition in while ensures that the loop is executed exactly once without -// triggering warnings from MSVC about the condition being always false. -#define ASSERT_EQUAL_APPROX(a, b) \ - do { \ - if (!are_doubles_approx_equal((a), (b))) { \ - FAIL( "Approximate equality check failed: " \ - << std::fixed \ - << std::setprecision(std::numeric_limits::digits10 + 1) \ - << (a) << " != " << (b) ); \ - } \ - } while ( (void)0, 0 ) - - -// Compare two floating point numbers either exactly or approximately depending -// on test_context::has_fp_bug() return value. -inline bool -are_doubles_equal(test_context_base const& tc, double a, double b) -{ - return tc.has_fp_bug() - ? are_doubles_approx_equal(a, b) - : are_doubles_exactly_equal(a, b); -} - -// This macro should be used when where we don't have any problems with string -// literals vs floating point literals mismatches described above and would -// ideally compare the numbers exactly but, unfortunately, currently can't do -// this unconditionally because at least some backends are currently buggy and -// don't handle the floating point values correctly. -// -// This can be only used from inside the common_tests class as it relies on -// having an accessible "tc_" variable to determine whether exact or -// approximate comparison should be used. -#define ASSERT_EQUAL(a, b) \ - do { \ - if (!are_doubles_equal(tc_, (a), (b))) { \ - FAIL( "Equality check failed: " \ - << std::fixed \ - << std::setprecision(std::numeric_limits::digits10 + 1) \ - << (a) << " != " << (b) ); \ - } \ - } while ( (void)0, 0 ) - - // Define the test cases in their own namespace to avoid clashes with the test // cases defined in individual backend tests: as only line number is used for // building the name of the "anonymous" function by the TEST_CASE macro, we diff --git a/tests/test-assert.h b/tests/test-assert.h index 76cacc36..54606eca 100644 --- a/tests/test-assert.h +++ b/tests/test-assert.h @@ -10,6 +10,11 @@ #include "soci-compiler.h" +#include +#include + +#include "test-context.h" + namespace soci { @@ -29,11 +34,59 @@ are_doubles_exactly_equal(double a, double b) SOCI_GCC_WARNING_RESTORE(float-equal) } +// Compare doubles for approximate equality. This has to be used everywhere +// where we write "3.14" (or "6.28") to the database as a string and then +// compare the value read back with the literal 3.14 floating point constant +// because they are not the same. +// +// It is also used for the backends which currently don't handle doubles +// correctly. +// +// Notice that this function is normally not used directly but rather from the +// macro below. +inline bool are_doubles_approx_equal(double const a, double const b) +{ + // The formula taken from CATCH test framework + // https://github.com/philsquared/Catch/ + // Thanks to Richard Harris for his help refining this formula + double const epsilon(std::numeric_limits::epsilon() * 100); + double const scale(1.0); + return std::fabs(a - b) < epsilon * (scale + (std::max)(std::fabs(a), std::fabs(b))); +} + +// Compare two floating point numbers either exactly or approximately depending +// on test_context::has_fp_bug() return value. +inline bool +are_doubles_equal(test_context_base const& tc, double a, double b) +{ + return tc.has_fp_bug() + ? are_doubles_approx_equal(a, b) + : are_doubles_exactly_equal(a, b); +} + } // namespace tests } // namespace soci -// This macro can be only used inside CATCH tests. +// Define macros for comparing floating point numbers. +// +// All of them can only be used inside CATCH test cases. + +// This is a macro to ensure we use the correct line numbers. The weird +// do/while construction is used to make this a statement and the even weirder +// condition in while ensures that the loop is executed exactly once without +// triggering warnings from MSVC about the condition being always false. +#define ASSERT_EQUAL_APPROX(a, b) \ + do { \ + if (!are_doubles_approx_equal((a), (b))) { \ + FAIL( "Approximate equality check failed: " \ + << std::fixed \ + << std::setprecision(std::numeric_limits::digits10 + 1) \ + << (a) << " != " << (b) ); \ + } \ + } while ( (void)0, 0 ) + + #define ASSERT_EQUAL_EXACT(a, b) \ do { \ if (!are_doubles_exactly_equal((a), (b))) { \ @@ -44,4 +97,24 @@ are_doubles_exactly_equal(double a, double b) } \ } while ( (void)0, 0 ) +// This macro should be used when where we don't have any problems with string +// literals vs floating point literals mismatches described above and would +// ideally compare the numbers exactly but, unfortunately, currently can't do +// this unconditionally because at least some backends are currently buggy and +// don't handle the floating point values correctly. +// +// This can be only used from inside the common_tests class as it relies on +// having an accessible "tc_" variable to determine whether exact or +// approximate comparison should be used. +#define ASSERT_EQUAL(a, b) \ + do { \ + if (!are_doubles_equal(tc_, (a), (b))) { \ + FAIL( "Equality check failed: " \ + << std::fixed \ + << std::setprecision(std::numeric_limits::digits10 + 1) \ + << (a) << " != " << (b) ); \ + } \ + } while ( (void)0, 0 ) + + #endif // SOCI_TEST_ASSERT_H_INCLUDED