Chromium Code Reviews| Index: base/numerics/safe_numerics_unittest.cc |
| diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc |
| index 8ced4bdb7b244e0637dc18f8c2f296d84d49f671..9c767d24b518d18c08131106be1049b5d60f1595 100644 |
| --- a/base/numerics/safe_numerics_unittest.cc |
| +++ b/base/numerics/safe_numerics_unittest.cc |
| @@ -22,6 +22,9 @@ |
| using std::numeric_limits; |
| using base::CheckedNumeric; |
| +using base::IsValidForType; |
| +using base::ValueOrDieForType; |
| +using base::ValueOrDefaultForType; |
| using base::CheckNum; |
| using base::CheckAdd; |
| using base::CheckSub; |
| @@ -37,6 +40,7 @@ using base::SizeT; |
| using base::StrictNumeric; |
| using base::saturated_cast; |
| using base::strict_cast; |
| +using base::StrictNumeric; |
| using base::internal::MaxExponent; |
| using base::internal::RANGE_VALID; |
| using base::internal::RANGE_INVALID; |
| @@ -108,6 +112,20 @@ struct LogOnFailure { |
| << "Result test: Value " << GetNumericValueForTest(actual) << " as " \ |
| << dst << " on line " << line |
| +// Test the simple pointer arithmetic overrides. |
| +template <typename Dst> |
| +void TestStrictPointerMath() { |
| + Dst dummy_value = 0; |
| + Dst* dummy_ptr = &dummy_value; |
| + static const Dst kDummyOffset = 2; // Don't want to go too far. |
| + EXPECT_EQ(dummy_ptr + kDummyOffset, |
| + dummy_ptr + StrictNumeric<Dst>(kDummyOffset)); |
| + EXPECT_EQ(dummy_ptr - kDummyOffset, |
| + dummy_ptr - StrictNumeric<Dst>(kDummyOffset)); |
| + EXPECT_NE(dummy_ptr, dummy_ptr + StrictNumeric<Dst>(kDummyOffset)); |
| + EXPECT_NE(dummy_ptr, dummy_ptr - StrictNumeric<Dst>(kDummyOffset)); |
| +} |
|
Tom Sepez
2016/11/30 23:58:27
Can we have a test that adding numeric_limits<uinp
jschuh
2016/12/01 00:58:55
Unfortunately, no, because I don't have have a way
danakj
2016/12/01 01:00:25
Death tests are a possibility if I'm understanding
|
| + |
| // Signed integer arithmetic. |
| template <typename Dst> |
| static void TestSpecializedArithmetic( |
| @@ -170,6 +188,8 @@ static void TestSpecializedArithmetic( |
| TEST_EXPECTED_VALUE(0, |
| CheckedNumeric<Dst>(1) >> (sizeof(Dst) * CHAR_BIT - 1)); |
| TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one); |
| + |
| + TestStrictPointerMath<Dst>(); |
| } |
| // Unsigned integer arithmetic. |
| @@ -241,6 +261,8 @@ static void TestSpecializedArithmetic( |
| TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), |
| CheckedNumeric<Dst>(0) ^ static_cast<Dst>(-1)); |
| TEST_EXPECTED_VALUE(DstLimits::max(), ~CheckedNumeric<Dst>(0)); |
| + |
| + TestStrictPointerMath<Dst>(); |
| } |
| // Floating point arithmetic. |
| @@ -268,7 +290,6 @@ void TestSpecializedArithmetic( |
| TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) * 2); |
| TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2); |
| - EXPECT_EQ(static_cast<Dst>(1.0), CheckedNumeric<Dst>(1.0).ValueFloating()); |
| } |
| // Generic arithmetic tests. |
| @@ -411,6 +432,43 @@ struct TestNumericConversion {}; |
| << " on line " << line |
| template <typename Dst, typename Src> |
| +void TestStrictComparison() { |
| + typedef numeric_limits<Dst> DstLimits; |
| + typedef numeric_limits<Src> SrcLimits; |
| + static_assert(StrictNumeric<Src>(SrcLimits::min()) < DstLimits::max(), ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::min()) < SrcLimits::max(), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::min()) >= DstLimits::max()), |
| + ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::min()) >= SrcLimits::max()), |
| + ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::min()) <= DstLimits::max(), ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::min()) <= SrcLimits::max(), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::min()) > DstLimits::max()), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::min()) > SrcLimits::max()), ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) > DstLimits::min(), ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) > SrcLimits::min(), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= DstLimits::min()), |
| + ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= SrcLimits::min()), |
| + ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) >= DstLimits::min(), ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) >= SrcLimits::min(), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < DstLimits::min()), ""); |
| + static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < SrcLimits::min()), ""); |
| + static_assert(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(1), |
| + ""); |
| + static_assert(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(0), |
| + ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) != static_cast<Dst>(0), |
| + ""); |
| + static_assert(StrictNumeric<Src>(SrcLimits::max()) != DstLimits::min(), ""); |
| + static_assert( |
| + !(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(1)), ""); |
| + static_assert( |
| + !(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(0)), ""); |
| +} |
| + |
| +template <typename Dst, typename Src> |
| struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { |
| static void Test(const char *dst, const char *src, int line) { |
| typedef numeric_limits<Src> SrcLimits; |
| @@ -426,6 +484,8 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { |
| (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), |
| "Comparison must be sign preserving and value preserving"); |
| + TestStrictComparison<Dst, Src>(); |
| + |
| const CheckedNumeric<Dst> checked_dst = SrcLimits::max(); |
| TEST_EXPECTED_SUCCESS(checked_dst); |
| if (MaxExponent<Dst>::value > MaxExponent<Src>::value) { |
| @@ -466,6 +526,8 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { |
| (DstLimits::is_integer && SrcLimits::is_iec559), |
| "Destination must be narrower than source"); |
| + TestStrictComparison<Dst, Src>(); |
| + |
| const CheckedNumeric<Dst> checked_dst; |
| TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); |
| TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); |
| @@ -512,6 +574,8 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { |
| static_assert(SrcLimits::is_signed, "Source must be signed"); |
| static_assert(!DstLimits::is_signed, "Destination must be unsigned"); |
| + TestStrictComparison<Dst, Src>(); |
| + |
| const CheckedNumeric<Dst> checked_dst; |
| TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); |
| TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); |
| @@ -535,6 +599,8 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { |
| static_assert(SrcLimits::is_signed, "Source must be signed."); |
| static_assert(!DstLimits::is_signed, "Destination must be unsigned."); |
| + TestStrictComparison<Dst, Src>(); |
| + |
| const CheckedNumeric<Dst> checked_dst; |
| TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); |
| TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); |
| @@ -577,6 +643,8 @@ struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { |
| static_assert(!SrcLimits::is_signed, "Source must be unsigned."); |
| static_assert(DstLimits::is_signed, "Destination must be signed."); |
| + TestStrictComparison<Dst, Src>(); |
| + |
| const CheckedNumeric<Dst> checked_dst; |
| TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); |
| TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); |
| @@ -754,22 +822,21 @@ TEST(SafeNumerics, CastTests) { |
| auto int8_max = CheckNum(numeric_limits<int8_t>::max()); |
| auto double_max = CheckNum(numeric_limits<double>::max()); |
| static_assert( |
| - std::is_same<int16_t, decltype(int8_min.ValueOrDie<int16_t>())>::value, |
| + std::is_same<int16_t, |
| + decltype(int8_min.ValueOrDie<int16_t>())::type>::value, |
| "ValueOrDie returning incorrect type."); |
| static_assert( |
| std::is_same<int16_t, |
| - decltype(int8_min.ValueOrDefault<int16_t>(0))>::value, |
| + decltype(int8_min.ValueOrDefault<int16_t>(0))::type>::value, |
| "ValueOrDefault returning incorrect type."); |
| - static_assert( |
| - std::is_same<float, decltype(double_max.ValueFloating<float>())>::value, |
| - "ValueFloating returning incorrect type."); |
| - EXPECT_FALSE(int8_min.template IsValid<uint8_t>()); |
| - EXPECT_TRUE(int8_max.template IsValid<uint8_t>()); |
| + EXPECT_FALSE(IsValidForType<uint8_t>(int8_min)); |
| + EXPECT_TRUE(IsValidForType<uint8_t>(int8_max)); |
| EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::min()), |
| - int8_min.template ValueOrDie<int>()); |
| - EXPECT_TRUE(int8_max.template IsValid<uint32_t>()); |
| + ValueOrDieForType<int>(int8_min)); |
| + EXPECT_TRUE(IsValidForType<uint32_t>(int8_max)); |
| EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::max()), |
| - int8_max.template ValueOrDie<int>()); |
| + ValueOrDieForType<int>(int8_max)); |
| + EXPECT_EQ(0, ValueOrDefaultForType<int>(double_max, 0)); |
| uint8_t uint8_dest = 0; |
| int16_t int16_dest = 0; |
| double double_dest = 0; |
| @@ -896,19 +963,19 @@ TEST(SafeNumerics, CompoundNumericOperations) { |
| TEST(SafeNumerics, VariadicNumericOperations) { |
| auto a = CheckAdd(1, 2UL, CheckNum(3LL), 4).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(a)>(10), a); |
| + EXPECT_EQ(static_cast<decltype(a)::type>(10), a); |
| auto b = CheckSub(CheckNum(20.0), 2UL, 4).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(b)>(14.0), b); |
| + EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b); |
| auto c = CheckMul(20.0, CheckNum(1), 5, 3UL).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(c)>(300.0), c); |
| + EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c); |
| auto d = CheckDiv(20.0, 2.0, CheckNum(5LL), -4).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(d)>(-.5), d); |
| + EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d); |
| auto e = CheckMod(CheckNum(20), 3).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(e)>(2), e); |
| + EXPECT_EQ(static_cast<decltype(e)::type>(2), e); |
| auto f = CheckLsh(1, CheckNum(2)).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(f)>(4), f); |
| + EXPECT_EQ(static_cast<decltype(f)::type>(4), f); |
| auto g = CheckRsh(4, CheckNum(2)).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(g)>(1), g); |
| + EXPECT_EQ(static_cast<decltype(g)::type>(1), g); |
| auto h = CheckRsh(CheckAdd(1, 1, 1, 1), CheckSub(4, 2)).ValueOrDie(); |
| - EXPECT_EQ(static_cast<decltype(h)>(1), h); |
| + EXPECT_EQ(static_cast<decltype(h)::type>(1), h); |
| } |