blob: 9da577984140ed004df835344aa69da6184daeae [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
pinkerton@google.com4af6c912008-08-14 08:23:13 +09005#include "build/build_config.h"
6
initial.commit3f4a7322008-07-27 06:49:38 +09007#include <time.h>
8
pinkerton@google.com75d74022008-08-14 07:55:45 +09009#if defined(OS_WIN)
10#include <process.h>
11#endif
12
initial.commit3f4a7322008-07-27 06:49:38 +090013#include "base/time.h"
pinkerton@google.com75d74022008-08-14 07:55:45 +090014#include "base/platform_thread.h"
initial.commit3f4a7322008-07-27 06:49:38 +090015#include "testing/gtest/include/gtest/gtest.h"
16
17// Test conversions to/from time_t and exploding/unexploding.
18TEST(Time, TimeT) {
19 // C library time and exploded time.
20 time_t now_t_1 = time(NULL);
21 struct tm tms;
pinkerton@google.com75d74022008-08-14 07:55:45 +090022#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +090023 localtime_s(&tms, &now_t_1);
pinkerton@google.com75d74022008-08-14 07:55:45 +090024#elif defined(OS_POSIX)
25 localtime_r(&now_t_1, &tms);
26#endif
initial.commit3f4a7322008-07-27 06:49:38 +090027
28 // Convert to ours.
29 Time our_time_1 = Time::FromTimeT(now_t_1);
30 Time::Exploded exploded;
31 our_time_1.LocalExplode(&exploded);
32
33 // This will test both our exploding and our time_t -> Time conversion.
34 EXPECT_EQ(tms.tm_year + 1900, exploded.year);
35 EXPECT_EQ(tms.tm_mon + 1, exploded.month);
36 EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
37 EXPECT_EQ(tms.tm_hour, exploded.hour);
38 EXPECT_EQ(tms.tm_min, exploded.minute);
39 EXPECT_EQ(tms.tm_sec, exploded.second);
40
41 // Convert exploded back to the time struct.
42 Time our_time_2 = Time::FromLocalExploded(exploded);
43 EXPECT_TRUE(our_time_1 == our_time_2);
44
45 time_t now_t_2 = our_time_2.ToTimeT();
46 EXPECT_EQ(now_t_1, now_t_2);
47
deanm@google.com02781222008-08-19 18:16:49 +090048 EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT());
49 EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT());
50
initial.commit3f4a7322008-07-27 06:49:38 +090051 // Conversions of 0 should stay 0.
52 EXPECT_EQ(0, Time().ToTimeT());
53 EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
54}
55
56TEST(Time, ZeroIsSymmetric) {
deanm@google.com02781222008-08-19 18:16:49 +090057 Time zero_time(Time::FromTimeT(0));
58 EXPECT_EQ(0, zero_time.ToTimeT());
59
60 EXPECT_EQ(0.0, zero_time.ToDoubleT());
initial.commit3f4a7322008-07-27 06:49:38 +090061}
62
63TEST(Time, LocalExplode) {
64 Time a = Time::Now();
65 Time::Exploded exploded;
66 a.LocalExplode(&exploded);
67
68 Time b = Time::FromLocalExploded(exploded);
69
70 // The exploded structure doesn't have microseconds, so the result will be
71 // rounded to the nearest millisecond.
72 EXPECT_TRUE((a - b) < TimeDelta::FromMilliseconds(1));
73}
74
75TEST(Time, UTCExplode) {
76 Time a = Time::Now();
77 Time::Exploded exploded;
78 a.UTCExplode(&exploded);
79
80 Time b = Time::FromUTCExploded(exploded);
81 EXPECT_TRUE((a - b) < TimeDelta::FromMilliseconds(1));
82}
83
deanm@google.com02781222008-08-19 18:16:49 +090084TEST(Time, LocalMidnight) {
85 Time::Exploded exploded;
86 Time::Now().LocalMidnight().LocalExplode(&exploded);
87 EXPECT_EQ(0, exploded.hour);
88 EXPECT_EQ(0, exploded.minute);
89 EXPECT_EQ(0, exploded.second);
90 EXPECT_EQ(0, exploded.millisecond);
91}
92
initial.commit3f4a7322008-07-27 06:49:38 +090093TEST(TimeTicks, Deltas) {
94 TimeTicks ticks_start = TimeTicks::Now();
pinkerton@google.com75d74022008-08-14 07:55:45 +090095 PlatformThread::Sleep(10);
initial.commit3f4a7322008-07-27 06:49:38 +090096 TimeTicks ticks_stop = TimeTicks::Now();
97 TimeDelta delta = ticks_stop - ticks_start;
98 EXPECT_GE(delta.InMilliseconds(), 10);
99 EXPECT_GE(delta.InMicroseconds(), 10000);
100 EXPECT_EQ(delta.InSeconds(), 0);
101}
102
deanm@google.com02781222008-08-19 18:16:49 +0900103TEST(TimeDelta, FromAndIn) {
104 EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
105 EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
106 EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
107 EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
108 EXPECT_TRUE(TimeDelta::FromMilliseconds(2) ==
109 TimeDelta::FromMicroseconds(2000));
110 EXPECT_EQ(13, TimeDelta::FromDays(13).InDays());
111 EXPECT_EQ(13, TimeDelta::FromHours(13).InHours());
112 EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes());
113 EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds());
114 EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
115 EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds());
116 EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
117 EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
118}
119
pinkerton@google.com75d74022008-08-14 07:55:45 +0900120#if defined(OS_WIN)
121
122// TODO(pinkerton): Need to find a way to mock this for non-windows.
123
initial.commit3f4a7322008-07-27 06:49:38 +0900124namespace {
125
126class MockTimeTicks : public TimeTicks {
127 public:
128 static int Ticker() {
129 return static_cast<int>(InterlockedIncrement(&ticker_));
130 }
131
132 static void InstallTicker() {
133 old_tick_function_ = tick_function_;
134 tick_function_ = reinterpret_cast<TickFunction>(&Ticker);
135 ticker_ = -5;
136 }
137
138 static void UninstallTicker() {
139 tick_function_ = old_tick_function_;
140 }
141
142 private:
143 static volatile LONG ticker_;
144 static TickFunction old_tick_function_;
145};
146
147volatile LONG MockTimeTicks::ticker_;
148MockTimeTicks::TickFunction MockTimeTicks::old_tick_function_;
149
150HANDLE g_rollover_test_start;
151
152unsigned __stdcall RolloverTestThreadMain(void* param) {
153 int64 counter = reinterpret_cast<int64>(param);
154 DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
155 EXPECT_EQ(rv, WAIT_OBJECT_0);
156
157 TimeTicks last = TimeTicks::Now();
158 for (int index = 0; index < counter; index++) {
159 TimeTicks now = TimeTicks::Now();
160 int64 milliseconds = (now - last).InMilliseconds();
161 EXPECT_GT(milliseconds, 0);
162 EXPECT_LT(milliseconds, 250);
163 last = now;
164 }
165 return 0;
166}
167
168} // namespace
169
170TEST(TimeTicks, Rollover) {
171 // The internal counter rolls over at ~49days. We'll use a mock
172 // timer to test this case.
173 // Basic test algorithm:
174 // 1) Set clock to rollover - N
175 // 2) Create N threads
176 // 3) Start the threads
177 // 4) Each thread loops through TimeTicks() N times
178 // 5) Each thread verifies integrity of result.
179
180 const int kThreads = 8;
181 // Use int64 so we can cast into a void* without a compiler warning.
182 const int64 kChecks = 10;
183
184 // It takes a lot of iterations to reproduce the bug!
185 // (See bug 1081395)
186 for (int loop = 0; loop < 4096; loop++) {
187 // Setup
188 MockTimeTicks::InstallTicker();
189 g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
190 HANDLE threads[kThreads];
191
192 for (int index = 0; index < kThreads; index++) {
193 void* argument = reinterpret_cast<void*>(kChecks);
194 unsigned thread_id;
195 threads[index] = reinterpret_cast<HANDLE>(
196 _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0,
197 &thread_id));
198 EXPECT_NE((HANDLE)NULL, threads[index]);
199 }
200
201 // Start!
202 SetEvent(g_rollover_test_start);
203
204 // Wait for threads to finish
205 for (int index = 0; index < kThreads; index++) {
206 DWORD rv = WaitForSingleObject(threads[index], INFINITE);
207 EXPECT_EQ(rv, WAIT_OBJECT_0);
208 }
209
210 CloseHandle(g_rollover_test_start);
211
212 // Teardown
213 MockTimeTicks::UninstallTicker();
214 }
215}
pinkerton@google.com75d74022008-08-14 07:55:45 +0900216
217#endif
license.botf003cfe2008-08-24 09:55:55 +0900218