1 /*
2 * Copyright (c) 2014 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 "system_wrappers/include/ntp_time.h"
12
13 #include <random>
14
15 #include "system_wrappers/include/clock.h"
16 #include "test/gtest.h"
17
18 namespace webrtc {
19 namespace {
20
21 constexpr uint32_t kNtpSec = 0x12345678;
22 constexpr uint32_t kNtpFrac = 0x23456789;
23
24 constexpr int64_t kOneSecQ32x32 = uint64_t{1} << 32;
25 constexpr int64_t kOneMsQ32x32 = 4294967;
26
TEST(NtpTimeTest,NoValueMeansInvalid)27 TEST(NtpTimeTest, NoValueMeansInvalid) {
28 NtpTime ntp;
29 EXPECT_FALSE(ntp.Valid());
30 }
31
TEST(NtpTimeTest,CanResetValue)32 TEST(NtpTimeTest, CanResetValue) {
33 NtpTime ntp(kNtpSec, kNtpFrac);
34 EXPECT_TRUE(ntp.Valid());
35 ntp.Reset();
36 EXPECT_FALSE(ntp.Valid());
37 }
38
TEST(NtpTimeTest,CanGetWhatIsSet)39 TEST(NtpTimeTest, CanGetWhatIsSet) {
40 NtpTime ntp;
41 ntp.Set(kNtpSec, kNtpFrac);
42 EXPECT_EQ(kNtpSec, ntp.seconds());
43 EXPECT_EQ(kNtpFrac, ntp.fractions());
44 }
45
TEST(NtpTimeTest,SetIsSameAs2ParameterConstructor)46 TEST(NtpTimeTest, SetIsSameAs2ParameterConstructor) {
47 NtpTime ntp1(kNtpSec, kNtpFrac);
48 NtpTime ntp2;
49 EXPECT_NE(ntp1, ntp2);
50
51 ntp2.Set(kNtpSec, kNtpFrac);
52 EXPECT_EQ(ntp1, ntp2);
53 }
54
TEST(NtpTimeTest,ToMsMeansToNtpMilliseconds)55 TEST(NtpTimeTest, ToMsMeansToNtpMilliseconds) {
56 SimulatedClock clock(0x123456789abc);
57
58 NtpTime ntp = clock.CurrentNtpTime();
59 EXPECT_EQ(ntp.ToMs(), Clock::NtpToMs(ntp.seconds(), ntp.fractions()));
60 EXPECT_EQ(ntp.ToMs(), clock.CurrentNtpInMilliseconds());
61 }
62
TEST(NtpTimeTest,CanExplicitlyConvertToAndFromUint64)63 TEST(NtpTimeTest, CanExplicitlyConvertToAndFromUint64) {
64 uint64_t untyped_time = 0x123456789;
65 NtpTime time(untyped_time);
66 EXPECT_EQ(untyped_time, static_cast<uint64_t>(time));
67 EXPECT_EQ(NtpTime(0x12345678, 0x90abcdef), NtpTime(0x1234567890abcdef));
68 }
69
TEST(NtpTimeTest,VerifyInt64MsToQ32x32NearZero)70 TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearZero) {
71 // Zero
72 EXPECT_EQ(Int64MsToQ32x32(0), 0);
73
74 // Zero + 1 millisecond
75 EXPECT_EQ(Int64MsToQ32x32(1), kOneMsQ32x32);
76
77 // Zero - 1 millisecond
78 EXPECT_EQ(Int64MsToQ32x32(-1), -kOneMsQ32x32);
79
80 // Zero + 1 second
81 EXPECT_EQ(Int64MsToQ32x32(1000), kOneSecQ32x32);
82
83 // Zero - 1 second
84 EXPECT_EQ(Int64MsToQ32x32(-1000), -kOneSecQ32x32);
85 }
86
TEST(NtpTimeTest,VerifyInt64MsToUQ32x32NearZero)87 TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearZero) {
88 // Zero
89 EXPECT_EQ(Int64MsToUQ32x32(0), uint64_t{0});
90
91 // Zero + 1 millisecond
92 EXPECT_EQ(Int64MsToUQ32x32(1), uint64_t{kOneMsQ32x32});
93
94 // Zero - 1 millisecond
95 EXPECT_EQ(Int64MsToUQ32x32(-1), uint64_t{0}); // Clamped
96
97 // Zero + 1 second
98 EXPECT_EQ(Int64MsToUQ32x32(1000), uint64_t{kOneSecQ32x32});
99
100 // Zero - 1 second
101 EXPECT_EQ(Int64MsToUQ32x32(-1000), uint64_t{0}); // Clamped
102 }
103
TEST(NtpTimeTest,VerifyQ32x32ToInt64MsNearZero)104 TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearZero) {
105 // Zero
106 EXPECT_EQ(Q32x32ToInt64Ms(0), 0);
107
108 // Zero + 1 millisecond
109 EXPECT_EQ(Q32x32ToInt64Ms(kOneMsQ32x32), 1);
110
111 // Zero - 1 millisecond
112 EXPECT_EQ(Q32x32ToInt64Ms(-kOneMsQ32x32), -1);
113
114 // Zero + 1 second
115 EXPECT_EQ(Q32x32ToInt64Ms(kOneSecQ32x32), 1000);
116
117 // Zero - 1 second
118 EXPECT_EQ(Q32x32ToInt64Ms(-kOneSecQ32x32), -1000);
119 }
120
TEST(NtpTimeTest,VerifyUQ32x32ToInt64MsNearZero)121 TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearZero) {
122 // Zero
123 EXPECT_EQ(UQ32x32ToInt64Ms(0), 0);
124
125 // Zero + 1 millisecond
126 EXPECT_EQ(UQ32x32ToInt64Ms(kOneMsQ32x32), 1);
127
128 // Zero + 1 second
129 EXPECT_EQ(UQ32x32ToInt64Ms(kOneSecQ32x32), 1000);
130 }
131
TEST(NtpTimeTest,VerifyInt64MsToQ32x32NearMax)132 TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMax) {
133 constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max();
134 constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 999;
135
136 // Max
137 const int64_t boundary_q32x32 = Int64MsToQ32x32(kBoundaryMs);
138 EXPECT_LE(boundary_q32x32, kMaxQ32x32);
139 EXPECT_GT(boundary_q32x32, kMaxQ32x32 - kOneMsQ32x32);
140
141 // Max + 1 millisecond
142 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1), kMaxQ32x32); // Clamped
143
144 // Max - 1 millisecond
145 EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1), kMaxQ32x32 - kOneMsQ32x32);
146
147 // Max + 1 second
148 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000), kMaxQ32x32); // Clamped
149
150 // Max - 1 second
151 EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1000), kMaxQ32x32 - kOneSecQ32x32);
152 }
153
TEST(NtpTimeTest,VerifyInt64MsToUQ32x32NearMax)154 TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearMax) {
155 constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max();
156 constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 999;
157
158 // Max
159 const uint64_t boundary_uq32x32 = Int64MsToUQ32x32(kBoundaryMs);
160 EXPECT_LE(boundary_uq32x32, kMaxUQ32x32);
161 EXPECT_GT(boundary_uq32x32, kMaxUQ32x32 - kOneMsQ32x32);
162
163 // Max + 1 millisecond
164 EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1), kMaxUQ32x32); // Clamped
165
166 // Max - 1 millisecond
167 EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1), kMaxUQ32x32 - kOneMsQ32x32);
168
169 // Max + 1 second
170 EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1000), kMaxUQ32x32); // Clamped
171
172 // Max - 1 second
173 EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1000), kMaxUQ32x32 - kOneSecQ32x32);
174 }
175
TEST(NtpTimeTest,VerifyQ32x32ToInt64MsNearMax)176 TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMax) {
177 constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max();
178 constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 1000;
179
180 // Max
181 EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32), kBoundaryMs);
182
183 // Max - 1 millisecond
184 EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneMsQ32x32), kBoundaryMs - 1);
185
186 // Max - 1 second
187 EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000);
188 }
189
TEST(NtpTimeTest,VerifyUQ32x32ToInt64MsNearMax)190 TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearMax) {
191 constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max();
192 constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 1000;
193
194 // Max
195 EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32), kBoundaryMs);
196
197 // Max - 1 millisecond
198 EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneMsQ32x32), kBoundaryMs - 1);
199
200 // Max - 1 second
201 EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000);
202 }
203
TEST(NtpTimeTest,VerifyInt64MsToQ32x32NearMin)204 TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMin) {
205 constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000;
206 constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000;
207
208 // Min
209 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs), kBoundaryQ32x32);
210
211 // Min + 1 millisecond
212 EXPECT_EQ(Q32x32ToInt64Ms(Int64MsToQ32x32(kBoundaryMs + 1)), kBoundaryMs + 1);
213
214 // Min - 1 millisecond
215 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1), kBoundaryQ32x32); // Clamped
216
217 // Min + 1 second
218 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000),
219 kBoundaryQ32x32 + kOneSecQ32x32);
220
221 // Min - 1 second
222 EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1000), kBoundaryQ32x32); // Clamped
223 }
224
TEST(NtpTimeTest,VerifyQ32x32ToInt64MsNearMin)225 TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMin) {
226 constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000;
227 constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000;
228
229 // Min
230 EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32), kBoundaryMs);
231
232 // Min + 1 millisecond
233 EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneMsQ32x32), kBoundaryMs + 1);
234
235 // Min + 1 second
236 EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneSecQ32x32),
237 kBoundaryMs + 1000);
238 }
239
TEST(NtpTimeTest,VerifyInt64MsToQ32x32RoundTrip)240 TEST(NtpTimeTest, VerifyInt64MsToQ32x32RoundTrip) {
241 constexpr int kIterations = 50000;
242
243 std::mt19937 generator(123456789);
244 std::uniform_int_distribution<int64_t> distribution(
245 Q32x32ToInt64Ms(std::numeric_limits<int64_t>::min()),
246 Q32x32ToInt64Ms(std::numeric_limits<int64_t>::max()));
247
248 for (int iteration = 0; iteration < kIterations; ++iteration) {
249 int64_t input_ms = distribution(generator);
250 int64_t transit_q32x32 = Int64MsToQ32x32(input_ms);
251 int64_t output_ms = Q32x32ToInt64Ms(transit_q32x32);
252
253 ASSERT_EQ(input_ms, output_ms)
254 << "iteration = " << iteration << ", input_ms = " << input_ms
255 << ", transit_q32x32 = " << transit_q32x32
256 << ", output_ms = " << output_ms;
257 }
258 }
259
TEST(NtpTimeTest,VerifyInt64MsToUQ32x32RoundTrip)260 TEST(NtpTimeTest, VerifyInt64MsToUQ32x32RoundTrip) {
261 constexpr int kIterations = 50000;
262
263 std::mt19937 generator(123456789);
264 std::uniform_int_distribution<uint64_t> distribution(
265 UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::min()),
266 UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::max()));
267
268 for (int iteration = 0; iteration < kIterations; ++iteration) {
269 uint64_t input_ms = distribution(generator);
270 uint64_t transit_uq32x32 = Int64MsToUQ32x32(input_ms);
271 uint64_t output_ms = UQ32x32ToInt64Ms(transit_uq32x32);
272
273 ASSERT_EQ(input_ms, output_ms)
274 << "iteration = " << iteration << ", input_ms = " << input_ms
275 << ", transit_uq32x32 = " << transit_uq32x32
276 << ", output_ms = " << output_ms;
277 }
278 }
279
280 } // namespace
281 } // namespace webrtc
282