|
1 /* |
|
2 * Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Year 2000 compliance tests for STDLIB |
|
16 * |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 |
|
22 #include <stdlib.h> /* definition of exit() */ |
|
23 #include <stdio.h> |
|
24 #include <errno.h> |
|
25 #include <string.h> |
|
26 #include <time.h> |
|
27 #include <fcntl.h> |
|
28 #include <unistd.h> |
|
29 #include <sys/time.h> /* timeval, gettimeofday */ |
|
30 |
|
31 int failures=0; |
|
32 void failed(char* reason) |
|
33 { |
|
34 printf("\nFAILURE >>>%s\n", reason); |
|
35 failures++; |
|
36 } |
|
37 |
|
38 |
|
39 |
|
40 typedef struct { |
|
41 int day; /* 1-31 */ |
|
42 int month; /* 1-12 */ |
|
43 int year; /* 1970-2050 */ |
|
44 } testdate; |
|
45 |
|
46 char* testmonths[14] = { |
|
47 "invalid_0", |
|
48 "Jan", "Feb", "March", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec", |
|
49 "invalid_13" |
|
50 }; |
|
51 |
|
52 char* tmdaynames[8] = { |
|
53 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", |
|
54 "invalid_7" |
|
55 }; |
|
56 |
|
57 /* Format a testdate to match the Y2K document |
|
58 */ |
|
59 void format_testdate(testdate* aDate, char* aBuffer) |
|
60 { |
|
61 char* th="th"; |
|
62 if (aDate->day==1 || aDate->day==21 || aDate->day==31) |
|
63 th="st"; |
|
64 if (aDate->day==2 || aDate->day==22) |
|
65 th="nd"; |
|
66 |
|
67 sprintf(aBuffer, "%d%s %s %d", aDate->day, th, testmonths[aDate->month], aDate->year); |
|
68 } |
|
69 |
|
70 typedef struct { |
|
71 testdate input; /* for conversion to seconds */ |
|
72 testdate result; /* correct value */ |
|
73 } testpair; |
|
74 |
|
75 typedef struct { |
|
76 testdate input; /* for conversion to seconds */ |
|
77 int result; /* correct value */ |
|
78 } testint; |
|
79 |
|
80 /* MAJOR TEST FUNCTIONALITY - READ THIS CAREFULLY |
|
81 * |
|
82 * STDLIB date handling is done in terms of seconds since the "epoch", which was |
|
83 * 00:00 on 1st January, 1970. The Y2K significant functionality consists solely of the |
|
84 * routines which manipulate the struct tm data structure. |
|
85 * |
|
86 * time_t mktime (struct tm *brokentime) |
|
87 * |
|
88 * struct tm * gmtime (const time_t *time) |
|
89 * struct tm * localtime (const time_t *time) |
|
90 * |
|
91 * The mktime conversion is always using a GMT date, so we'll ignore the localtime function for Y2K |
|
92 * purposes. We also know that gmtime and localtime use the same underlying conversion function, |
|
93 * one applying the relevant GMT offset on the way in. |
|
94 * |
|
95 * Y2K is only concerned with dates, so we will always use 12:00:00 ("High Noon") as the time |
|
96 * of day. |
|
97 */ |
|
98 |
|
99 void tm_from_testdate(struct tm* aTm, testdate* aDate) |
|
100 { |
|
101 time_t seconds; |
|
102 struct tm setup; |
|
103 struct tm* res; |
|
104 |
|
105 setup.tm_hour = 12; |
|
106 setup.tm_min = 0; |
|
107 setup.tm_sec = 0; |
|
108 |
|
109 setup.tm_mday = aDate->day; |
|
110 setup.tm_mon = aDate->month - 1; /* struct tm uses 0-11 */ |
|
111 setup.tm_year = aDate->year - 1900; /* struct tm uses years since 1900 */ |
|
112 |
|
113 seconds = mktime(&setup); |
|
114 if (seconds != (time_t)(-1)) |
|
115 { |
|
116 res = gmtime(&seconds); |
|
117 *aTm = *res; |
|
118 return; |
|
119 } |
|
120 |
|
121 /* unable to convert date */ |
|
122 failed("tm_from_testdate: mktime failed"); |
|
123 } |
|
124 |
|
125 void normalize_tm(struct tm* aTm) |
|
126 { |
|
127 time_t seconds = mktime(aTm); |
|
128 if (seconds == (time_t)(-1)) |
|
129 { |
|
130 /* unable to convert date */ |
|
131 failed("normalize_tm: mktime failed"); |
|
132 } |
|
133 return; |
|
134 } |
|
135 |
|
136 int compare_testdate_tm(testdate* aDate, struct tm* aTm) |
|
137 { |
|
138 if (aDate->year-1900 != aTm->tm_year) |
|
139 return (aDate->year-1900-aTm->tm_year); |
|
140 if (aDate->month-1 != aTm->tm_mon) |
|
141 return (aDate->month-1-aTm->tm_mon); |
|
142 return (aDate->day - aTm->tm_mday); |
|
143 } |
|
144 |
|
145 /* |
|
146 * 4.1 Rule 1 Tests |
|
147 * |
|
148 * "No valid value for current date will cause any interruption in operation" |
|
149 * |
|
150 */ |
|
151 |
|
152 testpair data_4_1[14] = { |
|
153 {{ 31,12,1998 } , { 1, 1, 1999 } }, |
|
154 {{ 27, 2,1999 } , { 28, 2, 1999 } }, |
|
155 {{ 28, 2,1999 } , { 1, 3, 1999 } }, |
|
156 {{ 31, 8,1999 } , { 1, 9, 1999 } }, |
|
157 {{ 8, 9,1999 } , { 9, 9, 1999 } }, |
|
158 {{ 9, 9,1999 } , { 10, 9, 1999 } }, |
|
159 {{ 31,12,1999 } , { 1, 1, 2000 } }, |
|
160 {{ 27, 2,2000 } , { 28, 2, 2000 } }, |
|
161 {{ 28, 2,2000 } , { 29, 2, 2000 } }, |
|
162 {{ 29, 2,2000 } , { 1, 3, 2000 } }, |
|
163 {{ 31,12,2000 } , { 1, 1, 2001 } }, |
|
164 {{ 28, 2,2001 } , { 1, 3, 2001 } }, |
|
165 {{ 28, 2,2004 } , { 29, 2, 2004 } }, |
|
166 {{ 29, 2,2004 } , { 1, 3, 2004 } } |
|
167 }; |
|
168 |
|
169 /** |
|
170 @SYMTestCaseID SYSLIB-STDLIB-CT-1043 |
|
171 @SYMTestCaseDesc Tests for standard date boundaries |
|
172 @SYMTestPriority High |
|
173 @SYMTestActions Tests for standard date format |
|
174 @SYMTestExpectedResults Test must not fail |
|
175 @SYMREQ REQ0000 |
|
176 */ |
|
177 void tests_4_1() |
|
178 { |
|
179 int i; |
|
180 testdate* from_dp; |
|
181 testdate* to_dp; |
|
182 char frombuf[80]; |
|
183 char tobuf[80]; |
|
184 struct tm workdate; |
|
185 |
|
186 printf("\n4.1 Rule 1 Tests\n\n"); |
|
187 printf("4.1.1.1 Standard Date Boundaries\n\n"); |
|
188 for (i=0; i<14; i++) |
|
189 { |
|
190 from_dp=&data_4_1[i].input; |
|
191 to_dp=&data_4_1[i].result; |
|
192 |
|
193 format_testdate(from_dp, frombuf); |
|
194 format_testdate(to_dp, tobuf); |
|
195 printf("%-2d From %-14s to %-14s ", i+1, frombuf, tobuf); |
|
196 |
|
197 tm_from_testdate(&workdate, from_dp); |
|
198 if (compare_testdate_tm(from_dp, &workdate) != 0) |
|
199 failed("test_4_1: invalid from date"); |
|
200 |
|
201 workdate.tm_mday += 1; /* move the time on by one day */ |
|
202 |
|
203 normalize_tm(&workdate); |
|
204 if (compare_testdate_tm(to_dp, &workdate) != 0) |
|
205 { |
|
206 printf("*** FAILED\n"); |
|
207 failures++; |
|
208 } |
|
209 else |
|
210 printf("PASSED\n"); |
|
211 } |
|
212 |
|
213 } |
|
214 |
|
215 /* |
|
216 * 4.2 Rule 2 Tests (incorporating Rule 4 Tests) |
|
217 * |
|
218 * "All manipulations of date or time related data will produce the required results for |
|
219 * all valid date values prior to, during and after Year 2000" |
|
220 * |
|
221 * "Year 2000 must be recognised as a leap year" |
|
222 * |
|
223 */ |
|
224 |
|
225 testdate data_4_2_1[19] = { |
|
226 { 31, 12, 1998 }, |
|
227 { 1, 3, 1999 }, |
|
228 { 27, 2, 2000 }, |
|
229 { 31, 12, 2000 }, |
|
230 { 28, 2, 2004 }, |
|
231 { 1, 1, 1999 }, |
|
232 { 9, 9, 1999 }, |
|
233 { 28, 2, 2000 }, |
|
234 { 1, 1, 2001 }, |
|
235 { 29, 2, 2004 }, |
|
236 { 27, 2, 1999 }, |
|
237 { 31, 12, 1999 }, |
|
238 { 29, 2, 2000 }, |
|
239 { 28, 2, 2000 }, |
|
240 { 1, 3, 2004 }, |
|
241 { 28, 2, 1999 }, |
|
242 { 1, 1, 2000 }, |
|
243 { 1, 3, 2000 }, |
|
244 { 1, 3, 2001 } |
|
245 }; |
|
246 |
|
247 void tests_4_2_1() |
|
248 { |
|
249 int i; |
|
250 testdate* from_dp; |
|
251 char frombuf[80]; |
|
252 struct tm workdate; |
|
253 |
|
254 printf("\n4.2 Rule 2 Tests (incorporating Rule 4 Tests)\n\n"); |
|
255 printf("4.2.1 Valid Dates\n\n"); |
|
256 for (i=0; i<19; i++) |
|
257 { |
|
258 from_dp=&data_4_2_1[i]; |
|
259 |
|
260 format_testdate(from_dp, frombuf); |
|
261 printf("%-2d Valid date %-14s ", i+1, frombuf); |
|
262 |
|
263 tm_from_testdate(&workdate, from_dp); |
|
264 if (compare_testdate_tm(from_dp, &workdate) != 0) |
|
265 { |
|
266 printf("*** FAILED\n"); |
|
267 failures++; |
|
268 } |
|
269 else |
|
270 printf("PASSED\n"); |
|
271 } |
|
272 } |
|
273 |
|
274 testdate data_4_2_2[5] = { |
|
275 { 31, 4, 1998 }, |
|
276 { 30, 2, 2000 }, |
|
277 { 29, 2, 2001 }, |
|
278 { 29, 2, 1999 }, |
|
279 { 30, 2, 2004 } |
|
280 }; |
|
281 |
|
282 void tests_4_2_2() |
|
283 { |
|
284 int i; |
|
285 testdate* from_dp; |
|
286 char frombuf[80]; |
|
287 struct tm workdate; |
|
288 |
|
289 printf("\n4.2.2 Invalid Dates\n\n"); |
|
290 for (i=0; i<5; i++) |
|
291 { |
|
292 from_dp=&data_4_2_2[i]; |
|
293 |
|
294 format_testdate(from_dp, frombuf); |
|
295 printf("%-2d Invalid date %-14s ", i+1, frombuf); |
|
296 |
|
297 tm_from_testdate(&workdate, from_dp); |
|
298 if (compare_testdate_tm(from_dp, &workdate) == 0) |
|
299 { |
|
300 printf("*** FAILED\n"); |
|
301 failures++; |
|
302 } |
|
303 else |
|
304 printf("PASSED\n"); |
|
305 } |
|
306 } |
|
307 |
|
308 testint data_4_2_4[3] = { |
|
309 { { 31, 12, 2000 }, 366 }, |
|
310 { { 31, 12, 1999 }, 365 }, |
|
311 { { 31, 12, 2004 }, 366 } |
|
312 }; |
|
313 |
|
314 void tests_4_2_4() |
|
315 { |
|
316 int i; |
|
317 testdate* from_dp; |
|
318 char frombuf[80]; |
|
319 struct tm workdate; |
|
320 |
|
321 printf("\n4.2.4 Year Lengths\n\n"); |
|
322 for (i=0; i<3; i++) |
|
323 { |
|
324 from_dp=&data_4_2_4[i].input; |
|
325 |
|
326 format_testdate(from_dp, frombuf); |
|
327 printf("%-2d Yearday of %-14s == %d ", i+1, frombuf, data_4_2_4[i].result); |
|
328 |
|
329 tm_from_testdate(&workdate, from_dp); |
|
330 if (workdate.tm_yday+1 != data_4_2_4[i].result) |
|
331 { |
|
332 printf("*** FAILED\n"); |
|
333 failures++; |
|
334 } |
|
335 else |
|
336 printf("PASSED\n"); |
|
337 } |
|
338 } |
|
339 |
|
340 testint data_4_2_7[14] = { |
|
341 { { 1, 1, 1900 }, 1 }, // not supported |
|
342 { { 28, 2, 1900 }, 3 }, // not supported |
|
343 { { 1, 3, 1900 }, 4 }, // not supported |
|
344 { { 28, 2, 1999 }, 0 }, |
|
345 { { 1, 3, 1999 }, 1 }, |
|
346 { { 31, 12, 1999 }, 5 }, |
|
347 { { 1, 1, 2000 }, 6 }, |
|
348 { { 28, 2, 2000 }, 1 }, |
|
349 { { 29, 2, 2000 }, 2 }, |
|
350 { { 1, 3, 2000 }, 3 }, |
|
351 { { 1, 1, 2001 }, 1 }, |
|
352 { { 28, 2, 2004 }, 6 }, |
|
353 { { 29, 2, 2004 }, 0 }, |
|
354 { { 1, 3, 2004 }, 1 } |
|
355 }; |
|
356 |
|
357 void tests_4_2_7() |
|
358 { |
|
359 int i; |
|
360 testdate* from_dp; |
|
361 char frombuf[80]; |
|
362 struct tm workdate; |
|
363 |
|
364 printf("\n4.2.7 Calculation of days of the week from dates\n\n"); |
|
365 for (i=3; i<14; i++) |
|
366 { |
|
367 from_dp=&data_4_2_7[i].input; |
|
368 |
|
369 format_testdate(from_dp, frombuf); |
|
370 printf("%-2d %-14s == %-10s ", i+1, frombuf, tmdaynames[data_4_2_7[i].result]); |
|
371 |
|
372 tm_from_testdate(&workdate, from_dp); |
|
373 if (compare_testdate_tm(from_dp, &workdate) != 0) |
|
374 failed("test_4_2_7: invalid from date"); |
|
375 |
|
376 if (workdate.tm_wday != data_4_2_7[i].result) |
|
377 { |
|
378 printf("*** FAILED (%d %s)\n", workdate.tm_wday, tmdaynames[workdate.tm_wday]); |
|
379 failures++; |
|
380 } |
|
381 else |
|
382 printf("PASSED\n"); |
|
383 } |
|
384 } |
|
385 |
|
386 void do_all_tests() |
|
387 { |
|
388 time_t now = time(0); |
|
389 failures=0; |
|
390 |
|
391 tests_4_1(); |
|
392 tests_4_2_1(); |
|
393 tests_4_2_2(); |
|
394 tests_4_2_4(); |
|
395 tests_4_2_7(); |
|
396 |
|
397 if (failures != 0) |
|
398 printf("\n\n NOT YEAR 2000 COMPLIANT\n\n"); |
|
399 else |
|
400 printf("\n\n ALL TESTS PASSED - YEAR 2000 COMPLIANT\n\n"); |
|
401 |
|
402 printf("Test run dated: %s", ctime(&now)); |
|
403 } |
|
404 |
|
405 int main() |
|
406 { |
|
407 int fd; |
|
408 |
|
409 do_all_tests(); |
|
410 |
|
411 /* Now repeat the tests into a log file */ |
|
412 |
|
413 fd=open("c:/stdlib_y2k.txt", O_WRONLY+O_CREAT+O_TRUNC, 0); |
|
414 if (fd<0) |
|
415 { |
|
416 printf("unable to create test result file\n"); |
|
417 return -1; |
|
418 } |
|
419 |
|
420 setbuf(stderr, NULL); |
|
421 dup2(fd, fileno(stderr)); /* redirect stderr */ |
|
422 setbuf(stdout, NULL); |
|
423 dup2(fd, fileno(stdout)); /* redirect stdout */ |
|
424 close(fd); |
|
425 fclose(stdin); |
|
426 |
|
427 do_all_tests(); |
|
428 |
|
429 fflush(stdout); |
|
430 return 0; |
|
431 } |