/* * (C) 2022 René Meusel * (C) 2026 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_TEST_ARB_EQ_H_ #define BOTAN_TEST_ARB_EQ_H_ #include "tests.h" #include #include #include #include namespace Botan_Tests { namespace detail { /* Does T have a member to_string() returning std::string? */ template constexpr bool has_member_to_string = false; template constexpr bool has_member_to_string().to_string())>> = std::is_convertible_v().to_string()), std::string>; /* Is std::to_string(T) defined? */ template constexpr bool has_std_to_string = false; template constexpr bool has_std_to_string()))>> = true; /* Is ostream<<(T) defined? */ template constexpr bool has_ostream_operator = false; template constexpr bool has_ostream_operator(), std::declval()))>> = true; /* Is T a std::optional? */ template struct is_optional : std::false_type {}; template struct is_optional> : std::true_type {}; template constexpr bool is_optional_v = is_optional::value; /* Is T a std::vector? */ template struct is_vector : std::false_type {}; template struct is_vector> : std::true_type {}; template constexpr bool is_vector_v = is_vector::value; /* Is T a std::array? */ template struct is_std_array : std::false_type {}; template struct is_std_array> : std::true_type {}; template constexpr bool is_std_array_v = is_std_array::value; template std::string to_string(const T& v) { if constexpr(detail::is_optional_v) { return (v.has_value()) ? to_string(v.value()) : std::string("std::nullopt"); } else if constexpr(detail::is_vector_v || detail::is_std_array_v) { std::ostringstream oss; oss << "{"; for(size_t i = 0; i != v.size(); ++i) { if(i > 0) { oss << ", "; } oss << to_string(v[i]); } oss << "}"; return oss.str(); } else if constexpr(detail::has_member_to_string) { return v.to_string(); } else if constexpr(detail::has_ostream_operator) { std::ostringstream oss; oss << v; return oss.str(); } else if constexpr(detail::has_std_to_string) { return std::to_string(v); } else { static_assert(!sizeof(T), "This type is not printable"); return ""; } } } // namespace detail template bool test_arb_eq(Test::Result& result, std::string_view what, const T& produced, const T& expected) { static_assert(!std::convertible_to>, "Use test_bin_eq"); static_assert(!std::convertible_to, "Use test_str_eq"); static_assert(!std::is_integral_v, "Use test_{sz,u8,u16,u32,u64}_eq"); static_assert(!std::is_enum_v, "Use test_enum_eq"); if(produced == expected) { return result.test_success(what); } else { std::ostringstream out; out << result.who() << " " << what << " produced unexpected result '" << detail::to_string(produced) << "' expected '" << detail::to_string(expected) << "'"; return result.test_failure(out.str()); } } } // namespace Botan_Tests #endif