michael@0: var completed = false; michael@0: var testcases; michael@0: var tc = 0; michael@0: michael@0: SECTION = ""; michael@0: VERSION = ""; michael@0: BUGNUMBER = ""; michael@0: EXCLUDE = ""; michael@0: BUGNUMBER = ""; michael@0: michael@0: michael@0: TZ_DIFF = -8; michael@0: michael@0: var TT = ""; michael@0: var TT_ = ""; michael@0: var BR = ""; michael@0: var NBSP = " "; michael@0: var CR = "\n"; michael@0: var FONT = ""; michael@0: var FONT_ = ""; michael@0: var FONT_RED = ""; michael@0: var FONT_GREEN = ""; michael@0: var B = ""; michael@0: var B_ = "" michael@0: var H2 = ""; michael@0: var H2_ = ""; michael@0: var HR = ""; michael@0: var DEBUG = false; michael@0: michael@0: michael@0: var PASSED = " PASSED!" michael@0: var FAILED = " FAILED! expected: "; michael@0: function test() { michael@0: for ( tc=0; tc < testcases.length; tc++ ) { michael@0: testcases[tc].passed = writeTestCaseResult( michael@0: testcases[tc].expect, michael@0: testcases[tc].actual, michael@0: testcases[tc].description +" = "+ michael@0: testcases[tc].actual ); michael@0: michael@0: testcases[tc].reason += ( testcases[tc].passed ) ? "" : "wrong value "; michael@0: } michael@0: stopTest(); michael@0: return ( testcases ); michael@0: } michael@0: michael@0: function TestCase( n, d, e, a ) { michael@0: this.name = n; michael@0: this.description = d; michael@0: this.expect = e; michael@0: this.actual = a; michael@0: this.passed = true; michael@0: this.reason = ""; michael@0: this.bugnumber = BUGNUMBER; michael@0: michael@0: this.passed = getTestCaseResult( this.expect, this.actual ); michael@0: if ( DEBUG ) { michael@0: print( "added " + this.description ); michael@0: } michael@0: } michael@0: function startTest() { michael@0: // JavaScript 1.3 is supposed to be compliant ecma version 1.0 michael@0: if ( VERSION == "ECMA_1" ) { michael@0: version ( "130" ); michael@0: } michael@0: if ( VERSION == "JS_13" ) { michael@0: version ( "130" ); michael@0: } michael@0: if ( VERSION == "JS_12" ) { michael@0: version ( "120" ); michael@0: } michael@0: if ( VERSION == "JS_11" ) { michael@0: version ( "110" ); michael@0: } michael@0: // for ecma version 2.0, we will leave the javascript version to michael@0: // the default ( for now ). michael@0: writeHeaderToLog( SECTION + " "+ TITLE); michael@0: testcases = new Array(); michael@0: tc = 0; michael@0: michael@0: } michael@0: function getTestCaseResult( expect, actual ) { michael@0: // because ( NaN == NaN ) always returns false, need to do michael@0: // a special compare to see if we got the right result. michael@0: if ( actual != actual ) { michael@0: if ( typeof actual == "object" ) { michael@0: actual = "NaN object"; michael@0: } else { michael@0: actual = "NaN number"; michael@0: } michael@0: } michael@0: if ( expect != expect ) { michael@0: if ( typeof expect == "object" ) { michael@0: expect = "NaN object"; michael@0: } else { michael@0: expect = "NaN number"; michael@0: } michael@0: } michael@0: michael@0: var passed = ( expect == actual ) ? true : false; michael@0: michael@0: // if both objects are numbers michael@0: // need to replace w/ IEEE standard for rounding michael@0: if ( !passed michael@0: && typeof(actual) == "number" michael@0: && typeof(expect) == "number" michael@0: ) { michael@0: if ( Math.abs(actual-expect) < 0.0000001 ) { michael@0: passed = true; michael@0: } michael@0: } michael@0: michael@0: // verify type is the same michael@0: if ( typeof(expect) != typeof(actual) ) { michael@0: passed = false; michael@0: } michael@0: michael@0: return passed; michael@0: } michael@0: function writeTestCaseResult( expect, actual, string ) { michael@0: var passed = getTestCaseResult( expect, actual ); michael@0: writeFormattedResult( expect, actual, string, passed ); michael@0: return passed; michael@0: } michael@0: function writeFormattedResult( expect, actual, string, passed ) { michael@0: var s = TT + string ; michael@0: michael@0: for ( k = 0; michael@0: k < (60 - string.length >= 0 ? 60 - string.length : 5) ; michael@0: k++ ) { michael@0: } michael@0: michael@0: s += B ; michael@0: s += ( passed ) ? FONT_GREEN + NBSP + PASSED : FONT_RED + NBSP + FAILED + expect + TT_ ; michael@0: michael@0: print( s + FONT_ + B_ + TT_ ); michael@0: michael@0: return passed; michael@0: } michael@0: michael@0: function writeHeaderToLog( string ) { michael@0: print( H2 + string + H2_ ); michael@0: } michael@0: function stopTest() michael@0: { michael@0: var sizeTag = "<#TEST CASES SIZE>"; michael@0: var doneTag = "<#TEST CASES DONE>"; michael@0: var beginTag = "<#TEST CASE "; michael@0: var endTag = ">"; michael@0: michael@0: print(sizeTag); michael@0: print(testcases.length); michael@0: for (tc = 0; tc < testcases.length; tc++) michael@0: { michael@0: print(beginTag + 'PASSED' + endTag); michael@0: print(testcases[tc].passed); michael@0: print(beginTag + 'NAME' + endTag); michael@0: print(testcases[tc].name); michael@0: print(beginTag + 'EXPECTED' + endTag); michael@0: print(testcases[tc].expect); michael@0: print(beginTag + 'ACTUAL' + endTag); michael@0: print(testcases[tc].actual); michael@0: print(beginTag + 'DESCRIPTION' + endTag); michael@0: print(testcases[tc].description); michael@0: print(beginTag + 'REASON' + endTag); michael@0: print(( testcases[tc].passed ) ? "" : "wrong value "); michael@0: print(beginTag + 'BUGNUMBER' + endTag); michael@0: print( BUGNUMBER ); michael@0: } michael@0: print(doneTag); michael@0: print( HR ); michael@0: gc(); michael@0: } michael@0: function getFailedCases() { michael@0: for ( var i = 0; i < testcases.length; i++ ) { michael@0: if ( ! testcases[i].passed ) { michael@0: print( testcases[i].description +" = " +testcases[i].actual +" expected: "+ testcases[i].expect ); michael@0: } michael@0: } michael@0: } michael@0: function err( msg, page, line ) { michael@0: testcases[tc].actual = "error"; michael@0: testcases[tc].reason = msg; michael@0: writeTestCaseResult( testcases[tc].expect, michael@0: testcases[tc].actual, michael@0: testcases[tc].description +" = "+ testcases[tc].actual + michael@0: ": " + testcases[tc].reason ); michael@0: stopTest(); michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Type Conversion functions used by Type Conversion michael@0: * michael@0: */ michael@0: michael@0: michael@0: michael@0: /* michael@0: * Date functions used by tests in Date suite michael@0: * michael@0: */ michael@0: var msPerDay = 86400000; michael@0: var HoursPerDay = 24; michael@0: var MinutesPerHour = 60; michael@0: var SecondsPerMinute = 60; michael@0: var msPerSecond = 1000; michael@0: var msPerMinute = 60000; // msPerSecond * SecondsPerMinute michael@0: var msPerHour = 3600000; // msPerMinute * MinutesPerHour michael@0: michael@0: var TIME_1970 = 0; michael@0: var TIME_2000 = 946684800000; michael@0: var TIME_1900 = -2208988800000; michael@0: michael@0: function Day( t ) { michael@0: return ( Math.floor(t/msPerDay ) ); michael@0: } michael@0: function DaysInYear( y ) { michael@0: if ( y % 4 != 0 ) { michael@0: return 365; michael@0: } michael@0: if ( (y % 4 == 0) && (y % 100 != 0) ) { michael@0: return 366; michael@0: } michael@0: if ( (y % 100 == 0) && (y % 400 != 0) ) { michael@0: return 365; michael@0: } michael@0: if ( (y % 400 == 0) ){ michael@0: return 366; michael@0: } else { michael@0: return "ERROR: DaysInYear(" + y + ") case not covered"; michael@0: } michael@0: } michael@0: function TimeInYear( y ) { michael@0: return ( DaysInYear(y) * msPerDay ); michael@0: } michael@0: function DayNumber( t ) { michael@0: return ( Math.floor( t / msPerDay ) ); michael@0: } michael@0: function TimeWithinDay( t ) { michael@0: if ( t < 0 ) { michael@0: return ( (t % msPerDay) + msPerDay ); michael@0: } else { michael@0: return ( t % msPerDay ); michael@0: } michael@0: } michael@0: function YearNumber( t ) { michael@0: } michael@0: function TimeFromYear( y ) { michael@0: return ( msPerDay * DayFromYear(y) ); michael@0: } michael@0: function DayFromYear( y ) { michael@0: return ( 365*(y-1970) + michael@0: Math.floor((y-1969)/4) - michael@0: Math.floor((y-1901)/100) + michael@0: Math.floor((y-1601)/400) ); michael@0: } michael@0: function InLeapYear( t ) { michael@0: if ( DaysInYear(YearFromTime(t)) == 365 ) { michael@0: return 0; michael@0: } michael@0: if ( DaysInYear(YearFromTime(t)) == 366 ) { michael@0: return 1; michael@0: } else { michael@0: return "ERROR: InLeapYear("+t+") case not covered"; michael@0: } michael@0: } michael@0: function YearFromTime( t ) { michael@0: t = Number( t ); michael@0: var sign = ( t < 0 ) ? -1 : 1; michael@0: var year = ( sign < 0 ) ? 1969 : 1970; michael@0: for ( var timeToTimeZero = t; ; ) { michael@0: // subtract the current year's time from the time that's left. michael@0: timeToTimeZero -= sign * TimeInYear(year) michael@0: michael@0: // if there's less than the current year's worth of time left, then break. michael@0: if ( sign < 0 ) { michael@0: if ( sign * timeToTimeZero <= 0 ) { michael@0: break; michael@0: } else { michael@0: year += sign; michael@0: } michael@0: } else { michael@0: if ( sign * timeToTimeZero < 0 ) { michael@0: break; michael@0: } else { michael@0: year += sign; michael@0: } michael@0: } michael@0: } michael@0: return ( year ); michael@0: } michael@0: function MonthFromTime( t ) { michael@0: // i know i could use switch but i'd rather not until it's part of ECMA michael@0: var day = DayWithinYear( t ); michael@0: var leap = InLeapYear(t); michael@0: michael@0: if ( (0 <= day) && (day < 31) ) { michael@0: return 0; michael@0: } michael@0: if ( (31 <= day) && (day < (59+leap)) ) { michael@0: return 1; michael@0: } michael@0: if ( ((59+leap) <= day) && (day < (90+leap)) ) { michael@0: return 2; michael@0: } michael@0: if ( ((90+leap) <= day) && (day < (120+leap)) ) { michael@0: return 3; michael@0: } michael@0: if ( ((120+leap) <= day) && (day < (151+leap)) ) { michael@0: return 4; michael@0: } michael@0: if ( ((151+leap) <= day) && (day < (181+leap)) ) { michael@0: return 5; michael@0: } michael@0: if ( ((181+leap) <= day) && (day < (212+leap)) ) { michael@0: return 6; michael@0: } michael@0: if ( ((212+leap) <= day) && (day < (243+leap)) ) { michael@0: return 7; michael@0: } michael@0: if ( ((243+leap) <= day) && (day < (273+leap)) ) { michael@0: return 8; michael@0: } michael@0: if ( ((273+leap) <= day) && (day < (304+leap)) ) { michael@0: return 9; michael@0: } michael@0: if ( ((304+leap) <= day) && (day < (334+leap)) ) { michael@0: return 10; michael@0: } michael@0: if ( ((334+leap) <= day) && (day < (365+leap)) ) { michael@0: return 11; michael@0: } else { michael@0: return "ERROR: MonthFromTime("+t+") not known"; michael@0: } michael@0: } michael@0: function DayWithinYear( t ) { michael@0: return( Day(t) - DayFromYear(YearFromTime(t))); michael@0: } michael@0: function DateFromTime( t ) { michael@0: var day = DayWithinYear(t); michael@0: var month = MonthFromTime(t); michael@0: michael@0: if ( month == 0 ) { michael@0: return ( day + 1 ); michael@0: } michael@0: if ( month == 1 ) { michael@0: return ( day - 30 ); michael@0: } michael@0: if ( month == 2 ) { michael@0: return ( day - 58 - InLeapYear(t) ); michael@0: } michael@0: if ( month == 3 ) { michael@0: return ( day - 89 - InLeapYear(t)); michael@0: } michael@0: if ( month == 4 ) { michael@0: return ( day - 119 - InLeapYear(t)); michael@0: } michael@0: if ( month == 5 ) { michael@0: return ( day - 150- InLeapYear(t)); michael@0: } michael@0: if ( month == 6 ) { michael@0: return ( day - 180- InLeapYear(t)); michael@0: } michael@0: if ( month == 7 ) { michael@0: return ( day - 211- InLeapYear(t)); michael@0: } michael@0: if ( month == 8 ) { michael@0: return ( day - 242- InLeapYear(t)); michael@0: } michael@0: if ( month == 9 ) { michael@0: return ( day - 272- InLeapYear(t)); michael@0: } michael@0: if ( month == 10 ) { michael@0: return ( day - 303- InLeapYear(t)); michael@0: } michael@0: if ( month == 11 ) { michael@0: return ( day - 333- InLeapYear(t)); michael@0: } michael@0: michael@0: return ("ERROR: DateFromTime("+t+") not known" ); michael@0: } michael@0: function WeekDay( t ) { michael@0: var weekday = (Day(t)+4) % 7; michael@0: return( weekday < 0 ? 7 + weekday : weekday ); michael@0: } michael@0: michael@0: // missing daylight savins time adjustment michael@0: michael@0: function HourFromTime( t ) { michael@0: var h = Math.floor( t / msPerHour ) % HoursPerDay; michael@0: return ( (h<0) ? HoursPerDay + h : h ); michael@0: } michael@0: function MinFromTime( t ) { michael@0: var min = Math.floor( t / msPerMinute ) % MinutesPerHour; michael@0: return( ( min < 0 ) ? MinutesPerHour + min : min ); michael@0: } michael@0: function SecFromTime( t ) { michael@0: var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute; michael@0: return ( (sec < 0 ) ? SecondsPerMinute + sec : sec ); michael@0: } michael@0: function msFromTime( t ) { michael@0: var ms = t % msPerSecond; michael@0: return ( (ms < 0 ) ? msPerSecond + ms : ms ); michael@0: } michael@0: function LocalTZA() { michael@0: return ( TZ_DIFF * msPerHour ); michael@0: } michael@0: function UTC( t ) { michael@0: return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) ); michael@0: } michael@0: function DaylightSavingTA( t ) { michael@0: t = t - LocalTZA(); michael@0: michael@0: var dst_start = GetFirstSundayInApril(t) + 2*msPerHour; michael@0: var dst_end = GetLastSundayInOctober(t)+ 2*msPerHour; michael@0: michael@0: if ( t >= dst_start && t < dst_end ) { michael@0: return msPerHour; michael@0: } else { michael@0: return 0; michael@0: } michael@0: michael@0: // Daylight Savings Time starts on the first Sunday in April at 2:00AM in michael@0: // PST. Other time zones will need to override this function. michael@0: michael@0: print( new Date( UTC(dst_start + LocalTZA())) ); michael@0: michael@0: return UTC(dst_start + LocalTZA()); michael@0: } michael@0: function GetFirstSundayInApril( t ) { michael@0: var year = YearFromTime(t); michael@0: var leap = InLeapYear(t); michael@0: michael@0: var april = TimeFromYear(year) + TimeInMonth(0, leap) + TimeInMonth(1,leap) + michael@0: TimeInMonth(2,leap); michael@0: michael@0: for ( var first_sunday = april; WeekDay(first_sunday) > 0; michael@0: first_sunday += msPerDay ) michael@0: { michael@0: ; michael@0: } michael@0: michael@0: return first_sunday; michael@0: } michael@0: function GetLastSundayInOctober( t ) { michael@0: var year = YearFromTime(t); michael@0: var leap = InLeapYear(t); michael@0: michael@0: for ( var oct = TimeFromYear(year), m = 0; m < 9; m++ ) { michael@0: oct += TimeInMonth(m, leap); michael@0: } michael@0: for ( var last_sunday = oct + 30*msPerDay; WeekDay(last_sunday) > 0; michael@0: last_sunday -= msPerDay ) michael@0: { michael@0: ; michael@0: } michael@0: return last_sunday; michael@0: } michael@0: function LocalTime( t ) { michael@0: return ( t + LocalTZA() + DaylightSavingTA(t) ); michael@0: } michael@0: function MakeTime( hour, min, sec, ms ) { michael@0: if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) { michael@0: return Number.NaN; michael@0: } michael@0: michael@0: hour = ToInteger(hour); michael@0: min = ToInteger( min); michael@0: sec = ToInteger( sec); michael@0: ms = ToInteger( ms ); michael@0: michael@0: return( (hour*msPerHour) + (min*msPerMinute) + michael@0: (sec*msPerSecond) + ms ); michael@0: } michael@0: function MakeDay( year, month, date ) { michael@0: if ( isNaN(year) || isNaN(month) || isNaN(date) ) { michael@0: return Number.NaN; michael@0: } michael@0: year = ToInteger(year); michael@0: month = ToInteger(month); michael@0: date = ToInteger(date ); michael@0: michael@0: var sign = ( year < 1970 ) ? -1 : 1; michael@0: var t = ( year < 1970 ) ? 1 : 0; michael@0: var y = ( year < 1970 ) ? 1969 : 1970; michael@0: michael@0: var result5 = year + Math.floor( month/12 ); michael@0: var result6 = month % 12; michael@0: michael@0: if ( year < 1970 ) { michael@0: for ( y = 1969; y >= year; y += sign ) { michael@0: t += sign * TimeInYear(y); michael@0: } michael@0: } else { michael@0: for ( y = 1970 ; y < year; y += sign ) { michael@0: t += sign * TimeInYear(y); michael@0: } michael@0: } michael@0: michael@0: var leap = InLeapYear( t ); michael@0: michael@0: for ( var m = 0; m < month; m++ ) { michael@0: t += TimeInMonth( m, leap ); michael@0: } michael@0: michael@0: if ( YearFromTime(t) != result5 ) { michael@0: return Number.NaN; michael@0: } michael@0: if ( MonthFromTime(t) != result6 ) { michael@0: return Number.NaN; michael@0: } michael@0: if ( DateFromTime(t) != 1 ) { michael@0: return Number.NaN; michael@0: } michael@0: michael@0: return ( (Day(t)) + date - 1 ); michael@0: } michael@0: function TimeInMonth( month, leap ) { michael@0: // september april june november michael@0: // jan 0 feb 1 mar 2 apr 3 may 4 june 5 jul 6 michael@0: // aug 7 sep 8 oct 9 nov 10 dec 11 michael@0: michael@0: if ( month == 3 || month == 5 || month == 8 || month == 10 ) { michael@0: return ( 30*msPerDay ); michael@0: } michael@0: michael@0: // all the rest michael@0: if ( month == 0 || month == 2 || month == 4 || month == 6 || michael@0: month == 7 || month == 9 || month == 11 ) { michael@0: return ( 31*msPerDay ); michael@0: } michael@0: michael@0: // save february michael@0: return ( (leap == 0) ? 28*msPerDay : 29*msPerDay ); michael@0: } michael@0: function MakeDate( day, time ) { michael@0: if ( day == Number.POSITIVE_INFINITY || michael@0: day == Number.NEGATIVE_INFINITY || michael@0: day == Number.NaN ) { michael@0: return Number.NaN; michael@0: } michael@0: if ( time == Number.POSITIVE_INFINITY || michael@0: time == Number.POSITIVE_INFINITY || michael@0: day == Number.NaN) { michael@0: return Number.NaN; michael@0: } michael@0: return ( day * msPerDay ) + time; michael@0: } michael@0: function TimeClip( t ) { michael@0: if ( isNaN( t ) ) { michael@0: return ( Number.NaN ); michael@0: } michael@0: if ( Math.abs( t ) > 8.64e15 ) { michael@0: return ( Number.NaN ); michael@0: } michael@0: michael@0: return ( ToInteger( t ) ); michael@0: } michael@0: function ToInteger( t ) { michael@0: t = Number( t ); michael@0: michael@0: if ( isNaN( t ) ){ michael@0: return ( Number.NaN ); michael@0: } michael@0: if ( t == 0 || t == -0 || michael@0: t == Number.POSITIVE_INFINITY || t == Number.NEGATIVE_INFINITY ) { michael@0: return 0; michael@0: } michael@0: michael@0: var sign = ( t < 0 ) ? -1 : 1; michael@0: michael@0: return ( sign * Math.floor( Math.abs( t ) ) ); michael@0: } michael@0: function Enumerate ( o ) { michael@0: var properties = new Array(); michael@0: for ( p in o ) { michael@0: properties[ properties.length ] = new Array( p, o[p] ); michael@0: } michael@0: return properties; michael@0: } michael@0: function AddTestCase( description, expect, actual ) { michael@0: testcases[tc++] = new TestCase( SECTION, description, expect, actual ); michael@0: } michael@0: function getFailedCases() { michael@0: for ( var i = 0; i < testcases.length; i++ ) { michael@0: if ( ! testcases[i].passed ) { michael@0: print( testcases[i].description +" = " +testcases[i].actual +" expected: "+ testcases[i].expect ); michael@0: } michael@0: } michael@0: }