1 /*
2  *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rtc_base/units/unit_base.h"
12 
13 #include "test/gtest.h"
14 
15 namespace webrtc {
16 namespace {
17 class TestUnit final : public rtc_units_impl::RelativeUnit<TestUnit> {
18  public:
19   TestUnit() = delete;
20 
21   using UnitBase::FromValue;
22   using UnitBase::ToValue;
23   using UnitBase::ToValueOr;
24 
25   template <typename T>
FromKilo(T kilo)26   static constexpr TestUnit FromKilo(T kilo) {
27     return FromFraction(1000, kilo);
28   }
29   template <typename T = int64_t>
ToKilo() const30   T ToKilo() const {
31     return UnitBase::ToFraction<1000, T>();
32   }
ToKiloOr(int64_t fallback) const33   constexpr int64_t ToKiloOr(int64_t fallback) const {
34     return UnitBase::ToFractionOr<1000>(fallback);
35   }
36   template <typename T>
ToMilli() const37   constexpr T ToMilli() const {
38     return UnitBase::ToMultiple<1000, T>();
39   }
40 
41  private:
42   friend class rtc_units_impl::UnitBase<TestUnit>;
43   static constexpr bool one_sided = false;
44   using RelativeUnit<TestUnit>::RelativeUnit;
45 };
TestUnitAddKilo(TestUnit value,int add_kilo)46 constexpr TestUnit TestUnitAddKilo(TestUnit value, int add_kilo) {
47   value += TestUnit::FromKilo(add_kilo);
48   return value;
49 }
50 }  // namespace
51 namespace test {
TEST(UnitBaseTest,ConstExpr)52 TEST(UnitBaseTest, ConstExpr) {
53   constexpr int64_t kValue = -12345;
54   constexpr TestUnit kTestUnitZero = TestUnit::Zero();
55   constexpr TestUnit kTestUnitPlusInf = TestUnit::PlusInfinity();
56   constexpr TestUnit kTestUnitMinusInf = TestUnit::MinusInfinity();
57   static_assert(kTestUnitZero.IsZero(), "");
58   static_assert(kTestUnitPlusInf.IsPlusInfinity(), "");
59   static_assert(kTestUnitMinusInf.IsMinusInfinity(), "");
60   static_assert(kTestUnitPlusInf.ToKiloOr(-1) == -1, "");
61 
62   static_assert(kTestUnitPlusInf > kTestUnitZero, "");
63 
64   constexpr TestUnit kTestUnitKilo = TestUnit::FromKilo(kValue);
65   constexpr TestUnit kTestUnitValue = TestUnit::FromValue(kValue);
66 
67   static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, "");
68   static_assert(kTestUnitValue.ToValueOr(0) == kValue, "");
69   static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000,
70                 "");
71 }
72 
TEST(UnitBaseTest,GetBackSameValues)73 TEST(UnitBaseTest, GetBackSameValues) {
74   const int64_t kValue = 499;
75   for (int sign = -1; sign <= 1; ++sign) {
76     int64_t value = kValue * sign;
77     EXPECT_EQ(TestUnit::FromKilo(value).ToKilo(), value);
78     EXPECT_EQ(TestUnit::FromValue(value).ToValue<int64_t>(), value);
79   }
80   EXPECT_EQ(TestUnit::Zero().ToValue<int64_t>(), 0);
81 }
82 
TEST(UnitBaseTest,GetDifferentPrefix)83 TEST(UnitBaseTest, GetDifferentPrefix) {
84   const int64_t kValue = 3000000;
85   EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo(), kValue / 1000);
86   EXPECT_EQ(TestUnit::FromKilo(kValue).ToValue<int64_t>(), kValue * 1000);
87 }
88 
TEST(UnitBaseTest,IdentityChecks)89 TEST(UnitBaseTest, IdentityChecks) {
90   const int64_t kValue = 3000;
91   EXPECT_TRUE(TestUnit::Zero().IsZero());
92   EXPECT_FALSE(TestUnit::FromKilo(kValue).IsZero());
93 
94   EXPECT_TRUE(TestUnit::PlusInfinity().IsInfinite());
95   EXPECT_TRUE(TestUnit::MinusInfinity().IsInfinite());
96   EXPECT_FALSE(TestUnit::Zero().IsInfinite());
97   EXPECT_FALSE(TestUnit::FromKilo(-kValue).IsInfinite());
98   EXPECT_FALSE(TestUnit::FromKilo(kValue).IsInfinite());
99 
100   EXPECT_FALSE(TestUnit::PlusInfinity().IsFinite());
101   EXPECT_FALSE(TestUnit::MinusInfinity().IsFinite());
102   EXPECT_TRUE(TestUnit::FromKilo(-kValue).IsFinite());
103   EXPECT_TRUE(TestUnit::FromKilo(kValue).IsFinite());
104   EXPECT_TRUE(TestUnit::Zero().IsFinite());
105 
106   EXPECT_TRUE(TestUnit::PlusInfinity().IsPlusInfinity());
107   EXPECT_FALSE(TestUnit::MinusInfinity().IsPlusInfinity());
108 
109   EXPECT_TRUE(TestUnit::MinusInfinity().IsMinusInfinity());
110   EXPECT_FALSE(TestUnit::PlusInfinity().IsMinusInfinity());
111 }
112 
TEST(UnitBaseTest,ComparisonOperators)113 TEST(UnitBaseTest, ComparisonOperators) {
114   const int64_t kSmall = 450;
115   const int64_t kLarge = 451;
116   const TestUnit small = TestUnit::FromKilo(kSmall);
117   const TestUnit large = TestUnit::FromKilo(kLarge);
118 
119   EXPECT_EQ(TestUnit::Zero(), TestUnit::FromKilo(0));
120   EXPECT_EQ(TestUnit::PlusInfinity(), TestUnit::PlusInfinity());
121   EXPECT_EQ(small, TestUnit::FromKilo(kSmall));
122   EXPECT_LE(small, TestUnit::FromKilo(kSmall));
123   EXPECT_GE(small, TestUnit::FromKilo(kSmall));
124   EXPECT_NE(small, TestUnit::FromKilo(kLarge));
125   EXPECT_LE(small, TestUnit::FromKilo(kLarge));
126   EXPECT_LT(small, TestUnit::FromKilo(kLarge));
127   EXPECT_GE(large, TestUnit::FromKilo(kSmall));
128   EXPECT_GT(large, TestUnit::FromKilo(kSmall));
129   EXPECT_LT(TestUnit::Zero(), small);
130   EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall));
131   EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall));
132 
133   EXPECT_GT(TestUnit::PlusInfinity(), large);
134   EXPECT_LT(TestUnit::MinusInfinity(), TestUnit::Zero());
135 }
136 
TEST(UnitBaseTest,Clamping)137 TEST(UnitBaseTest, Clamping) {
138   const TestUnit upper = TestUnit::FromKilo(800);
139   const TestUnit lower = TestUnit::FromKilo(100);
140   const TestUnit under = TestUnit::FromKilo(100);
141   const TestUnit inside = TestUnit::FromKilo(500);
142   const TestUnit over = TestUnit::FromKilo(1000);
143   EXPECT_EQ(under.Clamped(lower, upper), lower);
144   EXPECT_EQ(inside.Clamped(lower, upper), inside);
145   EXPECT_EQ(over.Clamped(lower, upper), upper);
146 
147   TestUnit mutable_delta = lower;
148   mutable_delta.Clamp(lower, upper);
149   EXPECT_EQ(mutable_delta, lower);
150   mutable_delta = inside;
151   mutable_delta.Clamp(lower, upper);
152   EXPECT_EQ(mutable_delta, inside);
153   mutable_delta = over;
154   mutable_delta.Clamp(lower, upper);
155   EXPECT_EQ(mutable_delta, upper);
156 }
157 
TEST(UnitBaseTest,CanBeInititializedFromLargeInt)158 TEST(UnitBaseTest, CanBeInititializedFromLargeInt) {
159   const int kMaxInt = std::numeric_limits<int>::max();
160   EXPECT_EQ(TestUnit::FromKilo(kMaxInt).ToValue<int64_t>(),
161             static_cast<int64_t>(kMaxInt) * 1000);
162 }
163 
TEST(UnitBaseTest,ConvertsToAndFromDouble)164 TEST(UnitBaseTest, ConvertsToAndFromDouble) {
165   const int64_t kValue = 17017;
166   const double kMilliDouble = kValue * 1e3;
167   const double kValueDouble = kValue;
168   const double kKiloDouble = kValue * 1e-3;
169 
170   EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo<double>(), kKiloDouble);
171   EXPECT_EQ(TestUnit::FromKilo(kKiloDouble).ToValue<int64_t>(), kValue);
172 
173   EXPECT_EQ(TestUnit::FromValue(kValue).ToValue<double>(), kValueDouble);
174   EXPECT_EQ(TestUnit::FromValue(kValueDouble).ToValue<int64_t>(), kValue);
175 
176   EXPECT_NEAR(TestUnit::FromValue(kValue).ToMilli<double>(), kMilliDouble, 1);
177 
178   const double kPlusInfinity = std::numeric_limits<double>::infinity();
179   const double kMinusInfinity = -kPlusInfinity;
180 
181   EXPECT_EQ(TestUnit::PlusInfinity().ToKilo<double>(), kPlusInfinity);
182   EXPECT_EQ(TestUnit::MinusInfinity().ToKilo<double>(), kMinusInfinity);
183   EXPECT_EQ(TestUnit::PlusInfinity().ToValue<double>(), kPlusInfinity);
184   EXPECT_EQ(TestUnit::MinusInfinity().ToValue<double>(), kMinusInfinity);
185   EXPECT_EQ(TestUnit::PlusInfinity().ToMilli<double>(), kPlusInfinity);
186   EXPECT_EQ(TestUnit::MinusInfinity().ToMilli<double>(), kMinusInfinity);
187 
188   EXPECT_TRUE(TestUnit::FromKilo(kPlusInfinity).IsPlusInfinity());
189   EXPECT_TRUE(TestUnit::FromKilo(kMinusInfinity).IsMinusInfinity());
190   EXPECT_TRUE(TestUnit::FromValue(kPlusInfinity).IsPlusInfinity());
191   EXPECT_TRUE(TestUnit::FromValue(kMinusInfinity).IsMinusInfinity());
192 }
193 
TEST(UnitBaseTest,MathOperations)194 TEST(UnitBaseTest, MathOperations) {
195   const int64_t kValueA = 267;
196   const int64_t kValueB = 450;
197   const TestUnit delta_a = TestUnit::FromKilo(kValueA);
198   const TestUnit delta_b = TestUnit::FromKilo(kValueB);
199   EXPECT_EQ((delta_a + delta_b).ToKilo(), kValueA + kValueB);
200   EXPECT_EQ((delta_a - delta_b).ToKilo(), kValueA - kValueB);
201 
202   const int32_t kInt32Value = 123;
203   const double kFloatValue = 123.0;
204   EXPECT_EQ((TestUnit::FromValue(kValueA) * kValueB).ToValue<int64_t>(),
205             kValueA * kValueB);
206   EXPECT_EQ((TestUnit::FromValue(kValueA) * kInt32Value).ToValue<int64_t>(),
207             kValueA * kInt32Value);
208   EXPECT_EQ((TestUnit::FromValue(kValueA) * kFloatValue).ToValue<int64_t>(),
209             kValueA * kFloatValue);
210 
211   EXPECT_EQ((delta_b / 10).ToKilo(), kValueB / 10);
212   EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA);
213 
214   TestUnit mutable_delta = TestUnit::FromKilo(kValueA);
215   mutable_delta += TestUnit::FromKilo(kValueB);
216   EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA + kValueB));
217   mutable_delta -= TestUnit::FromKilo(kValueB);
218   EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA));
219 }
220 
TEST(UnitBaseTest,InfinityOperations)221 TEST(UnitBaseTest, InfinityOperations) {
222   const int64_t kValue = 267;
223   const TestUnit finite = TestUnit::FromKilo(kValue);
224   EXPECT_TRUE((TestUnit::PlusInfinity() + finite).IsPlusInfinity());
225   EXPECT_TRUE((TestUnit::PlusInfinity() - finite).IsPlusInfinity());
226   EXPECT_TRUE((finite + TestUnit::PlusInfinity()).IsPlusInfinity());
227   EXPECT_TRUE((finite - TestUnit::MinusInfinity()).IsPlusInfinity());
228 
229   EXPECT_TRUE((TestUnit::MinusInfinity() + finite).IsMinusInfinity());
230   EXPECT_TRUE((TestUnit::MinusInfinity() - finite).IsMinusInfinity());
231   EXPECT_TRUE((finite + TestUnit::MinusInfinity()).IsMinusInfinity());
232   EXPECT_TRUE((finite - TestUnit::PlusInfinity()).IsMinusInfinity());
233 }
234 }  // namespace test
235 }  // namespace webrtc
236