#include #include #include #include namespace xrpl { struct TER_test : public beast::unit_test::suite { void testTransResultInfo() { for (auto i = -400; i < 400; ++i) { TER t = TER::fromInt(i); auto inRange = isTelLocal(t) || isTemMalformed(t) || isTefFailure(t) || isTerRetry(t) || isTesSuccess(t) || isTecClaim(t); std::string token, text; auto good = transResultInfo(t, token, text); BEAST_EXPECT(inRange || !good); BEAST_EXPECT(transToken(t) == (good ? token : "-")); BEAST_EXPECT(transHuman(t) == (good ? text : "-")); auto code = transCode(token); BEAST_EXPECT(good == !!code); BEAST_EXPECT(!code || *code == t); } } // Helper template that makes sure two types are not convertible or // assignable if not the same. // o I1 one tuple index. // o I2 other tuple index. // o Tup is expected to be a tuple. // It's a functor, rather than a function template, since a class template // can be a template argument without being full specified. template class NotConvertible { public: template void operator()(Tup const& tup, beast::unit_test::suite&) const { // Entries in the tuple should not be convertible or assignable // unless they are the same types. using To_t = std::decay_t(tup))>; using From_t = std::decay_t(tup))>; static_assert( std::is_same::value == std::is_convertible::value, "Convert err"); static_assert( std::is_same::value == std::is_constructible::value, "Construct err"); static_assert( std::is_same::value == std::is_assignable::value, "Assign err"); // Assignment or conversion from integer to type should never work. static_assert( !std::is_convertible::value, "Convert err"); static_assert( !std::is_constructible::value, "Construct err"); static_assert( !std::is_assignable::value, "Assign err"); } }; // Fast iteration over the tuple. template < std::size_t I1, std::size_t I2, template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { Func func; func(tup, s); testIterate(tup, s); } // Slow iteration over the tuple. template < std::size_t I1, std::size_t I2, template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { Func func; func(tup, s); testIterate::value - 1, I2 - 1, Func>(tup, s); } // Finish iteration over the tuple. template < std::size_t I1, std::size_t I2, template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { Func func; func(tup, s); } void testConversion() { // Verify that valid conversions are valid and invalid conversions // are not valid. // Examples of each kind of enum. static auto const terEnums = std::make_tuple( telLOCAL_ERROR, temMALFORMED, tefFAILURE, terRETRY, tesSUCCESS, tecCLAIM); static int const hiIndex{ std::tuple_size::value - 1}; // Verify that enums cannot be converted to other enum types. testIterate(terEnums, *this); // Lambda that verifies assignability and convertibility. auto isConvertable = [](auto from, auto to) { using From_t = std::decay_t; using To_t = std::decay_t; static_assert( std::is_convertible::value, "Convert err"); static_assert( std::is_constructible::value, "Construct err"); static_assert( std::is_assignable::value, "Assign err"); }; // Verify the right types convert to NotTEC. NotTEC const notTec; isConvertable(telLOCAL_ERROR, notTec); isConvertable(temMALFORMED, notTec); isConvertable(tefFAILURE, notTec); isConvertable(terRETRY, notTec); isConvertable(tesSUCCESS, notTec); isConvertable(notTec, notTec); // Lambda that verifies types and not assignable or convertible. auto notConvertible = [](auto from, auto to) { using To_t = std::decay_t; using From_t = std::decay_t; static_assert( !std::is_convertible::value, "Convert err"); static_assert( !std::is_constructible::value, "Construct err"); static_assert( !std::is_assignable::value, "Assign err"); }; // Verify types that shouldn't convert to NotTEC. TER const ter; notConvertible(tecCLAIM, notTec); notConvertible(ter, notTec); notConvertible(4, notTec); // Verify the right types convert to TER. isConvertable(telLOCAL_ERROR, ter); isConvertable(temMALFORMED, ter); isConvertable(tefFAILURE, ter); isConvertable(terRETRY, ter); isConvertable(tesSUCCESS, ter); isConvertable(tecCLAIM, ter); isConvertable(notTec, ter); isConvertable(ter, ter); // Verify that you can't convert from int to ter. notConvertible(4, ter); } // Helper template that makes sure two types are comparable. Also // verifies that one of the types does not compare to int. // o I1 one tuple index. // o I2 other tuple index. // o Tup is expected to be a tuple. // It's a functor, rather than a function template, since a class template // can be a template argument without being full specified. template class CheckComparable { public: template void operator()(Tup const& tup, beast::unit_test::suite& s) const { // All entries in the tuple should be comparable one to the other. auto const lhs = std::get(tup); auto const rhs = std::get(tup); static_assert( std::is_same::value, "== err"); static_assert( std::is_same::value, "!= err"); static_assert( std::is_same::value, "< err"); static_assert( std::is_same::value, "<= err"); static_assert( std::is_same(lhs, rhs)), bool>::value, "> err"); static_assert( std::is_same=(lhs, rhs)), bool>::value, ">= err"); // Make sure a sampling of TER types exhibit the expected behavior // for all comparison operators. s.expect((lhs == rhs) == (TERtoInt(lhs) == TERtoInt(rhs))); s.expect((lhs != rhs) == (TERtoInt(lhs) != TERtoInt(rhs))); s.expect((lhs < rhs) == (TERtoInt(lhs) < TERtoInt(rhs))); s.expect((lhs <= rhs) == (TERtoInt(lhs) <= TERtoInt(rhs))); s.expect((lhs > rhs) == (TERtoInt(lhs) > TERtoInt(rhs))); s.expect((lhs >= rhs) == (TERtoInt(lhs) >= TERtoInt(rhs))); } }; void testComparison() { // All of the TER-related types should be comparable. // Examples of all the types we expect to successfully compare. static auto const ters = std::make_tuple( telLOCAL_ERROR, temMALFORMED, tefFAILURE, terRETRY, tesSUCCESS, tecCLAIM, NotTEC{telLOCAL_ERROR}, TER{tecCLAIM}); static int const hiIndex{std::tuple_size::value - 1}; // Verify that all types in the ters tuple can be compared with all // the other types in ters. testIterate(ters, *this); } void run() override { testTransResultInfo(); testConversion(); testComparison(); } }; BEAST_DEFINE_TESTSUITE(TER, protocol, xrpl); } // namespace xrpl