blob: ca99da8c0332fdb0229ca135821d431e9ef7fab3 [file] [log] [blame]
initial.commit3f4a7322008-07-27 06:49:38 +09001// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
initial.commit3f4a7322008-07-27 06:49:38 +090030#include <time.h>
31
pinkerton@google.com75d74022008-08-14 07:55:45 +090032#if defined(OS_WIN)
33#include <process.h>
34#endif
35
initial.commit3f4a7322008-07-27 06:49:38 +090036#include "base/time.h"
pinkerton@google.com75d74022008-08-14 07:55:45 +090037#include "base/platform_thread.h"
initial.commit3f4a7322008-07-27 06:49:38 +090038#include "testing/gtest/include/gtest/gtest.h"
39
40// Test conversions to/from time_t and exploding/unexploding.
41TEST(Time, TimeT) {
42 // C library time and exploded time.
43 time_t now_t_1 = time(NULL);
44 struct tm tms;
pinkerton@google.com75d74022008-08-14 07:55:45 +090045#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +090046 localtime_s(&tms, &now_t_1);
pinkerton@google.com75d74022008-08-14 07:55:45 +090047#elif defined(OS_POSIX)
48 localtime_r(&now_t_1, &tms);
49#endif
initial.commit3f4a7322008-07-27 06:49:38 +090050
51 // Convert to ours.
52 Time our_time_1 = Time::FromTimeT(now_t_1);
53 Time::Exploded exploded;
54 our_time_1.LocalExplode(&exploded);
55
56 // This will test both our exploding and our time_t -> Time conversion.
57 EXPECT_EQ(tms.tm_year + 1900, exploded.year);
58 EXPECT_EQ(tms.tm_mon + 1, exploded.month);
59 EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
60 EXPECT_EQ(tms.tm_hour, exploded.hour);
61 EXPECT_EQ(tms.tm_min, exploded.minute);
62 EXPECT_EQ(tms.tm_sec, exploded.second);
63
64 // Convert exploded back to the time struct.
65 Time our_time_2 = Time::FromLocalExploded(exploded);
66 EXPECT_TRUE(our_time_1 == our_time_2);
67
68 time_t now_t_2 = our_time_2.ToTimeT();
69 EXPECT_EQ(now_t_1, now_t_2);
70
71 // Conversions of 0 should stay 0.
72 EXPECT_EQ(0, Time().ToTimeT());
73 EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
74}
75
76TEST(Time, ZeroIsSymmetric) {
77 Time zeroTime(Time::FromTimeT(0));
78 EXPECT_EQ(0, zeroTime.ToTimeT());
79}
80
81TEST(Time, LocalExplode) {
82 Time a = Time::Now();
83 Time::Exploded exploded;
84 a.LocalExplode(&exploded);
85
86 Time b = Time::FromLocalExploded(exploded);
87
88 // The exploded structure doesn't have microseconds, so the result will be
89 // rounded to the nearest millisecond.
90 EXPECT_TRUE((a - b) < TimeDelta::FromMilliseconds(1));
91}
92
93TEST(Time, UTCExplode) {
94 Time a = Time::Now();
95 Time::Exploded exploded;
96 a.UTCExplode(&exploded);
97
98 Time b = Time::FromUTCExploded(exploded);
99 EXPECT_TRUE((a - b) < TimeDelta::FromMilliseconds(1));
100}
101
102TEST(TimeTicks, Deltas) {
103 TimeTicks ticks_start = TimeTicks::Now();
pinkerton@google.com75d74022008-08-14 07:55:45 +0900104 PlatformThread::Sleep(10);
initial.commit3f4a7322008-07-27 06:49:38 +0900105 TimeTicks ticks_stop = TimeTicks::Now();
106 TimeDelta delta = ticks_stop - ticks_start;
107 EXPECT_GE(delta.InMilliseconds(), 10);
108 EXPECT_GE(delta.InMicroseconds(), 10000);
109 EXPECT_EQ(delta.InSeconds(), 0);
110}
111
pinkerton@google.com75d74022008-08-14 07:55:45 +0900112#if defined(OS_WIN)
113
114// TODO(pinkerton): Need to find a way to mock this for non-windows.
115
initial.commit3f4a7322008-07-27 06:49:38 +0900116namespace {
117
118class MockTimeTicks : public TimeTicks {
119 public:
120 static int Ticker() {
121 return static_cast<int>(InterlockedIncrement(&ticker_));
122 }
123
124 static void InstallTicker() {
125 old_tick_function_ = tick_function_;
126 tick_function_ = reinterpret_cast<TickFunction>(&Ticker);
127 ticker_ = -5;
128 }
129
130 static void UninstallTicker() {
131 tick_function_ = old_tick_function_;
132 }
133
134 private:
135 static volatile LONG ticker_;
136 static TickFunction old_tick_function_;
137};
138
139volatile LONG MockTimeTicks::ticker_;
140MockTimeTicks::TickFunction MockTimeTicks::old_tick_function_;
141
142HANDLE g_rollover_test_start;
143
144unsigned __stdcall RolloverTestThreadMain(void* param) {
145 int64 counter = reinterpret_cast<int64>(param);
146 DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
147 EXPECT_EQ(rv, WAIT_OBJECT_0);
148
149 TimeTicks last = TimeTicks::Now();
150 for (int index = 0; index < counter; index++) {
151 TimeTicks now = TimeTicks::Now();
152 int64 milliseconds = (now - last).InMilliseconds();
153 EXPECT_GT(milliseconds, 0);
154 EXPECT_LT(milliseconds, 250);
155 last = now;
156 }
157 return 0;
158}
159
160} // namespace
161
162TEST(TimeTicks, Rollover) {
163 // The internal counter rolls over at ~49days. We'll use a mock
164 // timer to test this case.
165 // Basic test algorithm:
166 // 1) Set clock to rollover - N
167 // 2) Create N threads
168 // 3) Start the threads
169 // 4) Each thread loops through TimeTicks() N times
170 // 5) Each thread verifies integrity of result.
171
172 const int kThreads = 8;
173 // Use int64 so we can cast into a void* without a compiler warning.
174 const int64 kChecks = 10;
175
176 // It takes a lot of iterations to reproduce the bug!
177 // (See bug 1081395)
178 for (int loop = 0; loop < 4096; loop++) {
179 // Setup
180 MockTimeTicks::InstallTicker();
181 g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
182 HANDLE threads[kThreads];
183
184 for (int index = 0; index < kThreads; index++) {
185 void* argument = reinterpret_cast<void*>(kChecks);
186 unsigned thread_id;
187 threads[index] = reinterpret_cast<HANDLE>(
188 _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0,
189 &thread_id));
190 EXPECT_NE((HANDLE)NULL, threads[index]);
191 }
192
193 // Start!
194 SetEvent(g_rollover_test_start);
195
196 // Wait for threads to finish
197 for (int index = 0; index < kThreads; index++) {
198 DWORD rv = WaitForSingleObject(threads[index], INFINITE);
199 EXPECT_EQ(rv, WAIT_OBJECT_0);
200 }
201
202 CloseHandle(g_rollover_test_start);
203
204 // Teardown
205 MockTimeTicks::UninstallTicker();
206 }
207}
pinkerton@google.com75d74022008-08-14 07:55:45 +0900208
209#endif