| /* |
| * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "rtc_base/units/unit_base.h" |
| |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| namespace { |
| class TestUnit final : public rtc_units_impl::RelativeUnit<TestUnit> { |
| public: |
| TestUnit() = delete; |
| |
| using UnitBase::FromValue; |
| using UnitBase::ToValue; |
| using UnitBase::ToValueOr; |
| |
| template <typename T> |
| static constexpr TestUnit FromKilo(T kilo) { |
| return FromFraction(1000, kilo); |
| } |
| template <typename T = int64_t> |
| T ToKilo() const { |
| return UnitBase::ToFraction<1000, T>(); |
| } |
| constexpr int64_t ToKiloOr(int64_t fallback) const { |
| return UnitBase::ToFractionOr<1000>(fallback); |
| } |
| template <typename T> |
| constexpr T ToMilli() const { |
| return UnitBase::ToMultiple<1000, T>(); |
| } |
| |
| private: |
| friend class rtc_units_impl::UnitBase<TestUnit>; |
| static constexpr bool one_sided = false; |
| using RelativeUnit<TestUnit>::RelativeUnit; |
| }; |
| constexpr TestUnit TestUnitAddKilo(TestUnit value, int add_kilo) { |
| value += TestUnit::FromKilo(add_kilo); |
| return value; |
| } |
| } // namespace |
| namespace test { |
| TEST(UnitBaseTest, ConstExpr) { |
| constexpr int64_t kValue = -12345; |
| constexpr TestUnit kTestUnitZero = TestUnit::Zero(); |
| constexpr TestUnit kTestUnitPlusInf = TestUnit::PlusInfinity(); |
| constexpr TestUnit kTestUnitMinusInf = TestUnit::MinusInfinity(); |
| |
| static_assert(kTestUnitZero.IsZero(), ""); |
| static_assert(kTestUnitPlusInf.IsPlusInfinity(), ""); |
| static_assert(kTestUnitMinusInf.IsMinusInfinity(), ""); |
| static_assert(kTestUnitPlusInf.ToKiloOr(-1) == -1, ""); |
| |
| // Check FromValue is constexpr for floats. |
| static_assert(TestUnit::FromValue(0.0).IsZero()); |
| static_assert(TestUnit::FromValue(INFINITY).IsPlusInfinity()); |
| static_assert(TestUnit::FromValue(-INFINITY).IsMinusInfinity()); |
| static_assert(TestUnit::FromValue(250.0) == TestUnit::FromValue(250)); |
| static_assert(TestUnit::FromValue(-250.0) == TestUnit::FromValue(-250)); |
| |
| static_assert(kTestUnitPlusInf > kTestUnitZero, ""); |
| |
| constexpr TestUnit kTestUnitKilo = TestUnit::FromKilo(kValue); |
| constexpr TestUnit kTestUnitValue = TestUnit::FromValue(kValue); |
| |
| static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, ""); |
| static_assert(kTestUnitValue.ToValueOr(0) == kValue, ""); |
| static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000, |
| ""); |
| static_assert(TestUnit::FromValue(500) / 2 == TestUnit::FromValue(250)); |
| static_assert(TestUnit::FromValue(500.0) / 2 == TestUnit::FromValue(250.0)); |
| } |
| |
| TEST(UnitBaseTest, GetBackSameValues) { |
| const int64_t kValue = 499; |
| for (int sign = -1; sign <= 1; ++sign) { |
| int64_t value = kValue * sign; |
| EXPECT_EQ(TestUnit::FromKilo(value).ToKilo(), value); |
| EXPECT_EQ(TestUnit::FromValue(value).ToValue<int64_t>(), value); |
| } |
| EXPECT_EQ(TestUnit::Zero().ToValue<int64_t>(), 0); |
| } |
| |
| TEST(UnitBaseTest, GetDifferentPrefix) { |
| const int64_t kValue = 3000000; |
| EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo(), kValue / 1000); |
| EXPECT_EQ(TestUnit::FromKilo(kValue).ToValue<int64_t>(), kValue * 1000); |
| } |
| |
| TEST(UnitBaseTest, IdentityChecks) { |
| const int64_t kValue = 3000; |
| EXPECT_TRUE(TestUnit::Zero().IsZero()); |
| EXPECT_FALSE(TestUnit::FromKilo(kValue).IsZero()); |
| |
| EXPECT_TRUE(TestUnit::PlusInfinity().IsInfinite()); |
| EXPECT_TRUE(TestUnit::MinusInfinity().IsInfinite()); |
| EXPECT_FALSE(TestUnit::Zero().IsInfinite()); |
| EXPECT_FALSE(TestUnit::FromKilo(-kValue).IsInfinite()); |
| EXPECT_FALSE(TestUnit::FromKilo(kValue).IsInfinite()); |
| |
| EXPECT_FALSE(TestUnit::PlusInfinity().IsFinite()); |
| EXPECT_FALSE(TestUnit::MinusInfinity().IsFinite()); |
| EXPECT_TRUE(TestUnit::FromKilo(-kValue).IsFinite()); |
| EXPECT_TRUE(TestUnit::FromKilo(kValue).IsFinite()); |
| EXPECT_TRUE(TestUnit::Zero().IsFinite()); |
| |
| EXPECT_TRUE(TestUnit::PlusInfinity().IsPlusInfinity()); |
| EXPECT_FALSE(TestUnit::MinusInfinity().IsPlusInfinity()); |
| |
| EXPECT_TRUE(TestUnit::MinusInfinity().IsMinusInfinity()); |
| EXPECT_FALSE(TestUnit::PlusInfinity().IsMinusInfinity()); |
| } |
| |
| TEST(UnitBaseTest, ComparisonOperators) { |
| const int64_t kSmall = 450; |
| const int64_t kLarge = 451; |
| const TestUnit small = TestUnit::FromKilo(kSmall); |
| const TestUnit large = TestUnit::FromKilo(kLarge); |
| |
| EXPECT_EQ(TestUnit::Zero(), TestUnit::FromKilo(0)); |
| EXPECT_EQ(TestUnit::PlusInfinity(), TestUnit::PlusInfinity()); |
| EXPECT_EQ(small, TestUnit::FromKilo(kSmall)); |
| EXPECT_LE(small, TestUnit::FromKilo(kSmall)); |
| EXPECT_GE(small, TestUnit::FromKilo(kSmall)); |
| EXPECT_NE(small, TestUnit::FromKilo(kLarge)); |
| EXPECT_LE(small, TestUnit::FromKilo(kLarge)); |
| EXPECT_LT(small, TestUnit::FromKilo(kLarge)); |
| EXPECT_GE(large, TestUnit::FromKilo(kSmall)); |
| EXPECT_GT(large, TestUnit::FromKilo(kSmall)); |
| EXPECT_LT(TestUnit::Zero(), small); |
| EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); |
| EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); |
| |
| EXPECT_GT(TestUnit::PlusInfinity(), large); |
| EXPECT_LT(TestUnit::MinusInfinity(), TestUnit::Zero()); |
| } |
| |
| TEST(UnitBaseTest, Clamping) { |
| const TestUnit upper = TestUnit::FromKilo(800); |
| const TestUnit lower = TestUnit::FromKilo(100); |
| const TestUnit under = TestUnit::FromKilo(100); |
| const TestUnit inside = TestUnit::FromKilo(500); |
| const TestUnit over = TestUnit::FromKilo(1000); |
| EXPECT_EQ(under.Clamped(lower, upper), lower); |
| EXPECT_EQ(inside.Clamped(lower, upper), inside); |
| EXPECT_EQ(over.Clamped(lower, upper), upper); |
| |
| TestUnit mutable_delta = lower; |
| mutable_delta.Clamp(lower, upper); |
| EXPECT_EQ(mutable_delta, lower); |
| mutable_delta = inside; |
| mutable_delta.Clamp(lower, upper); |
| EXPECT_EQ(mutable_delta, inside); |
| mutable_delta = over; |
| mutable_delta.Clamp(lower, upper); |
| EXPECT_EQ(mutable_delta, upper); |
| } |
| |
| TEST(UnitBaseTest, CanBeInititializedFromLargeInt) { |
| const int kMaxInt = std::numeric_limits<int>::max(); |
| EXPECT_EQ(TestUnit::FromKilo(kMaxInt).ToValue<int64_t>(), |
| static_cast<int64_t>(kMaxInt) * 1000); |
| } |
| |
| TEST(UnitBaseTest, ConvertsToAndFromDouble) { |
| const int64_t kValue = 17017; |
| const double kMilliDouble = kValue * 1e3; |
| const double kValueDouble = kValue; |
| const double kKiloDouble = kValue * 1e-3; |
| |
| EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo<double>(), kKiloDouble); |
| EXPECT_EQ(TestUnit::FromKilo(kKiloDouble).ToValue<int64_t>(), kValue); |
| |
| EXPECT_EQ(TestUnit::FromValue(kValue).ToValue<double>(), kValueDouble); |
| EXPECT_EQ(TestUnit::FromValue(kValueDouble).ToValue<int64_t>(), kValue); |
| |
| EXPECT_NEAR(TestUnit::FromValue(kValue).ToMilli<double>(), kMilliDouble, 1); |
| |
| const double kPlusInfinity = std::numeric_limits<double>::infinity(); |
| const double kMinusInfinity = -kPlusInfinity; |
| |
| EXPECT_EQ(TestUnit::PlusInfinity().ToKilo<double>(), kPlusInfinity); |
| EXPECT_EQ(TestUnit::MinusInfinity().ToKilo<double>(), kMinusInfinity); |
| EXPECT_EQ(TestUnit::PlusInfinity().ToValue<double>(), kPlusInfinity); |
| EXPECT_EQ(TestUnit::MinusInfinity().ToValue<double>(), kMinusInfinity); |
| EXPECT_EQ(TestUnit::PlusInfinity().ToMilli<double>(), kPlusInfinity); |
| EXPECT_EQ(TestUnit::MinusInfinity().ToMilli<double>(), kMinusInfinity); |
| |
| EXPECT_TRUE(TestUnit::FromKilo(kPlusInfinity).IsPlusInfinity()); |
| EXPECT_TRUE(TestUnit::FromKilo(kMinusInfinity).IsMinusInfinity()); |
| EXPECT_TRUE(TestUnit::FromValue(kPlusInfinity).IsPlusInfinity()); |
| EXPECT_TRUE(TestUnit::FromValue(kMinusInfinity).IsMinusInfinity()); |
| } |
| |
| TEST(UnitBaseTest, MathOperations) { |
| const int64_t kValueA = 267; |
| const int64_t kValueB = 450; |
| const TestUnit delta_a = TestUnit::FromKilo(kValueA); |
| const TestUnit delta_b = TestUnit::FromKilo(kValueB); |
| EXPECT_EQ((delta_a + delta_b).ToKilo(), kValueA + kValueB); |
| EXPECT_EQ((delta_a - delta_b).ToKilo(), kValueA - kValueB); |
| |
| const int32_t kInt32Value = 123; |
| const double kFloatValue = 123.0; |
| EXPECT_EQ((TestUnit::FromValue(kValueA) * kValueB).ToValue<int64_t>(), |
| kValueA * kValueB); |
| EXPECT_EQ((TestUnit::FromValue(kValueA) * kInt32Value).ToValue<int64_t>(), |
| kValueA * kInt32Value); |
| EXPECT_EQ((TestUnit::FromValue(kValueA) * kFloatValue).ToValue<int64_t>(), |
| kValueA * kFloatValue); |
| |
| EXPECT_EQ((delta_b / 10).ToKilo(), kValueB / 10); |
| EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA); |
| |
| TestUnit mutable_delta = TestUnit::FromKilo(kValueA); |
| mutable_delta += TestUnit::FromKilo(kValueB); |
| EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA + kValueB)); |
| mutable_delta -= TestUnit::FromKilo(kValueB); |
| EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA)); |
| |
| // Division by an int rounds towards zero to follow regular int division. |
| EXPECT_EQ(TestUnit::FromValue(789) / 10, TestUnit::FromValue(78)); |
| EXPECT_EQ(TestUnit::FromValue(-789) / 10, TestUnit::FromValue(-78)); |
| } |
| |
| #if GTEST_HAS_DEATH_TEST && RTC_DCHECK_IS_ON && !defined(WEBRTC_ANDROID) |
| TEST(UnitBaseTest, CrashesWhenCreatedFromNan) { |
| EXPECT_DEATH(TestUnit::FromValue(NAN), ""); |
| EXPECT_DEATH(TestUnit::FromValue(0.0 / 0.0), ""); |
| EXPECT_DEATH(TestUnit::FromValue(INFINITY - INFINITY), ""); |
| } |
| #endif |
| |
| TEST(UnitBaseTest, InfinityOperations) { |
| const int64_t kValue = 267; |
| const TestUnit finite = TestUnit::FromKilo(kValue); |
| EXPECT_TRUE((TestUnit::PlusInfinity() + finite).IsPlusInfinity()); |
| EXPECT_TRUE((TestUnit::PlusInfinity() - finite).IsPlusInfinity()); |
| EXPECT_TRUE((finite + TestUnit::PlusInfinity()).IsPlusInfinity()); |
| EXPECT_TRUE((finite - TestUnit::MinusInfinity()).IsPlusInfinity()); |
| |
| EXPECT_TRUE((TestUnit::MinusInfinity() + finite).IsMinusInfinity()); |
| EXPECT_TRUE((TestUnit::MinusInfinity() - finite).IsMinusInfinity()); |
| EXPECT_TRUE((finite + TestUnit::MinusInfinity()).IsMinusInfinity()); |
| EXPECT_TRUE((finite - TestUnit::PlusInfinity()).IsMinusInfinity()); |
| } |
| |
| TEST(UnitBaseTest, UnaryMinus) { |
| const int64_t kValue = 1337; |
| const TestUnit unit = TestUnit::FromValue(kValue); |
| EXPECT_EQ(-unit.ToValue(), -kValue); |
| |
| // Check infinity. |
| EXPECT_EQ(-TestUnit::PlusInfinity(), TestUnit::MinusInfinity()); |
| EXPECT_EQ(-TestUnit::MinusInfinity(), TestUnit::PlusInfinity()); |
| } |
| |
| } // namespace test |
| } // namespace webrtc |