You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

363 lines
12 KiB

// 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<int64_t>::max(),
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<int64_t>::max() / 2 + 42,
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max()},
{42, 42},
{0, 0},
{-42, -42},
{std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::min()},
{std::numeric_limits<int64_t>::min() / 2 - 42,
std::numeric_limits<int32_t>::min()},
{std::numeric_limits<int64_t>::min(),
std::numeric_limits<int32_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, LargerToSmallerUnsignedInteger) {
struct ValuePair {
uint64_t from;
uint32_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint32_t>::max()},
{std::numeric_limits<uint64_t>::max() / 2 + 42,
std::numeric_limits<uint32_t>::max()},
{std::numeric_limits<uint32_t>::max(),
std::numeric_limits<uint32_t>::max()},
{42, 42},
{0, 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<uint32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, LargerSignedToSmallerUnsignedInteger) {
struct ValuePair {
int64_t from;
uint32_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<int64_t>::max(),
std::numeric_limits<uint32_t>::max()},
{std::numeric_limits<int64_t>::max() / 2 + 42,
std::numeric_limits<uint32_t>::max()},
{std::numeric_limits<uint32_t>::max(),
std::numeric_limits<uint32_t>::max()},
{42, 42},
{0, 0},
{-42, 0},
{std::numeric_limits<int64_t>::min() / 2 - 42, 0},
{std::numeric_limits<int64_t>::min(), 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<uint32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, LargerUnsignedToSmallerSignedInteger) {
struct ValuePair {
uint64_t from;
int32_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<uint64_t>::max(),
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<uint64_t>::max() / 2 + 42,
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max()},
{42, 42},
{0, 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, SignedToUnsigned32BitInteger) {
struct ValuePair {
int32_t from;
uint32_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max()},
{42, 42},
{0, 0},
{-42, 0},
{std::numeric_limits<int32_t>::min(), 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<uint32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, UnsignedToSigned32BitInteger) {
struct ValuePair {
uint32_t from;
int32_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<uint32_t>::max(),
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<uint32_t>::max() / 2 + 42,
std::numeric_limits<int32_t>::max()},
{std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max()},
{42, 42},
{0, 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, SignedToUnsigned64BitInteger) {
struct ValuePair {
int64_t from;
uint64_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<int64_t>::max(),
std::numeric_limits<int64_t>::max()},
{42, 42},
{0, 0},
{-42, 0},
{std::numeric_limits<int64_t>::min(), 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<uint64_t>(value_pair.from));
}
}
TEST(SaturateCastTest, UnsignedToSigned64BitInteger) {
struct ValuePair {
uint64_t from;
int64_t to;
};
constexpr ValuePair kValuePairs[] = {
{std::numeric_limits<uint64_t>::max(),
std::numeric_limits<int64_t>::max()},
{std::numeric_limits<uint64_t>::max() / 2 + 42,
std::numeric_limits<int64_t>::max()},
{std::numeric_limits<int64_t>::max(),
std::numeric_limits<int64_t>::max()},
{42, 42},
{0, 0},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int64_t>(value_pair.from));
}
}
TEST(SaturateCastTest, Float32ToSigned32) {
struct ValuePair {
float from;
int32_t to;
};
constexpr float kFloatMax = std::numeric_limits<float>::max();
// Note: kIntMax is one larger because float cannot represent the exact value.
constexpr float kIntMax =
static_cast<float>(std::numeric_limits<int32_t>::max());
constexpr float kIntMin = std::numeric_limits<int32_t>::min();
const ValuePair kValuePairs[] = {
{kFloatMax, std::numeric_limits<int32_t>::max()},
{std::nextafter(kIntMax, kFloatMax), std::numeric_limits<int32_t>::max()},
{kIntMax, std::numeric_limits<int32_t>::max()},
{std::nextafter(kIntMax, 0.f), 2147483520},
{42, 42},
{0, 0},
{-42, -42},
{std::nextafter(kIntMin, 0.f), -2147483520},
{kIntMin, std::numeric_limits<int32_t>::min()},
{std::nextafter(kIntMin, -kFloatMax),
std::numeric_limits<int32_t>::min()},
{-kFloatMax, std::numeric_limits<int32_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, Float32ToSigned64) {
struct ValuePair {
float from;
int64_t to;
};
constexpr float kFloatMax = std::numeric_limits<float>::max();
// Note: kIntMax is one larger because float cannot represent the exact value.
constexpr float kIntMax =
static_cast<float>(std::numeric_limits<int64_t>::max());
constexpr float kIntMin = std::numeric_limits<int64_t>::min();
const ValuePair kValuePairs[] = {
{kFloatMax, std::numeric_limits<int64_t>::max()},
{std::nextafter(kIntMax, kFloatMax), std::numeric_limits<int64_t>::max()},
{kIntMax, std::numeric_limits<int64_t>::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<int64_t>::min()},
{std::nextafter(kIntMin, -kFloatMax),
std::numeric_limits<int64_t>::min()},
{-kFloatMax, std::numeric_limits<int64_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int64_t>(value_pair.from));
}
}
TEST(SaturateCastTest, Float64ToSigned32) {
struct ValuePair {
double from;
int32_t to;
};
constexpr double kDoubleMax = std::numeric_limits<double>::max();
constexpr double kIntMax = std::numeric_limits<int32_t>::max();
constexpr double kIntMin = std::numeric_limits<int32_t>::min();
const ValuePair kValuePairs[] = {
{kDoubleMax, std::numeric_limits<int32_t>::max()},
{std::nextafter(kIntMax, kDoubleMax),
std::numeric_limits<int32_t>::max()},
{kIntMax, std::numeric_limits<int32_t>::max()},
{std::nextafter(kIntMax, 0.0), std::numeric_limits<int32_t>::max() - 1},
{42, 42},
{0, 0},
{-42, -42},
{std::nextafter(kIntMin, 0.0), std::numeric_limits<int32_t>::min() + 1},
{kIntMin, std::numeric_limits<int32_t>::min()},
{std::nextafter(kIntMin, -kDoubleMax),
std::numeric_limits<int32_t>::min()},
{-kDoubleMax, std::numeric_limits<int32_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int32_t>(value_pair.from));
}
}
TEST(SaturateCastTest, Float64ToSigned64) {
struct ValuePair {
double from;
int64_t to;
};
constexpr double kDoubleMax = std::numeric_limits<double>::max();
// Note: kIntMax is one larger because double cannot represent the exact
// value.
constexpr double kIntMax =
static_cast<double>(std::numeric_limits<int64_t>::max());
constexpr double kIntMin = std::numeric_limits<int64_t>::min();
const ValuePair kValuePairs[] = {
{kDoubleMax, std::numeric_limits<int64_t>::max()},
{std::nextafter(kIntMax, kDoubleMax),
std::numeric_limits<int64_t>::max()},
{kIntMax, std::numeric_limits<int64_t>::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<int64_t>::min()},
{std::nextafter(kIntMin, -kDoubleMax),
std::numeric_limits<int64_t>::min()},
{-kDoubleMax, std::numeric_limits<int64_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, saturate_cast<int64_t>(value_pair.from));
}
}
TEST(SaturateCastTest, Float32ToUnsigned64) {
struct ValuePair {
float from;
uint64_t to;
};
constexpr float kFloatMax = std::numeric_limits<float>::max();
// Note: kIntMax is one larger because float cannot represent the exact value.
constexpr float kIntMax =
static_cast<float>(std::numeric_limits<uint64_t>::max());
const ValuePair kValuePairs[] = {
{kFloatMax, std::numeric_limits<uint64_t>::max()},
{std::nextafter(kIntMax, kFloatMax),
std::numeric_limits<uint64_t>::max()},
{kIntMax, std::numeric_limits<uint64_t>::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<uint64_t>(value_pair.from));
}
}
TEST(SaturateCastTest, RoundingFloat32ToSigned64) {
struct ValuePair {
float from;
int64_t to;
};
constexpr float kFloatMax = std::numeric_limits<float>::max();
// Note: kIntMax is one larger because float cannot represent the exact value.
constexpr float kIntMax =
static_cast<float>(std::numeric_limits<int64_t>::max());
constexpr float kIntMin = std::numeric_limits<int64_t>::min();
const ValuePair kValuePairs[] = {
{kFloatMax, std::numeric_limits<int64_t>::max()},
{std::nextafter(kIntMax, kFloatMax), std::numeric_limits<int64_t>::max()},
{kIntMax, std::numeric_limits<int64_t>::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<int64_t>::min()},
{std::nextafter(kIntMin, -kFloatMax),
std::numeric_limits<int64_t>::min()},
{-kFloatMax, std::numeric_limits<int64_t>::min()},
};
for (const ValuePair& value_pair : kValuePairs) {
EXPECT_EQ(value_pair.to, rounded_saturate_cast<int64_t>(value_pair.from));
}
}
} // namespace
} // namespace openscreen