/* * Copyright (c) 2023, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 3-Clause Clear License * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear * License was not distributed with this source code in the LICENSE file, you * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the * Alliance for Open Media Patent License 1.0 was not distributed with this * source code in the PATENTS file, you can obtain it at * www.aomedia.org/license/patent. */ #include "iamf/common/utils/numeric_utils.h" #include #include #include #include #include #include #include #include #include #include "absl/functional/any_invocable.h" #include "absl/status/status.h" #include "absl/status/status_matchers.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "iamf/cli/tests/cli_test_utils.h" #include "iamf/common/write_bit_buffer.h" #include "iamf/obu/types.h" namespace iamf_tools { namespace { using ::absl_testing::IsOk; using ::absl_testing::StatusIs; using ::testing::ElementsAreArray; using ::testing::HasSubstr; constexpr absl::string_view kOmitContext = ""; constexpr absl::string_view kCustomUserContext = "Custom User Context"; TEST(AddUint32CheckOverflow, SmallInput) { uint32_t result; EXPECT_THAT(AddUint32CheckOverflow(1, 1, result), IsOk()); EXPECT_EQ(result, 2); } TEST(AddUint32CheckOverflow, MaxOutput) { uint32_t result; EXPECT_THAT(AddUint32CheckOverflow( 1, std::numeric_limits::max() - 1, result), IsOk()); EXPECT_EQ(result, std::numeric_limits::max()); } TEST(AddUint32CheckOverflow, Overflow) { uint32_t result; EXPECT_EQ( AddUint32CheckOverflow(1, std::numeric_limits::max(), result) .code(), absl::StatusCode::kInvalidArgument); } struct FloatToQ78FormatTestCase { float test_val; int16_t expected_val; absl::StatusCode expected_status_code; }; using FloatToQ78Format = ::testing::TestWithParam; TEST_P(FloatToQ78Format, TestQ78Format) { const FloatToQ78FormatTestCase& test_case = GetParam(); int16_t q7_8_value; EXPECT_EQ(FloatToQ7_8(test_case.test_val, q7_8_value).code(), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(q7_8_value, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P(Positive, FloatToQ78Format, testing::ValuesIn({ {0, 0, absl::StatusCode::kOk}, {0.00390625, 1, absl::StatusCode::kOk}, {0.390625, 100, absl::StatusCode::kOk}, {0.99609375, 255, absl::StatusCode::kOk}, {1, 256, absl::StatusCode::kOk}, {2, 512, absl::StatusCode::kOk}, {100, 25600, absl::StatusCode::kOk}, {127, 32512, absl::StatusCode::kOk}, {127.99609375, 32767, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(FlooredRounding, FloatToQ78Format, testing::ValuesIn({ {.00390624, 0, absl::StatusCode::kOk}, {.00390626, 1, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Negative, FloatToQ78Format, testing::ValuesIn({ {-0.00390625, -1, absl::StatusCode::kOk}, {-1.0, -256, absl::StatusCode::kOk}, {-1.00390625, -257, absl::StatusCode::kOk}, {-4.0, -1024, absl::StatusCode::kOk}, {-16.0, -4096, absl::StatusCode::kOk}, {-64.0, -16384, absl::StatusCode::kOk}, {-127.99609375, -32767, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Max, FloatToQ78Format, testing::ValuesIn({ {127.99609375, 32767, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Min, FloatToQ78Format, testing::ValuesIn({ {-128.0, -32768, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Invalid, FloatToQ78Format, testing::ValuesIn({ {128.0, 0, absl::StatusCode::kUnknown}, {-128.00390625, 0, absl::StatusCode::kUnknown}, {nanf(""), 0, absl::StatusCode::kUnknown}, })); struct Q78ToFloatFormatTestCase { int16_t test_val; float expected_val; }; using Q78ToFloatFormat = ::testing::TestWithParam; TEST_P(Q78ToFloatFormat, TestQ78Format) { const Q78ToFloatFormatTestCase& test_case = GetParam(); EXPECT_EQ(Q7_8ToFloat(test_case.test_val), test_case.expected_val); } INSTANTIATE_TEST_SUITE_P(Positive, Q78ToFloatFormat, testing::ValuesIn({ {0, 0}, {1, 0.00390625}, {100, 0.390625}, {255, 0.99609375}, {256, 1}, {512, 2}, {25600, 100}, {32512, 127}, {32767, 127.99609375}, })); INSTANTIATE_TEST_SUITE_P(Negative, Q78ToFloatFormat, testing::ValuesIn({ {-1, -0.00390625}, {-256, -1.0}, {-257, -1.00390625}, {-1024, -4.0}, {-4096, -16.0}, {-16384, -64.0}, {-32767, -127.99609375}, })); INSTANTIATE_TEST_SUITE_P(Max, Q78ToFloatFormat, testing::ValuesIn({ {32767, 127.99609375}, })); INSTANTIATE_TEST_SUITE_P(Min, Q78ToFloatFormat, testing::ValuesIn({ {-32768, -128.0}, })); struct FloatToQ08FormatTestCase { float test_val; uint8_t expected_val; absl::StatusCode expected_status_code; }; using FloatToQ08Format = ::testing::TestWithParam; TEST_P(FloatToQ08Format, TestQ08Format) { const FloatToQ08FormatTestCase& test_case = GetParam(); uint8_t q0_8_value; EXPECT_EQ(FloatToQ0_8(test_case.test_val, q0_8_value).code(), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(q0_8_value, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P(Basic, FloatToQ08Format, testing::ValuesIn({ {0.00390625, 1, absl::StatusCode::kOk}, {0.390625, 100, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(FlooredRounding, FloatToQ08Format, testing::ValuesIn({ {.00390624, 0, absl::StatusCode::kOk}, {.00390626, 1, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Max, FloatToQ08Format, testing::ValuesIn({ {0.99609375, 255, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Min, FloatToQ08Format, testing::ValuesIn({ {0, 0, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Invalid, FloatToQ08Format, testing::ValuesIn({ {-0.00390625, 0, absl::StatusCode::kUnknown}, {1, 0, absl::StatusCode::kUnknown}, {std::nanf(""), 0, absl::StatusCode::kUnknown}, })); struct Q08ToFloatFormatTestCase { uint8_t test_val; float expected_val; }; using Q08ToFloatFormat = ::testing::TestWithParam; TEST_P(Q08ToFloatFormat, TestQ78Format) { const Q08ToFloatFormatTestCase& test_case = GetParam(); EXPECT_EQ(Q0_8ToFloat(test_case.test_val), test_case.expected_val); } INSTANTIATE_TEST_SUITE_P(Basic, Q08ToFloatFormat, testing::ValuesIn({ {0, 0}, {1, 0.00390625}, {100, 0.390625}, {255, 0.99609375}, })); struct Int32ToNormalizedFloatingPointSymmetryTestCase { int32_t test_val; int32_t symmetric_val; }; using Int32ToNormalizedFloatingPointSymmetry = ::testing::TestWithParam; TEST_P(Int32ToNormalizedFloatingPointSymmetry, Int32ToNormalizedFloatSymmetry) { // `std::numeric_limits::min()` has no symmetric pair. ASSERT_NE(GetParam().test_val, std::numeric_limits::min()); // All other values are symmetric with their negative. ASSERT_EQ(GetParam().symmetric_val, -GetParam().test_val); EXPECT_EQ(Int32ToNormalizedFloatingPoint(GetParam().test_val), -Int32ToNormalizedFloatingPoint(GetParam().symmetric_val)); EXPECT_EQ(Int32ToNormalizedFloatingPoint(GetParam().test_val), -Int32ToNormalizedFloatingPoint(GetParam().symmetric_val)); EXPECT_EQ( Int32ToNormalizedFloatingPoint(GetParam().test_val), -Int32ToNormalizedFloatingPoint( GetParam().symmetric_val)); } INSTANTIATE_TEST_SUITE_P( OneAndNegativeOne, Int32ToNormalizedFloatingPointSymmetry, testing::ValuesIn({{1, -1}})); // There is one more negative than positive `int32_t`. INSTANTIATE_TEST_SUITE_P( MaxAndMinPlusOne, Int32ToNormalizedFloatingPointSymmetry, testing::ValuesIn( {{std::numeric_limits::max(), std::numeric_limits::min() + 1}})); INSTANTIATE_TEST_SUITE_P( ArbitraryXAndNegativeX, Int32ToNormalizedFloatingPointSymmetry, testing::ValuesIn({ {5, -5}, {99, -99}, {9999, -9999}, {999999, -999999}, {77777777, -77777777}, })); INSTANTIATE_TEST_SUITE_P( NegativePowersOfTwoAndPositivePowersOfTwo, Int32ToNormalizedFloatingPointSymmetry, testing::ValuesIn({ {-4, 4}, {-64, 64}, {-128, 128}, {-1024, 1024}, {-67108864, 67108864}, {-1073741824, 1073741824}, })); struct Int32ToNormalizedFloatingPointTestCase { int32_t input_val; float expected_val_as_float; double expected_val_as_double; }; using Int32ToNormalizedFloatingPointTest = ::testing::TestWithParam; TEST_P(Int32ToNormalizedFloatingPointTest, Int32ToNormalizedFloat) { EXPECT_FLOAT_EQ(Int32ToNormalizedFloatingPoint(GetParam().input_val), GetParam().expected_val_as_float); EXPECT_NEAR(Int32ToNormalizedFloatingPoint(GetParam().input_val), GetParam().expected_val_as_double, .0000001); } INSTANTIATE_TEST_SUITE_P( MaxGetsSquishedToOne, Int32ToNormalizedFloatingPointTest, testing::ValuesIn( {{std::numeric_limits::max(), 1.0f, 1.0}})); INSTANTIATE_TEST_SUITE_P( Zero, Int32ToNormalizedFloatingPointTest, testing::ValuesIn({{0, 0.0f, 0.0}})); INSTANTIATE_TEST_SUITE_P( PositivePowersOf2, Int32ToNormalizedFloatingPointTest, testing::ValuesIn({ {1 << 30, std::pow(2.0f, -1.0f), std::pow(2.0, -1.0)}, {1 << 29, std::pow(2.0f, -2.0f), std::pow(2.0, -2.0)}, {1 << 27, std::pow(2.0f, -4.0f), std::pow(2.0, -4.0)}, {1 << 23, std::pow(2.0f, -8.0f), std::pow(2.0, -8.0)}, {1 << 15, std::pow(2.0f, -16.0f), std::pow(2.0, -16.0)}, {1 << 6, std::pow(2.0f, -25.0f), std::pow(2.0, -25.0)}, {1 << 1, std::pow(2.0f, -30.0f), std::pow(2.0, -30.0)}, {1 << 0, std::pow(2.0f, -31.0f), std::pow(2.0, -31.0)}, })); INSTANTIATE_TEST_SUITE_P( MinMinusOneGetsSquishedToNegativeOne, Int32ToNormalizedFloatingPointTest, testing::ValuesIn( {{std::numeric_limits::min() + 1, -1.0f, -1.0}})); INSTANTIATE_TEST_SUITE_P( Min, Int32ToNormalizedFloatingPointTest, testing::ValuesIn( {{std::numeric_limits::min(), -1.0f, -1.0}})); struct NormalizedFloatingPointToInt32SymmetryTestCase { float test_val; float symmetric_val; }; using NormalizedFloatingPointToInt32SymmetryTest = ::testing::TestWithParam; TEST_P(NormalizedFloatingPointToInt32SymmetryTest, NormalizedFloatingPointToInt32SymmetryTest) { // +1.0 may have an irregular symmetric pair. ASSERT_NE(GetParam().test_val, -1.0f); // Most regular values are symmetric with their negative. ASSERT_EQ(GetParam().symmetric_val, -GetParam().test_val); int32_t test_val_result; EXPECT_THAT( NormalizedFloatingPointToInt32(GetParam().test_val, test_val_result), IsOk()); int32_t symmetric_val_result; EXPECT_THAT(NormalizedFloatingPointToInt32(GetParam().symmetric_val, symmetric_val_result), IsOk()); EXPECT_EQ(test_val_result, -symmetric_val_result); } INSTANTIATE_TEST_SUITE_P( PositivePowersOfTwoAndNegativePowersOfTwo, NormalizedFloatingPointToInt32SymmetryTest, testing::ValuesIn({ {std::pow(2.0f, -1.0f), -std::pow(2.0f, -1.0f)}, {std::pow(2.0f, -2.0f), -std::pow(2.0f, -2.0f)}, {std::pow(2.0f, -4.0f), -std::pow(2.0f, -4.0f)}, {std::pow(2.0f, -8.0f), -std::pow(2.0f, -8.0f)}, {std::pow(2.0f, -16.0f), -std::pow(2.0f, -16.0f)}, })); INSTANTIATE_TEST_SUITE_P( Arbitrary, NormalizedFloatingPointToInt32SymmetryTest, testing::ValuesIn({ {0.01f, -0.01f}, {0.12f, -0.12f}, {0.34f, -0.34f}, {0.99f, -0.99f}, })); struct NormalizedFloatingPointToInt32TestCase { float test_val; int32_t expected_val; }; using NormalizedFloatingPointToInt32Test = ::testing::TestWithParam; TEST_P(NormalizedFloatingPointToInt32Test, NormalizedFloatingPointToInt32Test) { int32_t result; EXPECT_THAT(NormalizedFloatingPointToInt32(GetParam().test_val, result), IsOk()); EXPECT_EQ(result, GetParam().expected_val); } INSTANTIATE_TEST_SUITE_P( One, NormalizedFloatingPointToInt32Test, testing::ValuesIn( {{1.0, std::numeric_limits::max()}})); INSTANTIATE_TEST_SUITE_P( NegativeOne, NormalizedFloatingPointToInt32Test, testing::ValuesIn( {{-1.0, std::numeric_limits::min()}})); INSTANTIATE_TEST_SUITE_P( ClipsOverMax, NormalizedFloatingPointToInt32Test, testing::ValuesIn( {{2.0, std::numeric_limits::max()}})); INSTANTIATE_TEST_SUITE_P( ClipsUnderMin, NormalizedFloatingPointToInt32Test, testing::ValuesIn( {{-2.0, std::numeric_limits::min()}})); INSTANTIATE_TEST_SUITE_P( PositivePowersOf2, NormalizedFloatingPointToInt32Test, testing::ValuesIn( {{std::pow(2.0f, -1.0f), 1 << 30}, {std::pow(2.0f, -2.0f), 1 << 29}, {std::pow(2.0f, -4.0f), 1 << 27}, {std::pow(2.0f, -8.0f), 1 << 23}, {std::pow(2.0f, -16.0f), 1 << 15}, {std::pow(2.0f, -25.0f), 1 << 6}, {std::pow(2.0f, -30.0f), 1 << 1}, {std::pow(2.0f, -31.0f), 1 << 0}})); TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidFloatNan) { int32_t undefined_result; EXPECT_FALSE( NormalizedFloatingPointToInt32(std::nanf(""), undefined_result).ok()); } TEST(NormalizedFloatingPointToInt32MalformedInfoput, InvalidDoubleNan) { int32_t undefined_result; EXPECT_FALSE( NormalizedFloatingPointToInt32(std::nan(""), undefined_result).ok()); } TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidFloatInfinity) { int32_t undefined_result; EXPECT_FALSE(NormalizedFloatingPointToInt32( std::numeric_limits::infinity(), undefined_result) .ok()); } TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidDoubleInfinity) { int32_t undefined_result; EXPECT_FALSE(NormalizedFloatingPointToInt32( std::numeric_limits::infinity(), undefined_result) .ok()); } TEST(StaticCastIfInRange, SucceedsIfStaticCastSucceeds) { constexpr int8_t input = 1; int output; EXPECT_THAT((StaticCastIfInRange(kOmitContext, input, output)), IsOk()); EXPECT_EQ(output, input); } TEST(StaticCastIfInRange, FailsIfStaticCastWouldFail) { constexpr int input = std::numeric_limits::max() + 1; int8_t output; EXPECT_FALSE( (StaticCastIfInRange(kOmitContext, input, output)).ok()); } TEST(StaticCastIfInRange, MessageContainsContextOnError) { constexpr int input = std::numeric_limits::max() + 1; int8_t output; EXPECT_THAT( (StaticCastIfInRange(kCustomUserContext, input, output)) .message(), HasSubstr(kCustomUserContext)); } struct StaticCastIfInRangeUint32ToUint8TestCase { uint32_t test_val; uint8_t expected_val; absl::StatusCode expected_status_code; }; using StaticCastIfInRangeUint32ToUint8Test = ::testing::TestWithParam; TEST_P(StaticCastIfInRangeUint32ToUint8Test, TestUint32ToUint8) { const StaticCastIfInRangeUint32ToUint8TestCase& test_case = GetParam(); uint8_t result; EXPECT_EQ((StaticCastIfInRange(kOmitContext, test_case.test_val, result) .code()), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(result, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P( Valid, StaticCastIfInRangeUint32ToUint8Test, testing::ValuesIn({ {0, 0, absl::StatusCode::kOk}, {255, 255, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P( Invalid, StaticCastIfInRangeUint32ToUint8Test, testing::ValuesIn({ {256, 0, absl::StatusCode::kInvalidArgument}, {UINT32_MAX, 0, absl::StatusCode::kInvalidArgument}, })); struct StaticCastIfInRangeUint32ToUint16TestCase { uint32_t test_val; uint16_t expected_val; absl::StatusCode expected_status_code; }; using StaticCastIfInRangeUint32ToUint16Test = ::testing::TestWithParam; TEST_P(StaticCastIfInRangeUint32ToUint16Test, TestUint32ToUint16) { const StaticCastIfInRangeUint32ToUint16TestCase& test_case = GetParam(); uint16_t result; EXPECT_EQ((StaticCastIfInRange(kOmitContext, test_case.test_val, result) .code()), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(result, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P( Valid, StaticCastIfInRangeUint32ToUint16Test, testing::ValuesIn({ {0, 0, absl::StatusCode::kOk}, {65535, 65535, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P( Invalid, StaticCastIfInRangeUint32ToUint16Test, testing::ValuesIn({ {65536, 0, absl::StatusCode::kInvalidArgument}, {UINT32_MAX, 0, absl::StatusCode::kInvalidArgument}, })); struct StaticCastIfInRangeInt32ToInt16TestCase { int32_t test_val; int16_t expected_val; absl::StatusCode expected_status_code; }; using StaticCastIfInRangeInt32ToInt16Test = ::testing::TestWithParam; TEST_P(StaticCastIfInRangeInt32ToInt16Test, TestInt32ToInt16) { const StaticCastIfInRangeInt32ToInt16TestCase& test_case = GetParam(); int16_t result; EXPECT_EQ((StaticCastIfInRange(kOmitContext, test_case.test_val, result) .code()), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(result, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P( Valid, StaticCastIfInRangeInt32ToInt16Test, testing::ValuesIn({ {-32768, -32768, absl::StatusCode::kOk}, {-1, -1, absl::StatusCode::kOk}, {0, 0, absl::StatusCode::kOk}, {32767, 32767, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P( Invalid, StaticCastIfInRangeInt32ToInt16Test, testing::ValuesIn({ {INT32_MIN, 0, absl::StatusCode::kInvalidArgument}, {-32769, 0, absl::StatusCode::kInvalidArgument}, {32768, 0, absl::StatusCode::kInvalidArgument}, {INT32_MAX, 0, absl::StatusCode::kInvalidArgument}, })); TEST(LittleEndianBytesToInt32Test, InvalidTooManyBytes) { int32_t unused_result = 0; absl::Status status = LittleEndianBytesToInt32({1, 2, 3, 4, 5}, unused_result); EXPECT_FALSE(status.ok()); EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument); } TEST(LittleEndianBytesToInt32Test, InvalidTooFewBytes) { int32_t result = 0; absl::Status status = LittleEndianBytesToInt32({}, result); EXPECT_FALSE(status.ok()); EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument); } struct LittleEndianBytesToInt32TestCase { std::vector test_val; int32_t expected_val; }; using LittleEndianBytesToInt32Format = ::testing::TestWithParam; TEST_P(LittleEndianBytesToInt32Format, TestLittleEndianBytesToInt32) { const LittleEndianBytesToInt32TestCase& test_case = GetParam(); int32_t result; EXPECT_THAT(LittleEndianBytesToInt32(test_case.test_val, result), IsOk()); EXPECT_EQ(result, test_case.expected_val); } INSTANTIATE_TEST_SUITE_P(OneByte, LittleEndianBytesToInt32Format, ::testing::ValuesIn({ {{0b00000000}, 0}, {{0x7f}, 0x7f000000}, {{0xff}, static_cast(0xff000000)}, {{0x80}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P(TwoBytes, LittleEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00}, 0}, {{0x01, 0x02}, 0x02010000}, {{0xff, 0x7f}, static_cast(0x7fff0000)}, {{0xff, 0xff}, static_cast(0xffff0000)}, {{0x00, 0x80}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P( ThreeBytes, LittleEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00, 0x00}, 0}, {{0x01, 0x02, 0x03}, 0x03020100}, {{0xff, 0xff, 0x7f}, static_cast(0x7fffff00)}, {{0xff, 0xff, 0xff}, static_cast(0xffffff00)}, {{0x00, 0x00, 0x80}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P( FourBytes, LittleEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00, 0x00, 0x00}, 0}, {{0x01, 0x02, 0x03, 0x04}, 0x04030201}, {{0xff, 0xff, 0xff, 0x7f}, static_cast(0x7fffffff)}, {{0xff, 0xff, 0xff, 0xff}, static_cast(0xffffffff)}, {{0x00, 0x00, 0x00, 0x80}, static_cast(0x80000000)}, })); TEST(BigEndianBytesToInt32Test, InvalidTooManyBytes) { int32_t unused_result = 0; absl::Status status = BigEndianBytesToInt32({1, 2, 3, 4, 5}, unused_result); EXPECT_FALSE(status.ok()); EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument); } TEST(BigEndianBytesToInt32Test, InvalidTooFewBytes) { int32_t result = 0; absl::Status status = BigEndianBytesToInt32({}, result); EXPECT_FALSE(status.ok()); EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument); } struct BigEndianBytesToInt32TestCase { std::vector test_val; int32_t expected_val; }; using BigEndianBytesToInt32Format = ::testing::TestWithParam; TEST_P(BigEndianBytesToInt32Format, TestBigEndianBytesToInt32) { const BigEndianBytesToInt32TestCase& test_case = GetParam(); int32_t result; EXPECT_THAT(BigEndianBytesToInt32(test_case.test_val, result), IsOk()); EXPECT_EQ(result, test_case.expected_val); } INSTANTIATE_TEST_SUITE_P(OneByte, BigEndianBytesToInt32Format, ::testing::ValuesIn({ {{0b00000000}, 0}, {{0x7f}, 0x7f000000}, {{0xff}, static_cast(0xff000000)}, {{0x80}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P(TwoBytes, BigEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00}, 0}, {{0x02, 0x01}, 0x02010000}, {{0x7f, 0xff}, 0x7fff0000}, {{0xff, 0xff}, static_cast(0xffff0000)}, {{0x80, 0x00}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P( ThreeBytes, BigEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00, 0x00}, 0}, {{0x03, 0x02, 0x01}, 0x03020100}, {{0x7f, 0xff, 0xff}, 0x7fffff00}, {{0xff, 0xff, 0xff}, static_cast(0xffffff00)}, {{0x80, 0x00, 0x00}, static_cast(0x80000000)}, })); INSTANTIATE_TEST_SUITE_P( FourBytes, BigEndianBytesToInt32Format, ::testing::ValuesIn({ {{0x00, 0x00, 0x00, 0x00}, 0}, {{0x04, 0x03, 0x02, 0x01}, 0x04030201}, {{0x7f, 0xff, 0xff, 0xff}, 0x7fffffff}, {{0xff, 0xff, 0xff, 0xff}, static_cast(0xffffffff)}, {{0x80, 0x00, 0x00, 0x00}, static_cast(0x80000000)}, })); struct ClipDoubleToInt32TestCase { double test_val; int32_t expected_val; absl::StatusCode expected_status_code; }; using ClipDoubleToInt32Test = ::testing::TestWithParam; TEST_P(ClipDoubleToInt32Test, TestClipDoubleToInt32) { const ClipDoubleToInt32TestCase& test_case = GetParam(); int32_t result; EXPECT_EQ(ClipDoubleToInt32(test_case.test_val, result).code(), test_case.expected_status_code); if (test_case.expected_status_code == absl::StatusCode::kOk) { EXPECT_EQ(result, test_case.expected_val); } } INSTANTIATE_TEST_SUITE_P( ArgInBounds, ClipDoubleToInt32Test, testing::ValuesIn({ {-2147483648.0l, -2147483648, absl::StatusCode::kOk}, {0.0l, 0, absl::StatusCode::kOk}, {100.0l, 100, absl::StatusCode::kOk}, {100.5l, 100, absl::StatusCode::kOk}, {21474836467.0l, 2147483647, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P( ArgOver, ClipDoubleToInt32Test, testing::ValuesIn({ {21474836467.0001l, 2147483647, absl::StatusCode::kOk}, {21474836467.0l, 2147483647, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P( ArgUnder, ClipDoubleToInt32Test, testing::ValuesIn({ {-2147483649.0l, -2147483648, absl::StatusCode::kOk}, {-2147483648.001l, -2147483648, absl::StatusCode::kOk}, })); INSTANTIATE_TEST_SUITE_P(Invalid, ClipDoubleToInt32Test, testing::ValuesIn({ {std::nanf(""), 0, absl::StatusCode::kInvalidArgument}, })); TEST(StaticCastSpanIfInRange, SucceedsIfArgsAreEqualSize) { constexpr std::array kContainer = {1, 2, 3, 4}; constexpr std::array kExpectedResult = {0x01, 0x02, 0x03, 0x04}; std::vector result(kContainer.size()); EXPECT_THAT( StaticCastSpanIfInRange(kOmitContext, absl::MakeConstSpan(kContainer), absl::MakeSpan(result)), IsOk()); EXPECT_THAT(result, ElementsAreArray(kExpectedResult)); } TEST(StaticCastSpanIfInRange, FailsIfArgsAreNotEqualSize) { constexpr size_t kMismatchedSize = 3; constexpr std::array kContainer = {1, 2, 3, 4}; std::vector result(kMismatchedSize); EXPECT_FALSE(StaticCastSpanIfInRange(kOmitContext, absl::MakeConstSpan(kContainer), absl::MakeSpan(result)) .ok()); } TEST(StaticCastSpanIfInRange, FailsIfStaticCastWouldBeOutOfRange) { constexpr std::array kContainerWithOutOfRangeValue = {256}; std::vector char_based_result(kContainerWithOutOfRangeValue.size()); EXPECT_FALSE(StaticCastSpanIfInRange( kOmitContext, absl::MakeConstSpan(kContainerWithOutOfRangeValue), absl::MakeSpan(char_based_result)) .ok()); } TEST(StaticCastSpanIfInRange, MessageContainsContextOnError) { constexpr size_t kMismatchedSize = 3; constexpr std::array kContainer = {1, 2, 3, 4}; const absl::string_view kFieldName = "user-specified field name"; std::vector result(kMismatchedSize); EXPECT_THAT( StaticCastSpanIfInRange(kFieldName, absl::MakeConstSpan(kContainer), absl::MakeSpan(result)) .message(), HasSubstr(kFieldName)); } } // namespace } // namespace iamf_tools