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 static_assert(TestUnit::FromValue(500) / 2 == TestUnit::FromValue(250));
72 }
73
TEST(UnitBaseTest,GetBackSameValues)74 TEST(UnitBaseTest, GetBackSameValues) {
75 const int64_t kValue = 499;
76 for (int sign = -1; sign <= 1; ++sign) {
77 int64_t value = kValue * sign;
78 EXPECT_EQ(TestUnit::FromKilo(value).ToKilo(), value);
79 EXPECT_EQ(TestUnit::FromValue(value).ToValue<int64_t>(), value);
80 }
81 EXPECT_EQ(TestUnit::Zero().ToValue<int64_t>(), 0);
82 }
83
TEST(UnitBaseTest,GetDifferentPrefix)84 TEST(UnitBaseTest, GetDifferentPrefix) {
85 const int64_t kValue = 3000000;
86 EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo(), kValue / 1000);
87 EXPECT_EQ(TestUnit::FromKilo(kValue).ToValue<int64_t>(), kValue * 1000);
88 }
89
TEST(UnitBaseTest,IdentityChecks)90 TEST(UnitBaseTest, IdentityChecks) {
91 const int64_t kValue = 3000;
92 EXPECT_TRUE(TestUnit::Zero().IsZero());
93 EXPECT_FALSE(TestUnit::FromKilo(kValue).IsZero());
94
95 EXPECT_TRUE(TestUnit::PlusInfinity().IsInfinite());
96 EXPECT_TRUE(TestUnit::MinusInfinity().IsInfinite());
97 EXPECT_FALSE(TestUnit::Zero().IsInfinite());
98 EXPECT_FALSE(TestUnit::FromKilo(-kValue).IsInfinite());
99 EXPECT_FALSE(TestUnit::FromKilo(kValue).IsInfinite());
100
101 EXPECT_FALSE(TestUnit::PlusInfinity().IsFinite());
102 EXPECT_FALSE(TestUnit::MinusInfinity().IsFinite());
103 EXPECT_TRUE(TestUnit::FromKilo(-kValue).IsFinite());
104 EXPECT_TRUE(TestUnit::FromKilo(kValue).IsFinite());
105 EXPECT_TRUE(TestUnit::Zero().IsFinite());
106
107 EXPECT_TRUE(TestUnit::PlusInfinity().IsPlusInfinity());
108 EXPECT_FALSE(TestUnit::MinusInfinity().IsPlusInfinity());
109
110 EXPECT_TRUE(TestUnit::MinusInfinity().IsMinusInfinity());
111 EXPECT_FALSE(TestUnit::PlusInfinity().IsMinusInfinity());
112 }
113
TEST(UnitBaseTest,ComparisonOperators)114 TEST(UnitBaseTest, ComparisonOperators) {
115 const int64_t kSmall = 450;
116 const int64_t kLarge = 451;
117 const TestUnit small = TestUnit::FromKilo(kSmall);
118 const TestUnit large = TestUnit::FromKilo(kLarge);
119
120 EXPECT_EQ(TestUnit::Zero(), TestUnit::FromKilo(0));
121 EXPECT_EQ(TestUnit::PlusInfinity(), TestUnit::PlusInfinity());
122 EXPECT_EQ(small, TestUnit::FromKilo(kSmall));
123 EXPECT_LE(small, TestUnit::FromKilo(kSmall));
124 EXPECT_GE(small, TestUnit::FromKilo(kSmall));
125 EXPECT_NE(small, TestUnit::FromKilo(kLarge));
126 EXPECT_LE(small, TestUnit::FromKilo(kLarge));
127 EXPECT_LT(small, TestUnit::FromKilo(kLarge));
128 EXPECT_GE(large, TestUnit::FromKilo(kSmall));
129 EXPECT_GT(large, TestUnit::FromKilo(kSmall));
130 EXPECT_LT(TestUnit::Zero(), small);
131 EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall));
132 EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall));
133
134 EXPECT_GT(TestUnit::PlusInfinity(), large);
135 EXPECT_LT(TestUnit::MinusInfinity(), TestUnit::Zero());
136 }
137
TEST(UnitBaseTest,Clamping)138 TEST(UnitBaseTest, Clamping) {
139 const TestUnit upper = TestUnit::FromKilo(800);
140 const TestUnit lower = TestUnit::FromKilo(100);
141 const TestUnit under = TestUnit::FromKilo(100);
142 const TestUnit inside = TestUnit::FromKilo(500);
143 const TestUnit over = TestUnit::FromKilo(1000);
144 EXPECT_EQ(under.Clamped(lower, upper), lower);
145 EXPECT_EQ(inside.Clamped(lower, upper), inside);
146 EXPECT_EQ(over.Clamped(lower, upper), upper);
147
148 TestUnit mutable_delta = lower;
149 mutable_delta.Clamp(lower, upper);
150 EXPECT_EQ(mutable_delta, lower);
151 mutable_delta = inside;
152 mutable_delta.Clamp(lower, upper);
153 EXPECT_EQ(mutable_delta, inside);
154 mutable_delta = over;
155 mutable_delta.Clamp(lower, upper);
156 EXPECT_EQ(mutable_delta, upper);
157 }
158
TEST(UnitBaseTest,CanBeInititializedFromLargeInt)159 TEST(UnitBaseTest, CanBeInititializedFromLargeInt) {
160 const int kMaxInt = std::numeric_limits<int>::max();
161 EXPECT_EQ(TestUnit::FromKilo(kMaxInt).ToValue<int64_t>(),
162 static_cast<int64_t>(kMaxInt) * 1000);
163 }
164
TEST(UnitBaseTest,ConvertsToAndFromDouble)165 TEST(UnitBaseTest, ConvertsToAndFromDouble) {
166 const int64_t kValue = 17017;
167 const double kMilliDouble = kValue * 1e3;
168 const double kValueDouble = kValue;
169 const double kKiloDouble = kValue * 1e-3;
170
171 EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo<double>(), kKiloDouble);
172 EXPECT_EQ(TestUnit::FromKilo(kKiloDouble).ToValue<int64_t>(), kValue);
173
174 EXPECT_EQ(TestUnit::FromValue(kValue).ToValue<double>(), kValueDouble);
175 EXPECT_EQ(TestUnit::FromValue(kValueDouble).ToValue<int64_t>(), kValue);
176
177 EXPECT_NEAR(TestUnit::FromValue(kValue).ToMilli<double>(), kMilliDouble, 1);
178
179 const double kPlusInfinity = std::numeric_limits<double>::infinity();
180 const double kMinusInfinity = -kPlusInfinity;
181
182 EXPECT_EQ(TestUnit::PlusInfinity().ToKilo<double>(), kPlusInfinity);
183 EXPECT_EQ(TestUnit::MinusInfinity().ToKilo<double>(), kMinusInfinity);
184 EXPECT_EQ(TestUnit::PlusInfinity().ToValue<double>(), kPlusInfinity);
185 EXPECT_EQ(TestUnit::MinusInfinity().ToValue<double>(), kMinusInfinity);
186 EXPECT_EQ(TestUnit::PlusInfinity().ToMilli<double>(), kPlusInfinity);
187 EXPECT_EQ(TestUnit::MinusInfinity().ToMilli<double>(), kMinusInfinity);
188
189 EXPECT_TRUE(TestUnit::FromKilo(kPlusInfinity).IsPlusInfinity());
190 EXPECT_TRUE(TestUnit::FromKilo(kMinusInfinity).IsMinusInfinity());
191 EXPECT_TRUE(TestUnit::FromValue(kPlusInfinity).IsPlusInfinity());
192 EXPECT_TRUE(TestUnit::FromValue(kMinusInfinity).IsMinusInfinity());
193 }
194
TEST(UnitBaseTest,MathOperations)195 TEST(UnitBaseTest, MathOperations) {
196 const int64_t kValueA = 267;
197 const int64_t kValueB = 450;
198 const TestUnit delta_a = TestUnit::FromKilo(kValueA);
199 const TestUnit delta_b = TestUnit::FromKilo(kValueB);
200 EXPECT_EQ((delta_a + delta_b).ToKilo(), kValueA + kValueB);
201 EXPECT_EQ((delta_a - delta_b).ToKilo(), kValueA - kValueB);
202
203 const int32_t kInt32Value = 123;
204 const double kFloatValue = 123.0;
205 EXPECT_EQ((TestUnit::FromValue(kValueA) * kValueB).ToValue<int64_t>(),
206 kValueA * kValueB);
207 EXPECT_EQ((TestUnit::FromValue(kValueA) * kInt32Value).ToValue<int64_t>(),
208 kValueA * kInt32Value);
209 EXPECT_EQ((TestUnit::FromValue(kValueA) * kFloatValue).ToValue<int64_t>(),
210 kValueA * kFloatValue);
211
212 EXPECT_EQ((delta_b / 10).ToKilo(), kValueB / 10);
213 EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA);
214
215 TestUnit mutable_delta = TestUnit::FromKilo(kValueA);
216 mutable_delta += TestUnit::FromKilo(kValueB);
217 EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA + kValueB));
218 mutable_delta -= TestUnit::FromKilo(kValueB);
219 EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA));
220
221 // Division by an int rounds towards zero to follow regular int division.
222 EXPECT_EQ(TestUnit::FromValue(789) / 10, TestUnit::FromValue(78));
223 EXPECT_EQ(TestUnit::FromValue(-789) / 10, TestUnit::FromValue(-78));
224 }
225
TEST(UnitBaseTest,InfinityOperations)226 TEST(UnitBaseTest, InfinityOperations) {
227 const int64_t kValue = 267;
228 const TestUnit finite = TestUnit::FromKilo(kValue);
229 EXPECT_TRUE((TestUnit::PlusInfinity() + finite).IsPlusInfinity());
230 EXPECT_TRUE((TestUnit::PlusInfinity() - finite).IsPlusInfinity());
231 EXPECT_TRUE((finite + TestUnit::PlusInfinity()).IsPlusInfinity());
232 EXPECT_TRUE((finite - TestUnit::MinusInfinity()).IsPlusInfinity());
233
234 EXPECT_TRUE((TestUnit::MinusInfinity() + finite).IsMinusInfinity());
235 EXPECT_TRUE((TestUnit::MinusInfinity() - finite).IsMinusInfinity());
236 EXPECT_TRUE((finite + TestUnit::MinusInfinity()).IsMinusInfinity());
237 EXPECT_TRUE((finite - TestUnit::PlusInfinity()).IsMinusInfinity());
238 }
239
TEST(UnitBaseTest,UnaryMinus)240 TEST(UnitBaseTest, UnaryMinus) {
241 const int64_t kValue = 1337;
242 const TestUnit unit = TestUnit::FromValue(kValue);
243 EXPECT_EQ(-unit.ToValue(), -kValue);
244
245 // Check infinity.
246 EXPECT_EQ(-TestUnit::PlusInfinity(), TestUnit::MinusInfinity());
247 EXPECT_EQ(-TestUnit::MinusInfinity(), TestUnit::PlusInfinity());
248 }
249
250 } // namespace test
251 } // namespace webrtc
252