// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "util/saturate_cast.h" #include "gtest/gtest.h" namespace openscreen { namespace { TEST(SaturateCastTest, LargerToSmallerSignedInteger) { struct ValuePair { int64_t from; int32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, {-42, -42}, {std::numeric_limits::min(), std::numeric_limits::min()}, {std::numeric_limits::min() / 2 - 42, std::numeric_limits::min()}, {std::numeric_limits::min(), std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, LargerToSmallerUnsignedInteger) { struct ValuePair { uint64_t from; uint32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, LargerSignedToSmallerUnsignedInteger) { struct ValuePair { int64_t from; uint32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, {-42, 0}, {std::numeric_limits::min() / 2 - 42, 0}, {std::numeric_limits::min(), 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, LargerUnsignedToSmallerSignedInteger) { struct ValuePair { uint64_t from; int32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, SignedToUnsigned32BitInteger) { struct ValuePair { int32_t from; uint32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, {-42, 0}, {std::numeric_limits::min(), 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, UnsignedToSigned32BitInteger) { struct ValuePair { uint32_t from; int32_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, SignedToUnsigned64BitInteger) { struct ValuePair { int64_t from; uint64_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, {-42, 0}, {std::numeric_limits::min(), 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, UnsignedToSigned64BitInteger) { struct ValuePair { uint64_t from; int64_t to; }; constexpr ValuePair kValuePairs[] = { {std::numeric_limits::max(), std::numeric_limits::max()}, {std::numeric_limits::max() / 2 + 42, std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}, {42, 42}, {0, 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, Float32ToSigned32) { struct ValuePair { float from; int32_t to; }; constexpr float kFloatMax = std::numeric_limits::max(); // Note: kIntMax is one larger because float cannot represent the exact value. constexpr float kIntMax = static_cast(std::numeric_limits::max()); constexpr float kIntMin = std::numeric_limits::min(); const ValuePair kValuePairs[] = { {kFloatMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kFloatMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.f), 2147483520}, {42, 42}, {0, 0}, {-42, -42}, {std::nextafter(kIntMin, 0.f), -2147483520}, {kIntMin, std::numeric_limits::min()}, {std::nextafter(kIntMin, -kFloatMax), std::numeric_limits::min()}, {-kFloatMax, std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, Float32ToSigned64) { struct ValuePair { float from; int64_t to; }; constexpr float kFloatMax = std::numeric_limits::max(); // Note: kIntMax is one larger because float cannot represent the exact value. constexpr float kIntMax = static_cast(std::numeric_limits::max()); constexpr float kIntMin = std::numeric_limits::min(); const ValuePair kValuePairs[] = { {kFloatMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kFloatMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.f), INT64_C(9223371487098961920)}, {42, 42}, {0, 0}, {-42, -42}, {std::nextafter(kIntMin, 0.f), INT64_C(-9223371487098961920)}, {kIntMin, std::numeric_limits::min()}, {std::nextafter(kIntMin, -kFloatMax), std::numeric_limits::min()}, {-kFloatMax, std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, Float64ToSigned32) { struct ValuePair { double from; int32_t to; }; constexpr double kDoubleMax = std::numeric_limits::max(); constexpr double kIntMax = std::numeric_limits::max(); constexpr double kIntMin = std::numeric_limits::min(); const ValuePair kValuePairs[] = { {kDoubleMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kDoubleMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.0), std::numeric_limits::max() - 1}, {42, 42}, {0, 0}, {-42, -42}, {std::nextafter(kIntMin, 0.0), std::numeric_limits::min() + 1}, {kIntMin, std::numeric_limits::min()}, {std::nextafter(kIntMin, -kDoubleMax), std::numeric_limits::min()}, {-kDoubleMax, std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, Float64ToSigned64) { struct ValuePair { double from; int64_t to; }; constexpr double kDoubleMax = std::numeric_limits::max(); // Note: kIntMax is one larger because double cannot represent the exact // value. constexpr double kIntMax = static_cast(std::numeric_limits::max()); constexpr double kIntMin = std::numeric_limits::min(); const ValuePair kValuePairs[] = { {kDoubleMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kDoubleMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.0), INT64_C(9223372036854774784)}, {42, 42}, {0, 0}, {-42, -42}, {std::nextafter(kIntMin, 0.0), INT64_C(-9223372036854774784)}, {kIntMin, std::numeric_limits::min()}, {std::nextafter(kIntMin, -kDoubleMax), std::numeric_limits::min()}, {-kDoubleMax, std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, Float32ToUnsigned64) { struct ValuePair { float from; uint64_t to; }; constexpr float kFloatMax = std::numeric_limits::max(); // Note: kIntMax is one larger because float cannot represent the exact value. constexpr float kIntMax = static_cast(std::numeric_limits::max()); const ValuePair kValuePairs[] = { {kFloatMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kFloatMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.f), UINT64_C(18446742974197923840)}, {42, 42}, {0, 0}, {-42, 0}, {-kFloatMax, 0}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, saturate_cast(value_pair.from)); } } TEST(SaturateCastTest, RoundingFloat32ToSigned64) { struct ValuePair { float from; int64_t to; }; constexpr float kFloatMax = std::numeric_limits::max(); // Note: kIntMax is one larger because float cannot represent the exact value. constexpr float kIntMax = static_cast(std::numeric_limits::max()); constexpr float kIntMin = std::numeric_limits::min(); const ValuePair kValuePairs[] = { {kFloatMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, kFloatMax), std::numeric_limits::max()}, {kIntMax, std::numeric_limits::max()}, {std::nextafter(kIntMax, 0.f), INT64_C(9223371487098961920)}, {41.9, 42}, {42, 42}, {42.6, 43}, {42.5, 43}, {42.4, 42}, {0.5, 1}, {0.1, 0}, {0, 0}, {-0.1, 0}, {-0.5, -1}, {-41.9, -42}, {-42, -42}, {-42.4, -42}, {-42.5, -43}, {-42.6, -43}, {std::nextafter(kIntMin, 0.f), INT64_C(-9223371487098961920)}, {kIntMin, std::numeric_limits::min()}, {std::nextafter(kIntMin, -kFloatMax), std::numeric_limits::min()}, {-kFloatMax, std::numeric_limits::min()}, }; for (const ValuePair& value_pair : kValuePairs) { EXPECT_EQ(value_pair.to, rounded_saturate_cast(value_pair.from)); } } } // namespace } // namespace openscreen