1// Copyright (c) 2012 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.
4
5#include <stdint.h>
6#include <time.h>
7
8#include "base/compiler_specific.h"
9#include "base/third_party/nspr/prtime.h"
10#include "base/time/time.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13using base::Time;
14
15namespace {
16
17// time_t representation of 15th Oct 2007 12:45:00 PDT
18PRTime comparison_time_pdt = 1192477500 * Time::kMicrosecondsPerSecond;
19
20// Time with positive tz offset and fractional seconds:
21// 2013-07-08T11:28:12.441381+02:00
22PRTime comparison_time_2 = INT64_C(1373275692441381);   // represented as GMT
23
24// Specialized test fixture allowing time strings without timezones to be
25// tested by comparing them to a known time in the local zone.
26class PRTimeTest : public testing::Test {
27 protected:
28  virtual void SetUp() OVERRIDE {
29    // Use mktime to get a time_t, and turn it into a PRTime by converting
30    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
31    // must be a time guaranteed to be outside of a DST fallback hour in
32    // any timezone.
33    struct tm local_comparison_tm = {
34      0,            // second
35      45,           // minute
36      12,           // hour
37      15,           // day of month
38      10 - 1,       // month
39      2007 - 1900,  // year
40      0,            // day of week (ignored, output only)
41      0,            // day of year (ignored, output only)
42      -1            // DST in effect, -1 tells mktime to figure it out
43    };
44    comparison_time_local_ =
45        mktime(&local_comparison_tm) * Time::kMicrosecondsPerSecond;
46    ASSERT_GT(comparison_time_local_, 0);
47
48    const int microseconds = 441381;
49    struct tm local_comparison_tm_2 = {
50      12,           // second
51      28,           // minute
52      11,           // hour
53      8,            // day of month
54      7 - 1,        // month
55      2013 - 1900,  // year
56      0,            // day of week (ignored, output only)
57      0,            // day of year (ignored, output only)
58      -1            // DST in effect, -1 tells mktime to figure it out
59    };
60    comparison_time_local_2_ =
61        mktime(&local_comparison_tm_2) * Time::kMicrosecondsPerSecond;
62    ASSERT_GT(comparison_time_local_2_, 0);
63    comparison_time_local_2_ += microseconds;
64  }
65
66  PRTime comparison_time_local_;
67  PRTime comparison_time_local_2_;
68};
69
70// Tests the PR_ParseTimeString nspr helper function for
71// a variety of time strings.
72TEST_F(PRTimeTest, ParseTimeTest1) {
73  time_t current_time = 0;
74  time(&current_time);
75
76  const int BUFFER_SIZE = 64;
77  struct tm local_time = {0};
78  char time_buf[BUFFER_SIZE] = {0};
79#if defined(OS_WIN)
80  localtime_s(&local_time, &current_time);
81  asctime_s(time_buf, arraysize(time_buf), &local_time);
82#elif defined(OS_POSIX)
83  localtime_r(&current_time, &local_time);
84  asctime_r(&local_time, time_buf);
85#endif
86
87  PRTime current_time64 = static_cast<PRTime>(current_time) * PR_USEC_PER_SEC;
88
89  PRTime parsed_time = 0;
90  PRStatus result = PR_ParseTimeString(time_buf, PR_FALSE, &parsed_time);
91  EXPECT_EQ(PR_SUCCESS, result);
92  EXPECT_EQ(current_time64, parsed_time);
93}
94
95TEST_F(PRTimeTest, ParseTimeTest2) {
96  PRTime parsed_time = 0;
97  PRStatus result = PR_ParseTimeString("Mon, 15 Oct 2007 19:45:00 GMT",
98                                       PR_FALSE, &parsed_time);
99  EXPECT_EQ(PR_SUCCESS, result);
100  EXPECT_EQ(comparison_time_pdt, parsed_time);
101}
102
103TEST_F(PRTimeTest, ParseTimeTest3) {
104  PRTime parsed_time = 0;
105  PRStatus result = PR_ParseTimeString("15 Oct 07 12:45:00", PR_FALSE,
106                                       &parsed_time);
107  EXPECT_EQ(PR_SUCCESS, result);
108  EXPECT_EQ(comparison_time_local_, parsed_time);
109}
110
111TEST_F(PRTimeTest, ParseTimeTest4) {
112  PRTime parsed_time = 0;
113  PRStatus result = PR_ParseTimeString("15 Oct 07 19:45 GMT", PR_FALSE,
114                                       &parsed_time);
115  EXPECT_EQ(PR_SUCCESS, result);
116  EXPECT_EQ(comparison_time_pdt, parsed_time);
117}
118
119TEST_F(PRTimeTest, ParseTimeTest5) {
120  PRTime parsed_time = 0;
121  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:45 PDT 2007",
122                                       PR_FALSE, &parsed_time);
123  EXPECT_EQ(PR_SUCCESS, result);
124  EXPECT_EQ(comparison_time_pdt, parsed_time);
125}
126
127TEST_F(PRTimeTest, ParseTimeTest6) {
128  PRTime parsed_time = 0;
129  PRStatus result = PR_ParseTimeString("Monday, Oct 15, 2007 12:45 PM",
130                                       PR_FALSE, &parsed_time);
131  EXPECT_EQ(PR_SUCCESS, result);
132  EXPECT_EQ(comparison_time_local_, parsed_time);
133}
134
135TEST_F(PRTimeTest, ParseTimeTest7) {
136  PRTime parsed_time = 0;
137  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00 PM", PR_FALSE,
138                                       &parsed_time);
139  EXPECT_EQ(PR_SUCCESS, result);
140  EXPECT_EQ(comparison_time_local_, parsed_time);
141}
142
143TEST_F(PRTimeTest, ParseTimeTest8) {
144  PRTime parsed_time = 0;
145  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00. PM", PR_FALSE,
146                                       &parsed_time);
147  EXPECT_EQ(PR_SUCCESS, result);
148  EXPECT_EQ(comparison_time_local_, parsed_time);
149}
150
151TEST_F(PRTimeTest, ParseTimeTest9) {
152  PRTime parsed_time = 0;
153  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00.0 PM", PR_FALSE,
154                                       &parsed_time);
155  EXPECT_EQ(PR_SUCCESS, result);
156  EXPECT_EQ(comparison_time_local_, parsed_time);
157}
158
159TEST_F(PRTimeTest, ParseTimeTest10) {
160  PRTime parsed_time = 0;
161  PRStatus result = PR_ParseTimeString("15-OCT-2007 12:45pm", PR_FALSE,
162                                       &parsed_time);
163  EXPECT_EQ(PR_SUCCESS, result);
164  EXPECT_EQ(comparison_time_local_, parsed_time);
165}
166
167TEST_F(PRTimeTest, ParseTimeTest11) {
168  PRTime parsed_time = 0;
169  PRStatus result = PR_ParseTimeString("16 Oct 2007 4:45-JST (Tuesday)",
170                                       PR_FALSE, &parsed_time);
171  EXPECT_EQ(PR_SUCCESS, result);
172  EXPECT_EQ(comparison_time_pdt, parsed_time);
173}
174
175// hh:mm timezone offset.
176TEST_F(PRTimeTest, ParseTimeTest12) {
177  PRTime parsed_time = 0;
178  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+02:00",
179                                       PR_FALSE, &parsed_time);
180  EXPECT_EQ(PR_SUCCESS, result);
181  EXPECT_EQ(comparison_time_2, parsed_time);
182}
183
184// hhmm timezone offset.
185TEST_F(PRTimeTest, ParseTimeTest13) {
186  PRTime parsed_time = 0;
187  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+0200",
188                                       PR_FALSE, &parsed_time);
189  EXPECT_EQ(PR_SUCCESS, result);
190  EXPECT_EQ(comparison_time_2, parsed_time);
191}
192
193// hh timezone offset.
194TEST_F(PRTimeTest, ParseTimeTest14) {
195  PRTime parsed_time = 0;
196  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.4413819+02",
197                                       PR_FALSE, &parsed_time);
198  EXPECT_EQ(PR_SUCCESS, result);
199  EXPECT_EQ(comparison_time_2, parsed_time);
200}
201
202// 5 digits fractional second.
203TEST_F(PRTimeTest, ParseTimeTest15) {
204  PRTime parsed_time = 0;
205  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.44138Z",
206                                       PR_FALSE, &parsed_time);
207  EXPECT_EQ(PR_SUCCESS, result);
208  EXPECT_EQ(comparison_time_2-1, parsed_time);
209}
210
211// Fractional seconds, local timezone.
212TEST_F(PRTimeTest, ParseTimeTest16) {
213  PRTime parsed_time = 0;
214  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381",
215                                       PR_FALSE, &parsed_time);
216  EXPECT_EQ(PR_SUCCESS, result);
217  EXPECT_EQ(comparison_time_local_2_, parsed_time);
218}
219
220// "Z" (=GMT) timezone.
221TEST_F(PRTimeTest, ParseTimeTest17) {
222  PRTime parsed_time = 0;
223  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.441381Z",
224                                       PR_FALSE, &parsed_time);
225  EXPECT_EQ(PR_SUCCESS, result);
226  EXPECT_EQ(comparison_time_2, parsed_time);
227}
228
229// "T" delimiter replaced by space.
230TEST_F(PRTimeTest, ParseTimeTest18) {
231  PRTime parsed_time = 0;
232  PRStatus result = PR_ParseTimeString("2013-07-08 09:28:12.441381Z",
233                                       PR_FALSE, &parsed_time);
234  EXPECT_EQ(PR_SUCCESS, result);
235  EXPECT_EQ(comparison_time_2, parsed_time);
236}
237
238TEST_F(PRTimeTest, ParseTimeTestInvalid1) {
239  PRTime parsed_time = 0;
240  PRStatus result = PR_ParseTimeString("201-07-08T09:28:12.441381Z",
241                                       PR_FALSE, &parsed_time);
242  EXPECT_EQ(PR_FAILURE, result);
243}
244
245TEST_F(PRTimeTest, ParseTimeTestInvalid2) {
246  PRTime parsed_time = 0;
247  PRStatus result = PR_ParseTimeString("2013-007-08T09:28:12.441381Z",
248                                       PR_FALSE, &parsed_time);
249  EXPECT_EQ(PR_FAILURE, result);
250}
251
252TEST_F(PRTimeTest, ParseTimeTestInvalid3) {
253  PRTime parsed_time = 0;
254  PRStatus result = PR_ParseTimeString("2013-07-008T09:28:12.441381Z",
255                                       PR_FALSE, &parsed_time);
256  EXPECT_EQ(PR_FAILURE, result);
257}
258
259// This test should not crash when compiled with Visual C++ 2005 (see
260// http://crbug.com/4387).
261TEST_F(PRTimeTest, ParseTimeTestOutOfRange) {
262  PRTime parsed_time = 0;
263  // Note the lack of timezone in the time string.  The year has to be 3001.
264  // The date has to be after 23:59:59, December 31, 3000, US Pacific Time, so
265  // we use January 2, 3001 to make sure it's after the magic maximum in any
266  // timezone.
267  PRStatus result = PR_ParseTimeString("Sun Jan  2 00:00:00 3001",
268                                       PR_FALSE, &parsed_time);
269  EXPECT_EQ(PR_SUCCESS, result);
270}
271
272TEST_F(PRTimeTest, ParseTimeTestNotNormalized1) {
273  PRTime parsed_time = 0;
274  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:44:60 PDT 2007",
275                                       PR_FALSE, &parsed_time);
276  EXPECT_EQ(PR_SUCCESS, result);
277  EXPECT_EQ(comparison_time_pdt, parsed_time);
278}
279
280TEST_F(PRTimeTest, ParseTimeTestNotNormalized2) {
281  PRTime parsed_time = 0;
282  PRStatus result = PR_ParseTimeString("Sun Oct 14 36:45 PDT 2007",
283                                       PR_FALSE, &parsed_time);
284  EXPECT_EQ(PR_SUCCESS, result);
285  EXPECT_EQ(comparison_time_pdt, parsed_time);
286}
287
288}  // namespace
289