#include "cast.h"
#include "ylimits.h"
#include <library/cpp/testing/unittest/registar.h>
#include <util/system/valgrind.h>
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 <class T>
static inline bool ValidSignInfo(bool limitIsSigned, const T&) {
return limitIsSigned && IsNegative(T(-1)) || !limitIsSigned && !IsNegative(T(-1));
}
template <class T>
static inline bool TestIntegralLimits(const T&, bool unknownSign = true, bool isSigned = true) {
using lim = std::numeric_limits<T>;
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 <class T>
static inline bool TestSignedIntegralLimits(const T& val) {
return TestIntegralLimits(val, false, true);
}
template <class T>
static inline bool TestUnsignedIntegralLimits(const T& val) {
return TestIntegralLimits(val, false, false);
}
template <class T>
static inline bool TestFloatLimits(const T&) {
using lim = std::numeric_limits<T>;
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 <class T>
static inline bool TestNan(const T&) {
using lim = std::numeric_limits<T>;
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<i8>(), 127.0);
UNIT_ASSERT_VALUES_EQUAL(MaxFloor<i8>(), 127.0);
UNIT_ASSERT_VALUES_EQUAL(MaxCeil<ui8>(), 255.0);
UNIT_ASSERT_VALUES_EQUAL(MaxFloor<ui8>(), 255.0);
double d = 1ull << 63;
UNIT_ASSERT_VALUES_EQUAL(MaxCeil<i64>(), d);
UNIT_ASSERT_VALUES_EQUAL(MaxFloor<i64>(), nextafter(d, 0));
d *= 2;
UNIT_ASSERT_VALUES_EQUAL(MaxCeil<ui64>(), d);
UNIT_ASSERT_VALUES_EQUAL(MaxFloor<ui64>(), nextafter(d, 0));
}