|  | /* | 
|  | *  Copyright (c) 2014 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 "system_wrappers/include/ntp_time.h" | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <cstdlib> | 
|  | #include <limits> | 
|  | #include <random> | 
|  |  | 
|  | #include "system_wrappers/include/clock.h" | 
|  | #include "test/gmock.h" | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  |  | 
|  | using testing::Lt; | 
|  |  | 
|  | constexpr uint32_t kNtpSec = 0x12345678; | 
|  | constexpr uint32_t kNtpFrac = 0x23456789; | 
|  |  | 
|  | constexpr int64_t kOneSecQ32x32 = uint64_t{1} << 32; | 
|  | constexpr int64_t kOneMsQ32x32 = 4294967; | 
|  |  | 
|  | TEST(NtpTimeTest, NoValueMeansInvalid) { | 
|  | NtpTime ntp; | 
|  | EXPECT_FALSE(ntp.Valid()); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, CanResetValue) { | 
|  | NtpTime ntp(kNtpSec, kNtpFrac); | 
|  | EXPECT_TRUE(ntp.Valid()); | 
|  | ntp.Reset(); | 
|  | EXPECT_FALSE(ntp.Valid()); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, CanGetWhatIsSet) { | 
|  | NtpTime ntp; | 
|  | ntp.Set(kNtpSec, kNtpFrac); | 
|  | EXPECT_EQ(kNtpSec, ntp.seconds()); | 
|  | EXPECT_EQ(kNtpFrac, ntp.fractions()); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, SetIsSameAs2ParameterConstructor) { | 
|  | NtpTime ntp1(kNtpSec, kNtpFrac); | 
|  | NtpTime ntp2; | 
|  | EXPECT_NE(ntp1, ntp2); | 
|  |  | 
|  | ntp2.Set(kNtpSec, kNtpFrac); | 
|  | EXPECT_EQ(ntp1, ntp2); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, ToMsMeansToNtpMilliseconds) { | 
|  | SimulatedClock clock(0x123456789abc); | 
|  |  | 
|  | NtpTime ntp = clock.CurrentNtpTime(); | 
|  | EXPECT_EQ(ntp.ToMs(), clock.CurrentNtpInMilliseconds()); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, CanExplicitlyConvertToAndFromUint64) { | 
|  | uint64_t untyped_time = 0x123456789; | 
|  | NtpTime time(untyped_time); | 
|  | EXPECT_EQ(untyped_time, static_cast<uint64_t>(time)); | 
|  | EXPECT_EQ(NtpTime(0x12345678, 0x90abcdef), NtpTime(0x1234567890abcdef)); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearZero) { | 
|  | // Zero | 
|  | EXPECT_EQ(Int64MsToQ32x32(0), 0); | 
|  |  | 
|  | // Zero + 1 millisecond | 
|  | EXPECT_EQ(Int64MsToQ32x32(1), kOneMsQ32x32); | 
|  |  | 
|  | // Zero - 1 millisecond | 
|  | EXPECT_EQ(Int64MsToQ32x32(-1), -kOneMsQ32x32); | 
|  |  | 
|  | // Zero + 1 second | 
|  | EXPECT_EQ(Int64MsToQ32x32(1000), kOneSecQ32x32); | 
|  |  | 
|  | // Zero - 1 second | 
|  | EXPECT_EQ(Int64MsToQ32x32(-1000), -kOneSecQ32x32); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearZero) { | 
|  | // Zero | 
|  | EXPECT_EQ(Int64MsToUQ32x32(0), uint64_t{0}); | 
|  |  | 
|  | // Zero + 1 millisecond | 
|  | EXPECT_EQ(Int64MsToUQ32x32(1), uint64_t{kOneMsQ32x32}); | 
|  |  | 
|  | // Zero - 1 millisecond | 
|  | EXPECT_EQ(Int64MsToUQ32x32(-1), uint64_t{0});  // Clamped | 
|  |  | 
|  | // Zero + 1 second | 
|  | EXPECT_EQ(Int64MsToUQ32x32(1000), uint64_t{kOneSecQ32x32}); | 
|  |  | 
|  | // Zero - 1 second | 
|  | EXPECT_EQ(Int64MsToUQ32x32(-1000), uint64_t{0});  // Clamped | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearZero) { | 
|  | // Zero | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(0), 0); | 
|  |  | 
|  | // Zero + 1 millisecond | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kOneMsQ32x32), 1); | 
|  |  | 
|  | // Zero - 1 millisecond | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(-kOneMsQ32x32), -1); | 
|  |  | 
|  | // Zero + 1 second | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kOneSecQ32x32), 1000); | 
|  |  | 
|  | // Zero - 1 second | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(-kOneSecQ32x32), -1000); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearZero) { | 
|  | // Zero | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(0), 0); | 
|  |  | 
|  | // Zero + 1 millisecond | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(kOneMsQ32x32), 1); | 
|  |  | 
|  | // Zero + 1 second | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(kOneSecQ32x32), 1000); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMax) { | 
|  | constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max(); | 
|  | constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 999; | 
|  |  | 
|  | // Max | 
|  | const int64_t boundary_q32x32 = Int64MsToQ32x32(kBoundaryMs); | 
|  | EXPECT_LE(boundary_q32x32, kMaxQ32x32); | 
|  | EXPECT_GT(boundary_q32x32, kMaxQ32x32 - kOneMsQ32x32); | 
|  |  | 
|  | // Max + 1 millisecond | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1), kMaxQ32x32);  // Clamped | 
|  |  | 
|  | // Max - 1 millisecond | 
|  | EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1), kMaxQ32x32 - kOneMsQ32x32); | 
|  |  | 
|  | // Max + 1 second | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000), kMaxQ32x32);  // Clamped | 
|  |  | 
|  | // Max - 1 second | 
|  | EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1000), kMaxQ32x32 - kOneSecQ32x32); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearMax) { | 
|  | constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max(); | 
|  | constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 999; | 
|  |  | 
|  | // Max | 
|  | const uint64_t boundary_uq32x32 = Int64MsToUQ32x32(kBoundaryMs); | 
|  | EXPECT_LE(boundary_uq32x32, kMaxUQ32x32); | 
|  | EXPECT_GT(boundary_uq32x32, kMaxUQ32x32 - kOneMsQ32x32); | 
|  |  | 
|  | // Max + 1 millisecond | 
|  | EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1), kMaxUQ32x32);  // Clamped | 
|  |  | 
|  | // Max - 1 millisecond | 
|  | EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1), kMaxUQ32x32 - kOneMsQ32x32); | 
|  |  | 
|  | // Max + 1 second | 
|  | EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1000), kMaxUQ32x32);  // Clamped | 
|  |  | 
|  | // Max - 1 second | 
|  | EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1000), kMaxUQ32x32 - kOneSecQ32x32); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMax) { | 
|  | constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max(); | 
|  | constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 1000; | 
|  |  | 
|  | // Max | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32), kBoundaryMs); | 
|  |  | 
|  | // Max - 1 millisecond | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneMsQ32x32), kBoundaryMs - 1); | 
|  |  | 
|  | // Max - 1 second | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearMax) { | 
|  | constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max(); | 
|  | constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 1000; | 
|  |  | 
|  | // Max | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32), kBoundaryMs); | 
|  |  | 
|  | // Max - 1 millisecond | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneMsQ32x32), kBoundaryMs - 1); | 
|  |  | 
|  | // Max - 1 second | 
|  | EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMin) { | 
|  | constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000; | 
|  | constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000; | 
|  |  | 
|  | // Min | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs), kBoundaryQ32x32); | 
|  |  | 
|  | // Min + 1 millisecond | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(Int64MsToQ32x32(kBoundaryMs + 1)), kBoundaryMs + 1); | 
|  |  | 
|  | // Min - 1 millisecond | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1), kBoundaryQ32x32);  // Clamped | 
|  |  | 
|  | // Min + 1 second | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000), | 
|  | kBoundaryQ32x32 + kOneSecQ32x32); | 
|  |  | 
|  | // Min - 1 second | 
|  | EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1000), kBoundaryQ32x32);  // Clamped | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMin) { | 
|  | constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000; | 
|  | constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000; | 
|  |  | 
|  | // Min | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32), kBoundaryMs); | 
|  |  | 
|  | // Min + 1 millisecond | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneMsQ32x32), kBoundaryMs + 1); | 
|  |  | 
|  | // Min + 1 second | 
|  | EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneSecQ32x32), | 
|  | kBoundaryMs + 1000); | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToQ32x32RoundTrip) { | 
|  | constexpr int kIterations = 50000; | 
|  |  | 
|  | std::mt19937 generator(123456789); | 
|  | std::uniform_int_distribution<int64_t> distribution( | 
|  | Q32x32ToInt64Ms(std::numeric_limits<int64_t>::min()), | 
|  | Q32x32ToInt64Ms(std::numeric_limits<int64_t>::max())); | 
|  |  | 
|  | for (int iteration = 0; iteration < kIterations; ++iteration) { | 
|  | int64_t input_ms = distribution(generator); | 
|  | int64_t transit_q32x32 = Int64MsToQ32x32(input_ms); | 
|  | int64_t output_ms = Q32x32ToInt64Ms(transit_q32x32); | 
|  |  | 
|  | ASSERT_EQ(input_ms, output_ms) | 
|  | << "iteration = " << iteration << ", input_ms = " << input_ms | 
|  | << ", transit_q32x32 = " << transit_q32x32 | 
|  | << ", output_ms = " << output_ms; | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToUQ32x32RoundTrip) { | 
|  | constexpr int kIterations = 50000; | 
|  |  | 
|  | std::mt19937 generator(123456789); | 
|  | std::uniform_int_distribution<uint64_t> distribution( | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::min()), | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::max())); | 
|  |  | 
|  | for (int iteration = 0; iteration < kIterations; ++iteration) { | 
|  | uint64_t input_ms = distribution(generator); | 
|  | uint64_t transit_uq32x32 = Int64MsToUQ32x32(input_ms); | 
|  | uint64_t output_ms = UQ32x32ToInt64Ms(transit_uq32x32); | 
|  |  | 
|  | ASSERT_EQ(input_ms, output_ms) | 
|  | << "iteration = " << iteration << ", input_ms = " << input_ms | 
|  | << ", transit_uq32x32 = " << transit_uq32x32 | 
|  | << ", output_ms = " << output_ms; | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifyInt64MsToUQ32x32UsRoundTrip) { | 
|  | constexpr int kIterations = 50000; | 
|  |  | 
|  | std::mt19937 generator(123456789); | 
|  | std::uniform_int_distribution<uint64_t> distribution( | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::min()), | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::max())); | 
|  |  | 
|  | for (int iteration = 0; iteration < kIterations; ++iteration) { | 
|  | uint64_t input_ms = distribution(generator); | 
|  | uint64_t transit_uq32x32 = Int64MsToUQ32x32(input_ms); | 
|  | uint64_t output_ms = UQ32x32ToInt64Us(transit_uq32x32); | 
|  |  | 
|  | int64_t difference = input_ms * 1000 - output_ms; | 
|  | ASSERT_THAT(abs(difference), Lt(2)) | 
|  | << "iteration = " << iteration << ", input_ms = " << input_ms | 
|  | << ", transit_uq32x32 = " << transit_uq32x32 | 
|  | << ", output_us = " << output_ms; | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(NtpTimeTest, VerifySignedInt64MsToUQ32x32UsRoundTrip) { | 
|  | constexpr int kIterations = 50000; | 
|  |  | 
|  | std::mt19937 generator(123456789); | 
|  | std::uniform_int_distribution<int64_t> distribution( | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<int64_t>::min()), | 
|  | UQ32x32ToInt64Ms(std::numeric_limits<int64_t>::max())); | 
|  |  | 
|  | for (int iteration = 0; iteration < kIterations; ++iteration) { | 
|  | int64_t input_ms = distribution(generator); | 
|  | uint64_t transit_uq32x32 = Int64MsToUQ32x32(input_ms); | 
|  | int64_t output_ms = UQ32x32ToInt64Us(transit_uq32x32); | 
|  |  | 
|  | int64_t difference = input_ms * 1000 - output_ms; | 
|  | ASSERT_THAT(abs(difference), Lt(2)) | 
|  | << "iteration = " << iteration << ", input_ms = " << input_ms | 
|  | << ", transit_uq32x32 = " << transit_uq32x32 | 
|  | << ", output_us = " << output_ms; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace webrtc |