sl@0: /* sl@0: * Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * Year 2000 compliance tests for STDLIB sl@0: * sl@0: * sl@0: */ sl@0: sl@0: sl@0: sl@0: #include /* definition of exit() */ sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include /* timeval, gettimeofday */ sl@0: sl@0: int failures=0; sl@0: void failed(char* reason) sl@0: { sl@0: printf("\nFAILURE >>>%s\n", reason); sl@0: failures++; sl@0: } sl@0: sl@0: sl@0: sl@0: typedef struct { sl@0: int day; /* 1-31 */ sl@0: int month; /* 1-12 */ sl@0: int year; /* 1970-2050 */ sl@0: } testdate; sl@0: sl@0: char* testmonths[14] = { sl@0: "invalid_0", sl@0: "Jan", "Feb", "March", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec", sl@0: "invalid_13" sl@0: }; sl@0: sl@0: char* tmdaynames[8] = { sl@0: "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", sl@0: "invalid_7" sl@0: }; sl@0: sl@0: /* Format a testdate to match the Y2K document sl@0: */ sl@0: void format_testdate(testdate* aDate, char* aBuffer) sl@0: { sl@0: char* th="th"; sl@0: if (aDate->day==1 || aDate->day==21 || aDate->day==31) sl@0: th="st"; sl@0: if (aDate->day==2 || aDate->day==22) sl@0: th="nd"; sl@0: sl@0: sprintf(aBuffer, "%d%s %s %d", aDate->day, th, testmonths[aDate->month], aDate->year); sl@0: } sl@0: sl@0: typedef struct { sl@0: testdate input; /* for conversion to seconds */ sl@0: testdate result; /* correct value */ sl@0: } testpair; sl@0: sl@0: typedef struct { sl@0: testdate input; /* for conversion to seconds */ sl@0: int result; /* correct value */ sl@0: } testint; sl@0: sl@0: /* MAJOR TEST FUNCTIONALITY - READ THIS CAREFULLY sl@0: * sl@0: * STDLIB date handling is done in terms of seconds since the "epoch", which was sl@0: * 00:00 on 1st January, 1970. The Y2K significant functionality consists solely of the sl@0: * routines which manipulate the struct tm data structure. sl@0: * sl@0: * time_t mktime (struct tm *brokentime) sl@0: * sl@0: * struct tm * gmtime (const time_t *time) sl@0: * struct tm * localtime (const time_t *time) sl@0: * sl@0: * The mktime conversion is always using a GMT date, so we'll ignore the localtime function for Y2K sl@0: * purposes. We also know that gmtime and localtime use the same underlying conversion function, sl@0: * one applying the relevant GMT offset on the way in. sl@0: * sl@0: * Y2K is only concerned with dates, so we will always use 12:00:00 ("High Noon") as the time sl@0: * of day. sl@0: */ sl@0: sl@0: void tm_from_testdate(struct tm* aTm, testdate* aDate) sl@0: { sl@0: time_t seconds; sl@0: struct tm setup; sl@0: struct tm* res; sl@0: sl@0: setup.tm_hour = 12; sl@0: setup.tm_min = 0; sl@0: setup.tm_sec = 0; sl@0: sl@0: setup.tm_mday = aDate->day; sl@0: setup.tm_mon = aDate->month - 1; /* struct tm uses 0-11 */ sl@0: setup.tm_year = aDate->year - 1900; /* struct tm uses years since 1900 */ sl@0: sl@0: seconds = mktime(&setup); sl@0: if (seconds != (time_t)(-1)) sl@0: { sl@0: res = gmtime(&seconds); sl@0: *aTm = *res; sl@0: return; sl@0: } sl@0: sl@0: /* unable to convert date */ sl@0: failed("tm_from_testdate: mktime failed"); sl@0: } sl@0: sl@0: void normalize_tm(struct tm* aTm) sl@0: { sl@0: time_t seconds = mktime(aTm); sl@0: if (seconds == (time_t)(-1)) sl@0: { sl@0: /* unable to convert date */ sl@0: failed("normalize_tm: mktime failed"); sl@0: } sl@0: return; sl@0: } sl@0: sl@0: int compare_testdate_tm(testdate* aDate, struct tm* aTm) sl@0: { sl@0: if (aDate->year-1900 != aTm->tm_year) sl@0: return (aDate->year-1900-aTm->tm_year); sl@0: if (aDate->month-1 != aTm->tm_mon) sl@0: return (aDate->month-1-aTm->tm_mon); sl@0: return (aDate->day - aTm->tm_mday); sl@0: } sl@0: sl@0: /* sl@0: * 4.1 Rule 1 Tests sl@0: * sl@0: * "No valid value for current date will cause any interruption in operation" sl@0: * sl@0: */ sl@0: sl@0: testpair data_4_1[14] = { sl@0: {{ 31,12,1998 } , { 1, 1, 1999 } }, sl@0: {{ 27, 2,1999 } , { 28, 2, 1999 } }, sl@0: {{ 28, 2,1999 } , { 1, 3, 1999 } }, sl@0: {{ 31, 8,1999 } , { 1, 9, 1999 } }, sl@0: {{ 8, 9,1999 } , { 9, 9, 1999 } }, sl@0: {{ 9, 9,1999 } , { 10, 9, 1999 } }, sl@0: {{ 31,12,1999 } , { 1, 1, 2000 } }, sl@0: {{ 27, 2,2000 } , { 28, 2, 2000 } }, sl@0: {{ 28, 2,2000 } , { 29, 2, 2000 } }, sl@0: {{ 29, 2,2000 } , { 1, 3, 2000 } }, sl@0: {{ 31,12,2000 } , { 1, 1, 2001 } }, sl@0: {{ 28, 2,2001 } , { 1, 3, 2001 } }, sl@0: {{ 28, 2,2004 } , { 29, 2, 2004 } }, sl@0: {{ 29, 2,2004 } , { 1, 3, 2004 } } sl@0: }; sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-STDLIB-CT-1043 sl@0: @SYMTestCaseDesc Tests for standard date boundaries sl@0: @SYMTestPriority High sl@0: @SYMTestActions Tests for standard date format sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ0000 sl@0: */ sl@0: void tests_4_1() sl@0: { sl@0: int i; sl@0: testdate* from_dp; sl@0: testdate* to_dp; sl@0: char frombuf[80]; sl@0: char tobuf[80]; sl@0: struct tm workdate; sl@0: sl@0: printf("\n4.1 Rule 1 Tests\n\n"); sl@0: printf("4.1.1.1 Standard Date Boundaries\n\n"); sl@0: for (i=0; i<14; i++) sl@0: { sl@0: from_dp=&data_4_1[i].input; sl@0: to_dp=&data_4_1[i].result; sl@0: sl@0: format_testdate(from_dp, frombuf); sl@0: format_testdate(to_dp, tobuf); sl@0: printf("%-2d From %-14s to %-14s ", i+1, frombuf, tobuf); sl@0: sl@0: tm_from_testdate(&workdate, from_dp); sl@0: if (compare_testdate_tm(from_dp, &workdate) != 0) sl@0: failed("test_4_1: invalid from date"); sl@0: sl@0: workdate.tm_mday += 1; /* move the time on by one day */ sl@0: sl@0: normalize_tm(&workdate); sl@0: if (compare_testdate_tm(to_dp, &workdate) != 0) sl@0: { sl@0: printf("*** FAILED\n"); sl@0: failures++; sl@0: } sl@0: else sl@0: printf("PASSED\n"); sl@0: } sl@0: sl@0: } sl@0: sl@0: /* sl@0: * 4.2 Rule 2 Tests (incorporating Rule 4 Tests) sl@0: * sl@0: * "All manipulations of date or time related data will produce the required results for sl@0: * all valid date values prior to, during and after Year 2000" sl@0: * sl@0: * "Year 2000 must be recognised as a leap year" sl@0: * sl@0: */ sl@0: sl@0: testdate data_4_2_1[19] = { sl@0: { 31, 12, 1998 }, sl@0: { 1, 3, 1999 }, sl@0: { 27, 2, 2000 }, sl@0: { 31, 12, 2000 }, sl@0: { 28, 2, 2004 }, sl@0: { 1, 1, 1999 }, sl@0: { 9, 9, 1999 }, sl@0: { 28, 2, 2000 }, sl@0: { 1, 1, 2001 }, sl@0: { 29, 2, 2004 }, sl@0: { 27, 2, 1999 }, sl@0: { 31, 12, 1999 }, sl@0: { 29, 2, 2000 }, sl@0: { 28, 2, 2000 }, sl@0: { 1, 3, 2004 }, sl@0: { 28, 2, 1999 }, sl@0: { 1, 1, 2000 }, sl@0: { 1, 3, 2000 }, sl@0: { 1, 3, 2001 } sl@0: }; sl@0: sl@0: void tests_4_2_1() sl@0: { sl@0: int i; sl@0: testdate* from_dp; sl@0: char frombuf[80]; sl@0: struct tm workdate; sl@0: sl@0: printf("\n4.2 Rule 2 Tests (incorporating Rule 4 Tests)\n\n"); sl@0: printf("4.2.1 Valid Dates\n\n"); sl@0: for (i=0; i<19; i++) sl@0: { sl@0: from_dp=&data_4_2_1[i]; sl@0: sl@0: format_testdate(from_dp, frombuf); sl@0: printf("%-2d Valid date %-14s ", i+1, frombuf); sl@0: sl@0: tm_from_testdate(&workdate, from_dp); sl@0: if (compare_testdate_tm(from_dp, &workdate) != 0) sl@0: { sl@0: printf("*** FAILED\n"); sl@0: failures++; sl@0: } sl@0: else sl@0: printf("PASSED\n"); sl@0: } sl@0: } sl@0: sl@0: testdate data_4_2_2[5] = { sl@0: { 31, 4, 1998 }, sl@0: { 30, 2, 2000 }, sl@0: { 29, 2, 2001 }, sl@0: { 29, 2, 1999 }, sl@0: { 30, 2, 2004 } sl@0: }; sl@0: sl@0: void tests_4_2_2() sl@0: { sl@0: int i; sl@0: testdate* from_dp; sl@0: char frombuf[80]; sl@0: struct tm workdate; sl@0: sl@0: printf("\n4.2.2 Invalid Dates\n\n"); sl@0: for (i=0; i<5; i++) sl@0: { sl@0: from_dp=&data_4_2_2[i]; sl@0: sl@0: format_testdate(from_dp, frombuf); sl@0: printf("%-2d Invalid date %-14s ", i+1, frombuf); sl@0: sl@0: tm_from_testdate(&workdate, from_dp); sl@0: if (compare_testdate_tm(from_dp, &workdate) == 0) sl@0: { sl@0: printf("*** FAILED\n"); sl@0: failures++; sl@0: } sl@0: else sl@0: printf("PASSED\n"); sl@0: } sl@0: } sl@0: sl@0: testint data_4_2_4[3] = { sl@0: { { 31, 12, 2000 }, 366 }, sl@0: { { 31, 12, 1999 }, 365 }, sl@0: { { 31, 12, 2004 }, 366 } sl@0: }; sl@0: sl@0: void tests_4_2_4() sl@0: { sl@0: int i; sl@0: testdate* from_dp; sl@0: char frombuf[80]; sl@0: struct tm workdate; sl@0: sl@0: printf("\n4.2.4 Year Lengths\n\n"); sl@0: for (i=0; i<3; i++) sl@0: { sl@0: from_dp=&data_4_2_4[i].input; sl@0: sl@0: format_testdate(from_dp, frombuf); sl@0: printf("%-2d Yearday of %-14s == %d ", i+1, frombuf, data_4_2_4[i].result); sl@0: sl@0: tm_from_testdate(&workdate, from_dp); sl@0: if (workdate.tm_yday+1 != data_4_2_4[i].result) sl@0: { sl@0: printf("*** FAILED\n"); sl@0: failures++; sl@0: } sl@0: else sl@0: printf("PASSED\n"); sl@0: } sl@0: } sl@0: sl@0: testint data_4_2_7[14] = { sl@0: { { 1, 1, 1900 }, 1 }, // not supported sl@0: { { 28, 2, 1900 }, 3 }, // not supported sl@0: { { 1, 3, 1900 }, 4 }, // not supported sl@0: { { 28, 2, 1999 }, 0 }, sl@0: { { 1, 3, 1999 }, 1 }, sl@0: { { 31, 12, 1999 }, 5 }, sl@0: { { 1, 1, 2000 }, 6 }, sl@0: { { 28, 2, 2000 }, 1 }, sl@0: { { 29, 2, 2000 }, 2 }, sl@0: { { 1, 3, 2000 }, 3 }, sl@0: { { 1, 1, 2001 }, 1 }, sl@0: { { 28, 2, 2004 }, 6 }, sl@0: { { 29, 2, 2004 }, 0 }, sl@0: { { 1, 3, 2004 }, 1 } sl@0: }; sl@0: sl@0: void tests_4_2_7() sl@0: { sl@0: int i; sl@0: testdate* from_dp; sl@0: char frombuf[80]; sl@0: struct tm workdate; sl@0: sl@0: printf("\n4.2.7 Calculation of days of the week from dates\n\n"); sl@0: for (i=3; i<14; i++) sl@0: { sl@0: from_dp=&data_4_2_7[i].input; sl@0: sl@0: format_testdate(from_dp, frombuf); sl@0: printf("%-2d %-14s == %-10s ", i+1, frombuf, tmdaynames[data_4_2_7[i].result]); sl@0: sl@0: tm_from_testdate(&workdate, from_dp); sl@0: if (compare_testdate_tm(from_dp, &workdate) != 0) sl@0: failed("test_4_2_7: invalid from date"); sl@0: sl@0: if (workdate.tm_wday != data_4_2_7[i].result) sl@0: { sl@0: printf("*** FAILED (%d %s)\n", workdate.tm_wday, tmdaynames[workdate.tm_wday]); sl@0: failures++; sl@0: } sl@0: else sl@0: printf("PASSED\n"); sl@0: } sl@0: } sl@0: sl@0: void do_all_tests() sl@0: { sl@0: time_t now = time(0); sl@0: failures=0; sl@0: sl@0: tests_4_1(); sl@0: tests_4_2_1(); sl@0: tests_4_2_2(); sl@0: tests_4_2_4(); sl@0: tests_4_2_7(); sl@0: sl@0: if (failures != 0) sl@0: printf("\n\n NOT YEAR 2000 COMPLIANT\n\n"); sl@0: else sl@0: printf("\n\n ALL TESTS PASSED - YEAR 2000 COMPLIANT\n\n"); sl@0: sl@0: printf("Test run dated: %s", ctime(&now)); sl@0: } sl@0: sl@0: int main() sl@0: { sl@0: int fd; sl@0: sl@0: do_all_tests(); sl@0: sl@0: /* Now repeat the tests into a log file */ sl@0: sl@0: fd=open("c:/stdlib_y2k.txt", O_WRONLY+O_CREAT+O_TRUNC, 0); sl@0: if (fd<0) sl@0: { sl@0: printf("unable to create test result file\n"); sl@0: return -1; sl@0: } sl@0: sl@0: setbuf(stderr, NULL); sl@0: dup2(fd, fileno(stderr)); /* redirect stderr */ sl@0: setbuf(stdout, NULL); sl@0: dup2(fd, fileno(stdout)); /* redirect stdout */ sl@0: close(fd); sl@0: fclose(stdin); sl@0: sl@0: do_all_tests(); sl@0: sl@0: fflush(stdout); sl@0: return 0; sl@0: }