From e748fa1a10e48fa686fa37d6057b854337b21a0d Mon Sep 17 00:00:00 2001 From: Klevanets Igor Date: Wed, 24 Jul 2019 22:35:12 +0300 Subject: [PATCH] Improve tests --- v3/main.cpp | 387 ++++++++++++++++++++++++++++------------------------ 1 file changed, 210 insertions(+), 177 deletions(-) diff --git a/v3/main.cpp b/v3/main.cpp index 12598a3..b4653be 100644 --- a/v3/main.cpp +++ b/v3/main.cpp @@ -8,10 +8,10 @@ using namespace std; -#define assert(a, info) \ - { \ - if (!(a)) \ - throw std::runtime_error(#a ", line:" + std::to_string(__LINE__) + ", info:" + info); \ +#define assert(a, info) \ + { \ + if (!(a)) \ + throw std::runtime_error(#a ", line:" + std::to_string(__LINE__) + ", info: " + info); \ } struct _test { @@ -27,6 +27,84 @@ struct _test { std::cerr << std::hex << std::setw(16) << std::setfill('0') << n << std::endl; } + template + static auto _getStdNum(T n) { + using Num = decltype(n); + static_assert(std::numeric_limits::is_integer, ""); + static_assert(sizeof(n) == 4 || sizeof(n) == 8 || sizeof(n) == 16 || sizeof(n) == 64, ""); + using StdNum = std::conditional_t ::is_signed, + std::conditional_t || sizeof(n) <= 4, int32_t, int64_t>, + std::conditional_t || sizeof(n) <= 4, uint32_t, uint64_t>>; + return StdNum(n); + }; + + template + static std::string _typeInfo(T val) { + std::stringstream s; + s << typeid(decltype(val)).name() << "(" << (sizeof(val)*8) << " bits;" << (std::numeric_limits::is_signed ? "signed" : "unsigned") << ")"; + return s.str(); + }; + + template + static void _compare2Nums(T1 commonRes, T2 stdRes, int lineNo, const char* details_) { + std::string details; + if (details_) { + details.assign(details_); + } + assert(typeid(_getStdNum(commonRes)) == typeid(stdRes), + "should be: " + _typeInfo(stdRes) + ". mapped type: " + _typeInfo(_getStdNum(commonRes)) + ". actual type: " + _typeInfo(commonRes) + ". line=" + std::to_string(lineNo) + ": " + details); + + auto fail = [&](const std::string& msg) { + std::cerr << "Common number:" << std::endl; + printNum(commonRes); + std::cerr << "Std number:" << std::endl; + printNum(stdRes); + throw std::runtime_error("check failed: " + msg + ". line=" + std::to_string(lineNo) + ": " + details); + }; + + if ((commonRes & 0xFF) != (stdRes & 0xFF)) { + fail("first byte mismatch"); + } + + auto getLastByte = [](const auto& num) -> unsigned char { + const int bits = (sizeof(num) - 1) * 8; + return (num >> bits) & 0xFF; + }; + if (getLastByte(commonRes) != getLastByte(stdRes)) { + fail("last byte mismatch"); + } + + unsigned char middleByte = (stdRes >> 8) & 0xFF; + for (size_t idx = 1; idx < sizeof(commonRes)/8 - 1; ++idx) { + if (commonRes.m_arr[idx] != middleByte) { + fail("middle byte mismatch"); + } + } + }; + + template + static void _testUnaryOperator(Func func, Num num, int lineNo = 0, const char* details = nullptr) { + auto commonRes = func(num); + static_assert(std::is_same_v, ""); + + auto stdNum = _getStdNum(num); + auto stdRes = func(stdNum); + + _compare2Nums(commonRes, stdRes, lineNo, details); + } + + template + static void _testBinaryOperator(Func func, Num1 num1, Num2 num2, int lineNo = 0, const char* details = nullptr) { + auto commonRes = func(num1, num2); + static_assert(std::is_same_v, ""); + + auto stdNum1 = _getStdNum(num1); + auto stdNum2 = _getStdNum(num2); + auto stdRes = func(stdNum1, stdNum2); + + _compare2Nums(commonRes, stdRes, lineNo, details); + } + static void testCtors() { int512_t a1 = 0; for (auto c : a1.m_arr) { @@ -1399,188 +1477,139 @@ struct _test { assert(a1 == 7000000000000000000_int256, ""); } - static void testNativeOperators() { - auto a1 = ~uint512_t(0xff); - assert(typeid(uint512_t) == typeid(a1), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a1.m_arr[idx] == 0xff, std::to_string(idx)); - } - assert(a1.m_arr[63] == 0x00, ""); - - auto a2 = -uint512_t(0x1); - assert(typeid(uint512_t) == typeid(a2), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a2.m_arr[idx] == 0xff, std::to_string(idx)); - } - - auto a3 = 2 * uint512_t(0x1); - assert(typeid(uint512_t) == typeid(a3), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a3.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a3.m_arr[63] == 2, ""); - - auto a4 = uint512_t(0x1) * 2; - assert(typeid(uint512_t) == typeid(a4), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a4.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a4.m_arr[63] == 2, ""); - - auto a5 = 4 / uint512_t(0x2); - assert(typeid(uint512_t) == typeid(a5), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a5.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a5.m_arr[63] == 2, ""); - - auto a6 = uint512_t(0x4) / 2; - assert(typeid(uint512_t) == typeid(a6), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a6.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a6.m_arr[63] == 2, ""); - - auto a7 = 8 % uint512_t(0x5); - assert(typeid(uint512_t) == typeid(a7), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a7.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a7.m_arr[63] == 3, ""); - - auto a8 = uint512_t(0x8) % 5; - assert(typeid(uint512_t) == typeid(a8), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a8.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a8.m_arr[63] == 3, ""); - - auto a9 = 8 + uint512_t(0x5); - assert(typeid(uint512_t) == typeid(a9), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a9.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a9.m_arr[63] == 13, ""); - - auto a10 = uint512_t(0x8) + 5; - assert(typeid(uint512_t) == typeid(a10), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a10.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a10.m_arr[63] == 13, ""); - - auto a11 = 8 - uint512_t(0x5); - assert(typeid(uint512_t) == typeid(a11), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a11.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a11.m_arr[63] == 3, ""); - - auto a12 = uint512_t(0x8) - 5; - assert(typeid(uint512_t) == typeid(a12), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a12.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a12.m_arr[63] == 3, ""); - - assert(uint512_t(15) < 20U, ""); - assert(uint512_t(20) > 15U, ""); - assert(uint512_t(15) <= 20U, ""); - assert(uint512_t(20) >= 15U, ""); - assert(uint512_t(20) <= 20U, ""); - assert(uint512_t(20) >= 20U, ""); - assert(uint512_t(20) == 20U, ""); - - assert(15U < uint512_t(20), ""); - assert(20U > uint512_t(15), ""); - assert(15U <= uint512_t(20), ""); - assert(20U >= uint512_t(15), ""); - assert(20U <= uint512_t(20), ""); - assert(20U >= uint512_t(20), ""); - assert(20U == uint512_t(20), ""); - - assert(uint512_t(15) < uint128_t(20), ""); - assert(uint512_t(20) > uint128_t(15), ""); - assert(uint512_t(15) <= uint128_t(20), ""); - assert(uint512_t(20) >= uint128_t(15), ""); - assert(uint512_t(20) <= uint128_t(20), ""); - assert(uint512_t(20) >= uint128_t(20), ""); - assert(uint512_t(20) == uint128_t(20), ""); - - assert(uint128_t(15) < uint512_t(20), ""); - assert(uint128_t(20) > uint512_t(15), ""); - assert(uint128_t(15) <= uint512_t(20), ""); - assert(uint128_t(20) >= uint512_t(15), ""); - assert(uint128_t(20) <= uint512_t(20), ""); - assert(uint128_t(20) >= uint512_t(20), ""); - assert(uint128_t(20) == uint512_t(20), ""); - - auto a13 = 9 & uint512_t(5); - assert(typeid(uint512_t) == typeid(a13), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a13.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a13.m_arr[63] == 1, ""); - - auto a14 = uint512_t(9) & 5; - assert(typeid(uint512_t) == typeid(a14), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a14.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a14.m_arr[63] == 1, ""); - - auto a15 = 9 | uint512_t(5); - assert(typeid(uint512_t) == typeid(a15), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a15.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a15.m_arr[63] == 13, ""); + template + static void _testComparationPositive() { + assert(Type1(1500) < Type2(2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) > Type2(1500), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(1500) <= Type2(2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) <= Type2(2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) >= Type2(1500), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) >= Type2(2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) == Type2(2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(2000) != Type2(2001), _typeInfo(0) + " vs " + _typeInfo(0)); + } - auto a16 = uint512_t(9) | 5; - assert(typeid(uint512_t) == typeid(a16), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a16.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a16.m_arr[63] == 13, ""); + template + static void _testComparationNegative() { + assert(Type1(-1500) > Type2(-2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) < Type2(-1500), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) <= Type2(-2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) <= Type2(-1500), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) >= Type2(-2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-1500) >= Type2(-2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) == Type2(-2000), _typeInfo(0) + " vs " + _typeInfo(0)); + assert(Type1(-2000) != Type2(-2001), _typeInfo(0) + " vs " + _typeInfo(0)); + } - auto a17 = 4 ^ uint512_t(5); - assert(typeid(uint512_t) == typeid(a17), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a17.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a17.m_arr[63] == 1, ""); + static void testNativeOperators() { +#define test_unary_operator(Operator, num, ExpType) \ + { \ + _testUnaryOperator([](auto v){ return Operator v;}, num, __LINE__); \ + } - auto a18 = uint512_t(4) ^ 5; - assert(typeid(uint512_t) == typeid(a18), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a18.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a18.m_arr[63] == 1, ""); +#define test_binary_operators(num1, Operator, num2, ExpType) \ + { \ + _testBinaryOperator([](auto l, auto r){ return l Operator r;}, num1, num2, __LINE__, "operator" #Operator); \ + } - auto a19 = uint512_t(8) << 1; - assert(typeid(uint512_t) == typeid(a19), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a19.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a19.m_arr[63] == 16, ""); +#define test_case(num1, num2, ExpType) \ + { \ + test_binary_operators(num1, *, num2, ExpType); \ + test_binary_operators(num1, /, num2, ExpType); \ + test_binary_operators(num1, %, num2, ExpType); \ + test_binary_operators(num1, +, num2, ExpType); \ + test_binary_operators(num1, -, num2, ExpType); \ + test_binary_operators(num1, &, num2, ExpType); \ + test_binary_operators(num1, |, num2, ExpType); \ + test_binary_operators(num1, ^, num2, ExpType); \ + } - auto a20 = uint512_t(8) >> 1; - assert(typeid(uint512_t) == typeid(a20), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a20.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a20.m_arr[63] == 4, ""); + test_unary_operator(~, uint512_t(0xff), uint512_t); + test_unary_operator(-, uint512_t(0xff), uint512_t); + test_unary_operator(+, uint512_t(0xff), uint512_t); + + test_case(8, uint512_t(5), uint512_t); + test_case(-8, uint512_t(5), uint512_t); + test_case(uint512_t(5), 5, uint512_t); + test_case(uint512_t(5), -5, uint512_t); + + test_case(8, int128_t(5), int128_t); + test_case(8, int128_t(-5), int128_t); + test_case(-8, int128_t(5), int128_t); + test_case(-8, int128_t(-5), int128_t); + test_case(int128_t(8), 5, int128_t); + test_case(int128_t(-8), 5, int128_t); + test_case(int128_t(8), -5, int128_t); + test_case(int128_t(-8), -5, int128_t); + + test_case(uint512_t(8), uint128_t(5), uint512_t); + test_case(uint128_t(8), uint512_t(5), uint512_t); + + test_case(uint128_t(8), int512_t(-5), int512_t); + test_case(uint128_t(8), int512_t(5), int512_t); + test_case(uint512_t(8), int128_t(-5), uint512_t); + test_case(uint512_t(8), int128_t(5), uint512_t); + + test_case(int512_t(-8), uint128_t(5), int512_t); + test_case(int512_t(8), uint128_t(5), int512_t); + test_case(int128_t(-8), uint512_t(5), uint512_t); + test_case(int128_t(8), uint512_t(5), uint512_t); + + test_case(int512_t(8), int128_t(5), int512_t); + test_case(int512_t(-8), int128_t(5), int512_t); + test_case(int512_t(8), int128_t(-5), int512_t); + test_case(int512_t(-8), int128_t(-5), int512_t); + test_case(int128_t(8), int512_t(5), int512_t); + test_case(int128_t(-8), int512_t(5), int512_t); + test_case(int128_t(8), int512_t(-5), int512_t); + test_case(int128_t(-8), int512_t(-5), int512_t); + + test_case(uint512_t(8), uint512_t(5), uint512_t); + test_case(uint512_t(8), int512_t(5), uint512_t); + test_case(uint512_t(8), int512_t(-5), uint512_t); + test_case(int512_t(8), uint512_t(5), uint512_t); + test_case(int512_t(-8), uint512_t(5), uint512_t); + test_case(int512_t(8), int512_t(5), int512_t); + test_case(int512_t(8), int512_t(-5), int512_t); + test_case(int512_t(-8), int512_t(5), int512_t); + test_case(int512_t(-8), int512_t(-5), int512_t); + + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + _testComparationPositive(); + + _testComparationNegative(); + _testComparationNegative(); + _testComparationNegative(); + _testComparationNegative(); + _testComparationNegative(); + + test_binary_operators(uint512_t(8), <<, 1, uint512_t); + test_binary_operators(uint512_t(8), >>, 1, uint512_t); assert(!uint256_t(0), ""); assert(uint256_t(1), ""); - auto a21 = +uint512_t(0x1); - assert(typeid(uint512_t) == typeid(a21), ""); - for (int idx = 0; idx < 63; ++idx) { - assert(a21.m_arr[idx] == 0, std::to_string(idx)); - } - assert(a21.m_arr[63] == 1, ""); - assert(1024_int128 * 2.0 == 2048, ""); assert(2.0 * 1024_int128 == 2048, ""); @@ -1591,6 +1620,10 @@ struct _test { uint256_t c2 = 100000000000000000000_uint256; uint256_t c3 = c1 * c2; assert(c3 == 10000000000000000000000000000000000000000_uint256, ""); + +#undef test_case +#undef test_binary_operators +#undef test_unary_operator } static void testNativeOperatorsAssign() {