55#define BITCOIN_TEST_UTIL_FRAMEWORK_H
66#pragma once
77
8+ #include < crypto/hex_base.h>
9+ #include < test/util/common.h>
810#include < tinyformat.h>
911
1012#include < algorithm>
@@ -113,31 +115,36 @@ inline void log(LogLevel level, const char* fmt, Args&&... args)
113115 }
114116}
115117
116- /* * Types that implement the `<<` operator. Pointers are excluded: operator<< for
117- * char-like pointers calls strlen on the pointee, which is unsafe for raw memory. */
118118template <typename T>
119- concept streamable = !std::is_pointer_v<T> && requires (std::ostream& os, const T& value) { os << value; };
120-
121- /* * Types that implement a `ToString()` member returning `std::string`. */
122- template <typename T>
123- concept has_to_string = requires (const T& value) {
124- { value.ToString () } -> std::same_as<std::string>;
125- };
119+ concept streamable = requires (std::ostream& os, const T& value) { os << value; };
126120
127121template <typename T>
128122concept is_cstring = std::is_same_v<std::decay_t <T>, const char *> || std::is_same_v<std::decay_t <T>, char *>;
129123
130124template <typename T>
131125std::string stringify (const T& value)
132126{
133- if constexpr (streamable<T>) {
127+ if constexpr (pointer<T>) {
128+ if (!value) return " nullptr" ;
129+ std::ostringstream os;
130+ os << static_cast <const void *>(value);
131+ return os.str ();
132+ } else if constexpr (streamable<T>) {
134133 std::ostringstream os;
135134 os << value;
136135 return os.str ();
137- } else if constexpr (has_to_string<T>) {
138- return value.ToString ();
136+ } else if constexpr (has_hex_str<T>) {
137+ return HexStr (value);
138+ } else if constexpr (has_serialize<T>) {
139+ DataStream ds;
140+ ds << value;
141+ return HexStr (ds);
142+ } else if constexpr (pair_like<T>) {
143+ return " (" + stringify (value.first ) + " , " + stringify (value.second ) + " )" ;
144+ } else if constexpr (is_variant<T>) {
145+ return std::visit ([](const auto & v) { return stringify (v); }, value);
139146 } else {
140- return typeid (T). name ( );
147+ static_assert ( sizeof (T) == 0 , " No stringify() for this type. " );
141148 }
142149}
143150
@@ -258,6 +265,10 @@ inline std::string current_test_full_name()
258265}
259266
260267
268+ template <std::ranges::range R1 , std::ranges::range R2 >
269+ requires std::equality_comparable_with<std::ranges::range_value_t <R1 >, std::ranges::range_value_t <R2 >>
270+ Result check_equal_ranges (const R1 & r1, const R2 & r2);
271+
261272/* * A captured expression is used to stringify the result before evaluation.
262273 * When an expression evaluates to `false`, the string is reported to the user. */
263274template <typename T>
@@ -280,16 +291,26 @@ struct CapturedExpression {
280291 template <typename U> \
281292 Result operator op (const U& rhs) const \
282293 { \
283- bool btc_test_result; \
284- if constexpr (is_cstring<T> && is_cstring<U>) { \
285- btc_test_result = (std::strcmp (lhs, rhs) op 0 ); \
286- } else if constexpr (std::is_integral_v<T> && std::is_integral_v<U> && \
287- std::is_signed_v<T> != std::is_signed_v<U>) { \
288- btc_test_result = cmp (lhs, rhs); \
294+ if constexpr (((#op)[0 ] == ' =' || (#op)[0 ] == ' !' ) && \
295+ non_string_range<T> && non_string_range<U>) { \
296+ if constexpr ((#op)[0 ] == ' =' ) { \
297+ return check_equal_ranges (lhs, rhs); \
298+ } else { \
299+ return Result::failed (" != on ranges is not supported" ); \
300+ } \
289301 } else { \
290- btc_test_result = static_cast <bool >(lhs op rhs); \
302+ bool btc_test_result; \
303+ if constexpr (is_cstring<T> && is_cstring<U>) { \
304+ btc_test_result = (std::strcmp (lhs, rhs) op 0 ); \
305+ } else if constexpr (std::is_integral_v<T> && std::is_integral_v<U> && \
306+ std::is_signed_v<T> != std::is_signed_v<U>) { \
307+ btc_test_result = cmp (lhs, rhs); \
308+ } else { \
309+ btc_test_result = static_cast <bool >(lhs op rhs); \
310+ } \
311+ return btc_test_result ? Result::ok () \
312+ : Result::failed (stringify (lhs) + " " #op " " + stringify (rhs)); \
291313 } \
292- return btc_test_result ? Result::ok () : Result::failed (stringify (lhs) + " " #op " " + stringify (rhs)); \
293314 }
294315
295316 DECOMPOSE_OP (==, std::cmp_equal)
@@ -802,16 +823,6 @@ using btc_suite_fixture = ::framework::EmptyFixture;
802823 #expr, __FILE__, __LINE__); \
803824 } while (false )
804825
805- /* * Passes if two ranges contain equal elements. Accepts any two types that
806- * satisfy std::ranges::range with comparable element types. */
807- #define CHECK_EQUAL_RANGES (a, b ) \
808- do { \
809- auto & btc_test_ctx_{::framework::test_context ()}; \
810- ::framework::Result btc_test_res_{::framework::check_equal_ranges ((a), (b))}; \
811- ::framework::record_check (btc_test_ctx_, btc_test_res_, " CHECK_EQUAL_RANGES" , \
812- #a " == " #b, __FILE__, __LINE__); \
813- } while (false )
814-
815826/* * Unconditionally records a failure with `msg`. Does not abort the test. */
816827#define RECORD_ERROR (msg ) \
817828 do { \
@@ -845,6 +856,22 @@ using btc_suite_fixture = ::framework::EmptyFixture;
845856 } \
846857 } while (false )
847858
859+ /* * Like CHECK, but the expression is evaluated as a plain bool: no
860+ * decomposition, no stringify of operands. On failure only the expression
861+ * text is reported. Use when either operand of `==` / `!=` lacks a
862+ * stringify path. */
863+ #define CHECK_NO_DISPLAY (expr, ...) \
864+ do { \
865+ auto & btc_test_ctx_{::framework::test_context ()}; \
866+ ::framework::Result btc_test_res_{static_cast <bool >(expr) ? ::framework::Result::ok () \
867+ : ::framework::Result::failed ({})}; \
868+ std::ostringstream btc_test_os_; \
869+ __VA_OPT__ (if (!btc_test_res_.is_ok ()) btc_test_os_ << __VA_ARGS__;) \
870+ ::framework::record_check (btc_test_ctx_, btc_test_res_, " CHECK_NO_DISPLAY" , #expr, __FILE__, \
871+ __LINE__, btc_test_res_.is_ok() ? std::string{} : btc_test_os_.str ()); \
872+ } while (false )
873+
874+ #define BOOST_CHECK_NO_DISPLAY (expr ) CHECK_NO_DISPLAY (expr)
848875#define BOOST_CHECK (expr ) CHECK (expr)
849876#define BOOST_REQUIRE (expr ) REQUIRE (expr)
850877#define BOOST_TEST (expr ) CHECK (expr)
@@ -871,7 +898,7 @@ using btc_suite_fixture = ::framework::EmptyFixture;
871898#define BOOST_TEST_MESSAGE (msg ) TEST_MESSAGE (msg)
872899#define BOOST_WARN_MESSAGE (expr, msg ) WARN_MESSAGE (expr, msg)
873900#define BOOST_CHECK_EQUAL_COLLECTIONS (ab, ae, bb, be ) \
874- CHECK_EQUAL_RANGES (std::ranges::subrange ((ab), (ae)), std::ranges::subrange ((bb), (be)))
901+ CHECK (std::ranges::subrange ((ab), (ae)) == std::ranges::subrange ((bb), (be)))
875902#define BOOST_AUTO_TEST_CASE (name ) FIXTURE_TEST_CASE (name, btc_suite_fixture)
876903#define BOOST_FIXTURE_TEST_CASE (name, F ) \
877904 using name = F; \
0 commit comments