source: valtobtest/subversion-1.6.2/subversion/tests/libsvn_subr/time-test.c @ 3

Last change on this file since 3 was 3, checked in by valtob, 15 years ago

subversion source 1.6.2 as test

File size: 13.4 KB
Line 
1/*
2 * time-test.c -- test the time functions
3 *
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
6 *
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution.  The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
12 *
13 * This software consists of voluntary contributions made by many
14 * individuals.  For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
17 */
18
19#include <stdio.h>
20#include <string.h>
21#include <apr_general.h>
22#include "svn_time.h"
23
24#include "../svn_test.h"
25
26/* All these variables should refer to the same point in time. */
27apr_time_t test_timestamp = APR_TIME_C(1021316450966679);
28const char *test_timestring =
29"2002-05-13T19:00:50.966679Z";
30const char *test_old_timestring =
31"Mon 13 May 2002 22:00:50.966679 (day 133, dst 1, gmt_off 010800)";
32
33
34static svn_error_t *
35test_time_to_cstring(const char **msg,
36                     svn_boolean_t msg_only,
37                     svn_test_opts_t *opts,
38                     apr_pool_t *pool)
39{
40  const char *timestring;
41
42  *msg = "test svn_time_to_cstring";
43
44  if (msg_only)
45    return SVN_NO_ERROR;
46
47  timestring = svn_time_to_cstring(test_timestamp,pool);
48
49  if (strcmp(timestring,test_timestring) != 0)
50    {
51      return svn_error_createf
52        (SVN_ERR_TEST_FAILED, NULL,
53         "svn_time_to_cstring (%" APR_TIME_T_FMT
54         ") returned date string '%s' instead of '%s'",
55         test_timestamp,timestring,test_timestring);
56    }
57
58  return SVN_NO_ERROR;
59}
60
61
62static svn_error_t *
63test_time_from_cstring(const char **msg,
64                       svn_boolean_t msg_only,
65                       svn_test_opts_t *opts,
66                       apr_pool_t *pool)
67{
68  apr_time_t timestamp;
69
70  *msg = "test svn_time_from_cstring";
71
72  if (msg_only)
73    return SVN_NO_ERROR;
74
75  SVN_ERR(svn_time_from_cstring(&timestamp, test_timestring, pool));
76
77  if (timestamp != test_timestamp)
78    {
79      return svn_error_createf
80        (SVN_ERR_TEST_FAILED, NULL,
81         "svn_time_from_cstring (%s) returned time '%" APR_TIME_T_FMT
82         "' instead of '%" APR_TIME_T_FMT "'",
83         test_timestring,timestamp,test_timestamp);
84    }
85
86  return SVN_NO_ERROR;
87}
88
89/* Before editing these tests cases please see the comment in
90 * test_time_from_cstring_old regarding the requirements to exercise the bug
91 * that they exist to test. */
92static const char *failure_old_tests[] = {
93  /* Overflow Day */
94  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
95  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
96  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
97  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
98  " 3 Oct 2000 HH:MM:SS.UUU (day 277, dst 1, gmt_off -18000)",
99
100  /* Overflow Month */
101  "Tue 3 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
102  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
103  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
104  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
105  " 2000 HH:MM:SS.UUU (day 277, dst 1, gmt_off -18000)",
106
107  NULL
108};
109
110static svn_error_t *
111test_time_from_cstring_old(const char **msg,
112                           svn_boolean_t msg_only,
113                           svn_test_opts_t *opts,
114                           apr_pool_t *pool)
115{
116  apr_time_t timestamp;
117  const char **ft;
118
119  *msg = "test svn_time_from_cstring (old format)";
120
121  if (msg_only)
122    return SVN_NO_ERROR;
123
124  SVN_ERR(svn_time_from_cstring(&timestamp, test_old_timestring, pool));
125
126  if (timestamp != test_timestamp)
127    {
128      return svn_error_createf
129        (SVN_ERR_TEST_FAILED, NULL,
130         "svn_time_from_cstring (%s) returned time '%" APR_TIME_T_FMT
131         "' instead of '%" APR_TIME_T_FMT "'",
132         test_old_timestring,timestamp,test_timestamp);
133    }
134
135    /* These tests should fail.  They've been added to cover a string overflow
136     * found in our code.  However, even if they fail that may not indicate
137     * that there is no problem.  The strings being tested need to be
138     * sufficently long to cause a segmentation fault in order to exercise
139     * this bug.  Unfortunately due to differences in compilers, architectures,
140     * etc. there is no way to be sure that the bug is being exerercised on
141     * all platforms. */
142    for (ft = failure_old_tests; *ft; ft++)
143      {
144        svn_error_t *err = svn_time_from_cstring(&timestamp, *ft, pool);
145        if (! err)
146          return svn_error_createf
147            (SVN_ERR_TEST_FAILED, NULL,
148             "svn_time_from_cstring (%s) succeeded when it should have failed",
149             *ft);
150        svn_error_clear(err);
151      }
152
153  return SVN_NO_ERROR;
154}
155
156
157static svn_error_t *
158test_time_invariant(const char **msg,
159                    svn_boolean_t msg_only,
160                    svn_test_opts_t *opts,
161                    apr_pool_t *pool)
162{
163  apr_time_t current_timestamp = apr_time_now();
164  const char *timestring;
165  apr_time_t timestamp;
166
167  *msg = "test svn_time_[to/from]_cstring() invariant";
168
169  if (msg_only)
170    return SVN_NO_ERROR;
171
172  timestring = svn_time_to_cstring(current_timestamp, pool);
173  SVN_ERR(svn_time_from_cstring(&timestamp, timestring, pool));
174
175  if (timestamp != current_timestamp)
176    {
177      return svn_error_createf
178        (SVN_ERR_TEST_FAILED, NULL,
179         "svn_time_from_cstring ( svn_time_to_cstring (n) ) returned time '%"
180         APR_TIME_T_FMT
181         "' instead of '%" APR_TIME_T_FMT "'",
182         timestamp,current_timestamp);
183    }
184
185  return SVN_NO_ERROR;
186}
187
188
189struct date_test {
190  const char *str;
191  apr_int32_t year;
192  apr_int32_t mon;
193  apr_int32_t mday;
194  apr_int32_t hour;
195  apr_int32_t min;
196  apr_int32_t sec;
197  apr_int32_t usec;
198};
199
200/* These date strings do not specify a time zone, so we expand the
201   svn_parse_date result it in the local time zone and verify that
202   against the desired values. */
203static struct date_test localtz_tests[] = {
204  /* YYYY-M[M]-D[D] */
205  { "2013-01-25",                      2013,  1, 25,  0,  0,  0,      0 },
206  { "2013-1-25",                       2013,  1, 25,  0,  0,  0,      0 },
207  { "2013-01-2",                       2013,  1,  2,  0,  0,  0,      0 },
208  /* YYYY-M[M]-D[D][Th[h]:mm[:ss[.u[u[u[u[u[u] */
209  { "2015-04-26T00:01:59.652655",      2015,  4, 26,  0,  1, 59, 652655 },
210  { "2034-07-20T17:03:36.11379",       2034,  7, 20, 17,  3, 36, 113790 },
211  { "1975-10-29T17:23:56.3859",        1975, 10, 29, 17, 23, 56, 385900 },
212  { "2024-06-08T13:06:14.897",         2024,  6,  8, 13,  6, 14, 897000 },
213  { "2000-01-10T05:11:11.65",          2000,  1, 10,  5, 11, 11, 650000 },
214  { "2017-01-28T07:21:13.2",           2017,  1, 28,  7, 21, 13, 200000 },
215  { "2013-05-18T13:52:49",             2013,  5, 18, 13, 52, 49,      0 },
216  { "2020-05-14T15:28",                2020,  5, 14, 15, 28,  0,      0 },
217  { "2032-05-14T7:28",                 2032,  5, 14,  7, 28,  0,      0 },
218  { "2020-5-14T15:28",                 2020,  5, 14, 15, 28,  0,      0 },
219  { "2020-05-1T15:28",                 2020,  5,  1, 15, 28,  0,      0 },
220  /* YYYYMMDD */
221  { "20100226",                        2010,  2, 26,  0,  0,  0,      0 },
222  /* YYYYMMDD[Thhmm[ss[.u[u[u[u[u[u] */
223  { "19860214T050745.6",               1986,  2, 14,  5,  7, 45, 600000 },
224  { "20230219T0045",                   2023,  2, 19,  0, 45,  0,      0 },
225  /* YYYY-M[M]-D[D] [h]h:mm[:ss[.u[u[u[u[u[u] */
226  { "1975-07-11 06:31:49.749504",      1975,  7, 11,  6, 31, 49, 749504 },
227  { "2037-05-06 00:08",                2037,  5,  6,  0,  8,  0,      0 },
228  { "2037-5-6 7:01",                  2037,  5,  6,  7,  1,  0,      0 },
229  /* Make sure we can do leap days. */
230  { "1976-02-29",                      1976, 02, 29,  0,  0,  0,      0 },
231  { "2000-02-29",                      2000, 02, 29,  0,  0,  0,      0 },
232  { NULL }
233};
234
235/* These date strings specify an explicit time zone, so we expand the
236   svn_parse_date result in UTC and verify that against the desired
237   values (which have been adjusted for the specified time zone). */
238static struct date_test gmt_tests[] = {
239  /* YYYY-MM-DDThh:mm[:ss[.u[u[u[u[u[u]Z */
240  { "1979-05-05T15:16:04.39Z",         1979,  5,  5, 15, 16,  4, 390000 },
241  { "2012-03-25T12:14Z",               2012,  3, 25, 12, 14,  0,      0 },
242  /* YYYY-MM-DDThh:mm[:ss[.u[u[u[u[u[u]+OO[:oo] */
243  { "1991-09-13T20:13:01.12779+02:26", 1991,  9, 13, 17, 47,  1, 127790 },
244  { "1971-07-20T06:11-10",             1971,  7, 20, 16, 11,  0,      0 },
245  /* YYYYMMDDThhmm[ss[.u[u[u[u[u[u]Z */
246  { "20010808T105155.527Z",            2001,  8,  8, 10, 51, 55, 527000 },
247  { "19781204T1322Z",                  1978, 12,  4, 13, 22,  0,      0 },
248  /* YYYYMMDDThhmm[ss[.u[u[u[u[u[u]+OO[oo] */
249  { "20030930T001647.8008-0230",       2003,  9, 30,  2, 46, 47, 800800 },
250  { "19810526T1705+22",                1981,  5, 25, 19,  5,  0,      0 },
251  /* YYYY-MM-DD hh:mm[:ss[.u[u[u[u[u[u][ +OO[oo] */
252  { "2024-06-02 11:30:36 +08",         2024,  6,  2,  3, 30, 36,      0 },
253  { "1994-10-07 08:08 -1457",          1994, 10, 07, 23,  5,  0,      0 },
254  { NULL }
255};
256
257/* These date strings only specify a time of day, so we fill the
258   current date into the desired values before comparing.  (Currently
259   we do not allow a time zone with just a time of day.) */
260static struct date_test daytime_tests[] = {
261  /* hh:mm[:ss[.u[u[u[u[u[u] */
262  { "00:54:15.46",                        0,  0,  0,  0, 54, 15, 460000 },
263  { "18:21",                              0,  0,  0, 18, 21,  0,      0 },
264  { NULL }
265};
266
267/* These date strings should not parse correctly. */
268static const char *failure_tests[] = {
269  "2000-00-02",           /* Invalid month */
270  "2000-13-02",           /* Invalid month */
271  "2000-01-32",           /* Invalid day */
272  "2000-01-00",           /* Invalid day */
273  "1999-02-29",           /* Invalid leap day */
274  "2000-01-01 24:00:00",  /* Invalid hour */
275  "2000-01-01 00:60:00",  /* Invalid minute */
276  "2000-01-01 00:00:61",  /* Invalid second (60 is okay for leap seconds) */
277  "2000-01-01+24:00",     /* Invalid timezone hours */
278  "2000-01-01-02:60",     /* Invalid timezone minutes */
279  "2000-01-01Z",          /* Date with timezone, but no time */
280  "2000-01-01+01:00",
281  "20000101Z",
282  "20000101-0100",
283  "2000-01-01T10",        /* Time with hours but no minutes */
284  "20000101T10",
285  "2000-01-01 10",
286  NULL
287};
288
289static svn_error_t *
290compare_results(struct date_test *dt,
291                apr_time_exp_t *expt)
292{
293  if (expt->tm_year + 1900 != dt->year || expt->tm_mon + 1 != dt->mon
294      || expt->tm_mday != dt->mday || expt->tm_hour != dt->hour
295      || expt->tm_min != dt->min || expt->tm_sec != dt->sec
296      || expt->tm_usec != dt->usec)
297    return svn_error_createf
298      (SVN_ERR_TEST_FAILED, NULL, "Comparison failed for '%s'", dt->str);
299  return SVN_NO_ERROR;
300}
301
302static svn_error_t *
303test_parse_date(const char **msg,
304                svn_boolean_t msg_only,
305                svn_test_opts_t *opts,
306                apr_pool_t *pool)
307{
308  apr_time_t now, result;
309  apr_time_exp_t nowexp, expt;
310  svn_boolean_t matched;
311  struct date_test *dt;
312  const char **ft;
313
314  *msg = "test svn_parse_date";
315
316  if (msg_only)
317    return SVN_NO_ERROR;
318
319  now = apr_time_now();
320  if (apr_time_exp_lt(&nowexp, now) != APR_SUCCESS)
321    return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Can't expand time");
322
323  for (dt = localtz_tests; dt->str; dt++)
324    {
325      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
326      if (!matched)
327        return svn_error_createf
328          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
329      if (apr_time_exp_lt(&expt, result) != APR_SUCCESS)
330        return svn_error_createf
331          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
332      SVN_ERR(compare_results(dt, &expt));
333    }
334
335  for (dt = gmt_tests; dt->str; dt++)
336    {
337      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
338      if (!matched)
339        return svn_error_createf
340          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
341      if (apr_time_exp_gmt(&expt, result) != APR_SUCCESS)
342        return svn_error_createf
343          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
344      SVN_ERR(compare_results(dt, &expt));
345    }
346
347  for (dt = daytime_tests; dt->str; dt++)
348    {
349      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
350      if (!matched)
351        return svn_error_createf
352          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
353      if (apr_time_exp_lt(&expt, result) != APR_SUCCESS)
354        return svn_error_createf
355          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
356      dt->year = nowexp.tm_year + 1900;
357      dt->mon = nowexp.tm_mon + 1;
358      dt->mday = nowexp.tm_mday;
359      SVN_ERR(compare_results(dt, &expt));
360    }
361
362  for (ft = failure_tests; *ft; ft++)
363    {
364      SVN_ERR(svn_parse_date(&matched, &result, *ft, now, pool));
365      if (matched)
366        return svn_error_createf
367          (SVN_ERR_TEST_FAILED, NULL, "Match succeeded for '%s'", *ft);
368    }
369
370  return SVN_NO_ERROR;
371}
372
373
374
375/* The test table.  */
376
377struct svn_test_descriptor_t test_funcs[] =
378  {
379    SVN_TEST_NULL,
380    SVN_TEST_PASS(test_time_to_cstring),
381    SVN_TEST_PASS(test_time_from_cstring),
382    SVN_TEST_PASS(test_time_from_cstring_old),
383    SVN_TEST_PASS(test_time_invariant),
384    SVN_TEST_PASS(test_parse_date),
385    SVN_TEST_NULL
386  };
Note: See TracBrowser for help on using the repository browser.