#include "cast.h" #include "ylimits.h" #include #include class TLimitTest: public TTestBase { UNIT_TEST_SUITE(TLimitTest); UNIT_TEST(TestLimits); UNIT_TEST(TestNan); UNIT_TEST(TestMaxDouble); UNIT_TEST_SUITE_END(); protected: void TestLimits(); void TestNan(); void TestMaxDouble(); }; UNIT_TEST_SUITE_REGISTRATION(TLimitTest); #define CHECK_COND(X) UNIT_ASSERT(X) static inline bool ValidSignInfo(bool, bool) { return true; } template static inline bool ValidSignInfo(bool limitIsSigned, const T&) { return limitIsSigned && IsNegative(T(-1)) || !limitIsSigned && !IsNegative(T(-1)); } template static inline bool TestIntegralLimits(const T&, bool unknownSign = true, bool isSigned = true) { using lim = std::numeric_limits; CHECK_COND(lim::is_specialized); CHECK_COND(lim::is_integer); CHECK_COND(lim::min() < lim::max()); CHECK_COND((unknownSign && ((lim::is_signed && (lim::min() != 0)) || (!lim::is_signed && (lim::min() == 0)))) || (!unknownSign && ((lim::is_signed && isSigned) || (!lim::is_signed && !isSigned)))); T min = Min(); UNIT_ASSERT_EQUAL(lim::min(), min); T max = Max(); UNIT_ASSERT_EQUAL(lim::max(), max); if (unknownSign) { CHECK_COND(ValidSignInfo(lim::is_signed, T())); } return true; } template static inline bool TestSignedIntegralLimits(const T& val) { return TestIntegralLimits(val, false, true); } template static inline bool TestUnsignedIntegralLimits(const T& val) { return TestIntegralLimits(val, false, false); } template static inline bool TestFloatLimits(const T&) { using lim = std::numeric_limits; CHECK_COND(lim::is_specialized); CHECK_COND(!lim::is_modulo); CHECK_COND(!lim::is_integer); CHECK_COND(lim::is_signed); CHECK_COND(lim::max() > 1000); CHECK_COND(lim::min() > 0); CHECK_COND(lim::min() < 0.001); CHECK_COND(lim::epsilon() > 0); if (lim::is_iec559) { CHECK_COND(lim::has_infinity); CHECK_COND(lim::has_quiet_NaN); CHECK_COND(lim::has_signaling_NaN); } if (lim::has_infinity) { const T infinity = lim::infinity(); CHECK_COND(infinity > lim::max()); CHECK_COND(-infinity < -lim::max()); } return true; } template static inline bool TestNan(const T&) { using lim = std::numeric_limits; if (lim::has_quiet_NaN) { const T qnan = lim::quiet_NaN(); CHECK_COND(!(qnan == 42)); CHECK_COND(!(qnan == qnan)); CHECK_COND(qnan != 42); CHECK_COND(qnan != qnan); } return true; } void TLimitTest::TestLimits() { UNIT_ASSERT(TestIntegralLimits(bool())); UNIT_ASSERT(TestIntegralLimits(char())); using signed_char = signed char; UNIT_ASSERT(TestSignedIntegralLimits(signed_char())); using unsigned_char = unsigned char; UNIT_ASSERT(TestUnsignedIntegralLimits(unsigned_char())); UNIT_ASSERT(TestSignedIntegralLimits(short())); using unsigned_short = unsigned short; UNIT_ASSERT(TestUnsignedIntegralLimits(unsigned_short())); UNIT_ASSERT(TestSignedIntegralLimits(int())); using unsigned_int = unsigned int; UNIT_ASSERT(TestUnsignedIntegralLimits(unsigned_int())); UNIT_ASSERT(TestSignedIntegralLimits(long())); using unsigned_long = unsigned long; UNIT_ASSERT(TestUnsignedIntegralLimits(unsigned_long())); using long_long = long long; UNIT_ASSERT(TestSignedIntegralLimits(long_long())); using unsigned_long_long = unsigned long long; UNIT_ASSERT(TestUnsignedIntegralLimits(unsigned_long_long())); UNIT_ASSERT(TestFloatLimits(float())); UNIT_ASSERT(TestFloatLimits(double())); using long_double = long double; UNIT_ASSERT(RUNNING_ON_VALGRIND || TestFloatLimits(long_double())); } void TLimitTest::TestNan() { UNIT_ASSERT(::TestNan(float())); UNIT_ASSERT(::TestNan(double())); using long_double = long double; UNIT_ASSERT(::TestNan(long_double())); } void TLimitTest::TestMaxDouble() { UNIT_ASSERT_VALUES_EQUAL(MaxCeil(), 127.0); UNIT_ASSERT_VALUES_EQUAL(MaxFloor(), 127.0); UNIT_ASSERT_VALUES_EQUAL(MaxCeil(), 255.0); UNIT_ASSERT_VALUES_EQUAL(MaxFloor(), 255.0); double d = 1ull << 63; UNIT_ASSERT_VALUES_EQUAL(MaxCeil(), d); UNIT_ASSERT_VALUES_EQUAL(MaxFloor(), nextafter(d, 0)); d *= 2; UNIT_ASSERT_VALUES_EQUAL(MaxCeil(), d); UNIT_ASSERT_VALUES_EQUAL(MaxFloor(), nextafter(d, 0)); }