xref: /aosp_15_r20/external/cronet/base/time/time_apple_unittest.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker// Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker// found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker#include "base/time/time.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker#include "base/test/gtest_util.h"
8*6777b538SAndroid Build Coastguard Worker#include "testing/gtest/include/gtest/gtest.h"
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Workernamespace {
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Workerclass ScopedTimebase {
13*6777b538SAndroid Build Coastguard Worker public:
14*6777b538SAndroid Build Coastguard Worker  explicit ScopedTimebase(mach_timebase_info_data_t timebase) {
15*6777b538SAndroid Build Coastguard Worker    orig_timebase_ = base::TimeTicks::SetMachTimebaseInfoForTesting(timebase);
16*6777b538SAndroid Build Coastguard Worker  }
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker  ScopedTimebase(const ScopedTimebase&) = delete;
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker  ScopedTimebase& operator=(const ScopedTimebase&) = delete;
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker  ~ScopedTimebase() {
23*6777b538SAndroid Build Coastguard Worker    base::TimeTicks::SetMachTimebaseInfoForTesting(orig_timebase_);
24*6777b538SAndroid Build Coastguard Worker  }
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard Worker private:
27*6777b538SAndroid Build Coastguard Worker  mach_timebase_info_data_t orig_timebase_;
28*6777b538SAndroid Build Coastguard Worker};
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Workermach_timebase_info_data_t kIntelTimebase = {1, 1};
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker// A sample (not definitive) timebase for M1.
33*6777b538SAndroid Build Coastguard Workermach_timebase_info_data_t kM1Timebase = {125, 3};
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker}  // namespace
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Workernamespace base {
38*6777b538SAndroid Build Coastguard Workernamespace {
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Workerbase::Time NoonOnDate(int year, int month, int day) {
41*6777b538SAndroid Build Coastguard Worker  const base::Time::Exploded exploded = {
42*6777b538SAndroid Build Coastguard Worker      .year = year, .month = month, .day_of_month = day, .hour = 12};
43*6777b538SAndroid Build Coastguard Worker  base::Time imploded;
44*6777b538SAndroid Build Coastguard Worker  CHECK(base::Time::FromUTCExploded(exploded, &imploded));
45*6777b538SAndroid Build Coastguard Worker  return imploded;
46*6777b538SAndroid Build Coastguard Worker}
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Workervoid CheckRoundTrip(int y, int m, int d) {
49*6777b538SAndroid Build Coastguard Worker  base::Time original = NoonOnDate(y, m, d);
50*6777b538SAndroid Build Coastguard Worker  base::Time roundtrip = Time::FromNSDate(original.ToNSDate());
51*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(original, roundtrip);
52*6777b538SAndroid Build Coastguard Worker}
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, RoundTripNSDate) {
55*6777b538SAndroid Build Coastguard Worker  CheckRoundTrip(1911, 12, 14);
56*6777b538SAndroid Build Coastguard Worker  CheckRoundTrip(1924, 9, 28);
57*6777b538SAndroid Build Coastguard Worker  CheckRoundTrip(1926, 5, 12);
58*6777b538SAndroid Build Coastguard Worker  CheckRoundTrip(1969, 7, 24);
59*6777b538SAndroid Build Coastguard Worker}
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsIntelTimebase) {
62*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kIntelTimebase);
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker  // Perform the conversion.
65*6777b538SAndroid Build Coastguard Worker  uint64_t kArbitraryTicks = 59090101000;
66*6777b538SAndroid Build Coastguard Worker  TimeDelta result = TimeDelta::FromMachTime(kArbitraryTicks);
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker  // With Intel the output should be the input.
69*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(Nanoseconds(kArbitraryTicks), result);
70*6777b538SAndroid Build Coastguard Worker}
71*6777b538SAndroid Build Coastguard Worker
72*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsM1Timebase) {
73*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kM1Timebase);
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker  // Use a tick count that's divisible by 3.
76*6777b538SAndroid Build Coastguard Worker  const uint64_t kArbitraryTicks = 92738127000;
77*6777b538SAndroid Build Coastguard Worker  TimeDelta result = TimeDelta::FromMachTime(kArbitraryTicks);
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker  const uint64_t kExpectedResult =
80*6777b538SAndroid Build Coastguard Worker      kArbitraryTicks * kM1Timebase.numer / kM1Timebase.denom;
81*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(Nanoseconds(kExpectedResult), result);
82*6777b538SAndroid Build Coastguard Worker}
83*6777b538SAndroid Build Coastguard Worker
84*6777b538SAndroid Build Coastguard Worker// Tests MachTimeToMicroseconds when
85*6777b538SAndroid Build Coastguard Worker// mach_timebase_info_data_t.numer and mach_timebase_info_data_t.denom
86*6777b538SAndroid Build Coastguard Worker// are equal.
87*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsEqualTimebaseMembers) {
88*6777b538SAndroid Build Coastguard Worker  // These members would produce overflow but don't because
89*6777b538SAndroid Build Coastguard Worker  // MachTimeToMicroseconds should skip the timebase conversion
90*6777b538SAndroid Build Coastguard Worker  // when they're equal.
91*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase({UINT_MAX, UINT_MAX});
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker  uint64_t kArbitraryTicks = 175920053729;
94*6777b538SAndroid Build Coastguard Worker  TimeDelta result = TimeDelta::FromMachTime(kArbitraryTicks);
95*6777b538SAndroid Build Coastguard Worker
96*6777b538SAndroid Build Coastguard Worker  // With a unity timebase the output should be the input.
97*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(Nanoseconds(kArbitraryTicks), result);
98*6777b538SAndroid Build Coastguard Worker}
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsOverflowDetection) {
101*6777b538SAndroid Build Coastguard Worker  const uint32_t kArbitraryNumer = 1234567;
102*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase({kArbitraryNumer, 1});
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker  // Expect an overflow.
105*6777b538SAndroid Build Coastguard Worker  EXPECT_CHECK_DEATH(
106*6777b538SAndroid Build Coastguard Worker      TimeDelta::FromMachTime(std::numeric_limits<uint64_t>::max()));
107*6777b538SAndroid Build Coastguard Worker}
108*6777b538SAndroid Build Coastguard Worker
109*6777b538SAndroid Build Coastguard Worker// Tests that there's no overflow in MachTimeToMicroseconds even with
110*6777b538SAndroid Build Coastguard Worker// std::numeric_limits<uint64_t>::max() ticks on Intel.
111*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsNoOverflowIntel) {
112*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kIntelTimebase);
113*6777b538SAndroid Build Coastguard Worker
114*6777b538SAndroid Build Coastguard Worker  // The incoming Mach time ticks are on the order of nanoseconds while the
115*6777b538SAndroid Build Coastguard Worker  // return result is microseconds. Even though we're passing in the largest
116*6777b538SAndroid Build Coastguard Worker  // tick count the result should be orders of magnitude smaller. On Intel the
117*6777b538SAndroid Build Coastguard Worker  // mapping from ticks to nanoseconds is 1:1 so we wouldn't ever expect an
118*6777b538SAndroid Build Coastguard Worker  // overflow when applying the timebase conversion.
119*6777b538SAndroid Build Coastguard Worker  TimeDelta::FromMachTime(std::numeric_limits<uint64_t>::max());
120*6777b538SAndroid Build Coastguard Worker}
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker// Tests that there's no overflow in MachTimeToMicroseconds even with
123*6777b538SAndroid Build Coastguard Worker// std::numeric_limits<uint64_t>::max() ticks on M1.
124*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsNoOverflowM1) {
125*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kM1Timebase);
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker  // The incoming Mach time ticks are on the order of nanoseconds while the
128*6777b538SAndroid Build Coastguard Worker  // return result is microseconds. Even though we're passing in the largest
129*6777b538SAndroid Build Coastguard Worker  // tick count the result should be orders of magnitude smaller. Expect that
130*6777b538SAndroid Build Coastguard Worker  // FromMachTime(), when applying the timebase conversion, is smart enough to
131*6777b538SAndroid Build Coastguard Worker  // not multiply first and generate an overflow.
132*6777b538SAndroid Build Coastguard Worker  TimeDelta::FromMachTime(std::numeric_limits<uint64_t>::max());
133*6777b538SAndroid Build Coastguard Worker}
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker// Tests that there's no underflow in MachTimeToMicroseconds on Intel.
136*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsNoUnderflowIntel) {
137*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kIntelTimebase);
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker  // On Intel the timebase conversion is 1:1, so min ticks is one microsecond
140*6777b538SAndroid Build Coastguard Worker  // worth of nanoseconds.
141*6777b538SAndroid Build Coastguard Worker  const uint64_t kMinimumTicks = base::Time::kNanosecondsPerMicrosecond;
142*6777b538SAndroid Build Coastguard Worker  const uint64_t kOneMicrosecond = 1;
143*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(kOneMicrosecond,
144*6777b538SAndroid Build Coastguard Worker            TimeDelta::FromMachTime(kMinimumTicks).InMicroseconds() * 1UL);
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Worker  // If we have even one fewer tick (i.e. not enough ticks to constitute a full
147*6777b538SAndroid Build Coastguard Worker  // microsecond) the integer rounding should result in 0 microseconds.
148*6777b538SAndroid Build Coastguard Worker  const uint64_t kZeroMicroseconds = 0;
149*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(kZeroMicroseconds,
150*6777b538SAndroid Build Coastguard Worker            TimeDelta::FromMachTime(kMinimumTicks - 1).InMicroseconds() * 1UL);
151*6777b538SAndroid Build Coastguard Worker}
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker// Tests that there's no underflow in MachTimeToMicroseconds for M1.
154*6777b538SAndroid Build Coastguard WorkerTEST(TimeMacTest, MachTimeToMicrosecondsNoUnderflowM1) {
155*6777b538SAndroid Build Coastguard Worker  ScopedTimebase timebase(kM1Timebase);
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker  // Microseconds is mach_time multiplied by kM1Timebase.numer /
158*6777b538SAndroid Build Coastguard Worker  // (kM1Timebase.denom * base::Time::kNanosecondsPerMicrosecond). Inverting
159*6777b538SAndroid Build Coastguard Worker  // that should be the minimum number of ticks to get a single microsecond in
160*6777b538SAndroid Build Coastguard Worker  // return. If we get zero it means an underflow in the conversion. For example
161*6777b538SAndroid Build Coastguard Worker  // if FromMachTime() first divides mach_time by kM1Timebase.denom *
162*6777b538SAndroid Build Coastguard Worker  // base::Time::kNanosecondsPerMicrosecond we'll get zero back.
163*6777b538SAndroid Build Coastguard Worker  const uint64_t kMinimumTicks =
164*6777b538SAndroid Build Coastguard Worker      (kM1Timebase.denom * base::Time::kNanosecondsPerMicrosecond) /
165*6777b538SAndroid Build Coastguard Worker      kM1Timebase.numer;
166*6777b538SAndroid Build Coastguard Worker  const uint64_t kOneMicrosecond = 1;
167*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(kOneMicrosecond,
168*6777b538SAndroid Build Coastguard Worker            TimeDelta::FromMachTime(kMinimumTicks).InMicroseconds() * 1UL);
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker  // If we have even one fewer tick (i.e. not enough ticks to constitute a full
171*6777b538SAndroid Build Coastguard Worker  // microsecond) the integer rounding should result in 0 microseconds.
172*6777b538SAndroid Build Coastguard Worker  const uint64_t kZeroMicroseconds = 0;
173*6777b538SAndroid Build Coastguard Worker  EXPECT_EQ(kZeroMicroseconds,
174*6777b538SAndroid Build Coastguard Worker            TimeDelta::FromMachTime(kMinimumTicks - 1).InMicroseconds() * 1UL);
175*6777b538SAndroid Build Coastguard Worker}
176*6777b538SAndroid Build Coastguard Worker
177*6777b538SAndroid Build Coastguard Worker}  // namespace
178*6777b538SAndroid Build Coastguard Worker}  // namespace base
179