#include #include #include #include #include #include #define OP ::yycc::num::safe_op namespace yycctest::num::safe_op { template constexpr T MAX = std::numeric_limits::max(); template constexpr T MIN = std::numeric_limits::min(); #pragma region Wrapping operations TEST(NumSafeOp, WrappingAdd) { // Unsigned EXPECT_EQ(OP::wrapping_add(200, 55), UINT32_C(255)); EXPECT_EQ(OP::wrapping_add(200, MAX), UINT32_C(199)); // Signed EXPECT_EQ(OP::wrapping_add(100, 27), INT32_C(127)); EXPECT_EQ(OP::wrapping_add(MAX, 2), MIN + 1); } TEST(NumSafeOp, WrappingSub) { // Unsigned EXPECT_EQ(OP::wrapping_sub(100, 100), 0); EXPECT_EQ(OP::wrapping_sub(100, MAX), UINT32_C(101)); // Signed EXPECT_EQ(OP::wrapping_sub(0, 127), INT32_C(-127)); EXPECT_EQ(OP::wrapping_sub(-2, MAX), MAX); } TEST(NumSafeOp, WrappingMul) { // Unsigned EXPECT_EQ(OP::wrapping_mul(10, 12), UINT8_C(120)); EXPECT_EQ(OP::wrapping_mul(25, 12), UINT8_C(44)); // Signed EXPECT_EQ(OP::wrapping_mul(10, 12), INT32_C(120)); EXPECT_EQ(OP::wrapping_mul(11, 12), INT32_C(-124)); } TEST(NumSafeOp, WrappingDiv) { // Unsigned EXPECT_EQ(OP::wrapping_div(100, 10), UINT32_C(10)); // Signed EXPECT_EQ(OP::wrapping_div(100, 10), INT32_C(10)); EXPECT_EQ(OP::wrapping_div(-128, -1), INT32_C(-128)); } #pragma endregion #pragma region Checked operations TEST(NumSafeOp, CheckedAdd) { // Unsigned { auto rv = OP::checked_add(MAX - 2, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), MAX - 1); } { auto rv = OP::checked_add(MAX - 2, 3); EXPECT_FALSE(rv.has_value()); } // Signed { auto rv = OP::checked_add(MAX - 2, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), MAX - 1); } { auto rv = OP::checked_add(MAX - 2, 3); EXPECT_FALSE(rv.has_value()); } } TEST(NumSafeOp, CheckedSub) { // Unsigned { auto rv = OP::checked_sub(1, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), 0); } { auto rv = OP::checked_sub(0, 1); EXPECT_FALSE(rv.has_value()); } // Signed { auto rv = OP::checked_sub(MIN + 2, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), MIN + 1); } { auto rv = OP::checked_sub(MIN + 2, 3); EXPECT_FALSE(rv.has_value()); } } TEST(NumSafeOp, CheckedMul) { // Unsigned { auto rv = OP::checked_mul(5, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), 5); } { auto rv = OP::checked_mul(MAX, 2); EXPECT_FALSE(rv.has_value()); } // Signed { auto rv = OP::checked_mul(MAX, 1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), MAX); } { auto rv = OP::checked_mul(MAX, 2); EXPECT_FALSE(rv.has_value()); } } TEST(NumSafeOp, CheckedDiv) { // Unsigned { auto rv = OP::checked_div(128, 2); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), 64); } { auto rv = OP::checked_div(1, 0); EXPECT_FALSE(rv.has_value()); } // Signed { auto rv = OP::checked_div(MIN + 1, -1); ASSERT_TRUE(rv.has_value()); EXPECT_EQ(rv.value(), INT32_C(2147483647)); } { auto rv = OP::checked_div(MIN, -1); EXPECT_FALSE(rv.has_value()); } { auto rv = OP::checked_div(1, 0); EXPECT_FALSE(rv.has_value()); } } #pragma endregion #pragma region Overflowing operations TEST(NumSafeOp, OverflowingAdd) { // Unsigned { auto rv = OP::overflowing_add(5, 2); EXPECT_EQ(rv.first, 7); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_add(MAX, 1); EXPECT_EQ(rv.first, 0); EXPECT_EQ(rv.second, true); } // Signed { auto rv = OP::overflowing_add(5, 2); EXPECT_EQ(rv.first, 7); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_add(MAX, 1); EXPECT_EQ(rv.first, MIN); EXPECT_EQ(rv.second, true); } } TEST(NumSafeOp, OverflowingSub) { // Unsigned { auto rv = OP::overflowing_sub(5, 2); EXPECT_EQ(rv.first, 3); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_sub(0, 1); EXPECT_EQ(rv.first, MAX); EXPECT_EQ(rv.second, true); } // Signed { auto rv = OP::overflowing_sub(5, 2); EXPECT_EQ(rv.first, 3); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_sub(MIN, 1); EXPECT_EQ(rv.first, MAX); EXPECT_EQ(rv.second, true); } } TEST(NumSafeOp, OverflowingMul) { // Unsigned { auto rv = OP::overflowing_mul(5, 2); EXPECT_EQ(rv.first, 10); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_mul(UINT32_C(1000000000), 10); EXPECT_EQ(rv.first, UINT32_C(1410065408)); EXPECT_EQ(rv.second, true); } // Signed { auto rv = OP::overflowing_mul(5, 2); EXPECT_EQ(rv.first, 10); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_mul(INT32_C(1000000000), 10); EXPECT_EQ(rv.first, INT32_C(1410065408)); EXPECT_EQ(rv.second, true); } } TEST(NumSafeOp, OverflowingDiv) { // Unsigned { auto rv = OP::overflowing_div(5, 2); EXPECT_EQ(rv.first, 2); EXPECT_EQ(rv.second, false); } // Signed { auto rv = OP::overflowing_div(5, 2); EXPECT_EQ(rv.first, 2); EXPECT_EQ(rv.second, false); } { auto rv = OP::overflowing_div(MIN, -1); EXPECT_EQ(rv.first, MIN); EXPECT_EQ(rv.second, true); } } #pragma endregion #pragma region Saturating operations TEST(NumSafeOp, SaturatingAdd) { // Unsigned EXPECT_EQ(OP::saturating_add(100, 1), UINT32_C(101)); EXPECT_EQ(OP::saturating_add(MAX, 127), MAX); // Signed EXPECT_EQ(OP::saturating_add(100, 1), INT32_C(101)); EXPECT_EQ(OP::saturating_add(MAX, 100), MAX); EXPECT_EQ(OP::saturating_add(MIN, -1), MIN); } TEST(NumSafeOp, SaturatingSub) { // Unsigned EXPECT_EQ(OP::saturating_sub(100, 27), UINT32_C(73)); EXPECT_EQ(OP::saturating_sub(13, 127), 0); // Signed EXPECT_EQ(OP::saturating_sub(100, 127), -27); EXPECT_EQ(OP::saturating_sub(MIN, 100), MIN); EXPECT_EQ(OP::saturating_sub(MAX, -1), MAX); } TEST(NumSafeOp, SaturatingMul) { // Unsigned EXPECT_EQ(OP::saturating_mul(2, 10), UINT32_C(20)); EXPECT_EQ(OP::saturating_mul(MAX, 10), MAX); // Signed EXPECT_EQ(OP::saturating_mul(10, 12), 120); EXPECT_EQ(OP::saturating_mul(MAX, 10), MAX); EXPECT_EQ(OP::saturating_mul(MIN, 10), MIN); } TEST(NumSafeOp, SaturatingDiv) { // Unsigned EXPECT_EQ(OP::saturating_div(5, 2), UINT32_C(2)); // Signed EXPECT_EQ(OP::saturating_div(5, 2), 2); EXPECT_EQ(OP::saturating_div(MAX, -1), MIN + 1); EXPECT_EQ(OP::saturating_div(MIN, -1), MAX); } #pragma endregion } // namespace yycctest::num::safe_op