1/* The contents of this file are subject to the Netscape Public 2 * License Version 1.1 (the "License"); you may not use this file 3 * except in compliance with the License. You may obtain a copy of 4 * the License at http://www.mozilla.org/NPL/ 5 * 6 * Software distributed under the License is distributed on an "AS 7 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 8 * implied. See the License for the specific language governing 9 * rights and limitations under the License. 10 * 11 * The Original Code is Mozilla Communicator client code, released March 12 * 31, 1998. 13 * 14 * The Initial Developer of the Original Code is Netscape Communications 15 * Corporation. Portions created by Netscape are 16 * Copyright (C) 1998 Netscape Communications Corporation. All 17 * Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 */ 22/* 23 * JavaScript shared functions file for running the tests in either 24 * stand-alone JavaScript engine. To run a test, first load this file, 25 * then load the test script. 26 */ 27 28var completed = false; 29var testcases; 30var tc = 0; 31 32SECTION = ""; 33VERSION = ""; 34BUGNUMBER = ""; 35 36/* 37 * constant strings 38 */ 39var GLOBAL = "[object global]"; 40var PASSED = " PASSED!" 41var FAILED = " FAILED! expected: "; 42 43var DEBUG = false; 44 45 46 47/* wrapper for test cas constructor that doesn't require the SECTION 48 * argument. 49 */ 50 51function AddTestCase( description, expect, actual ) { 52 testcases[tc++] = new TestCase( SECTION, description, expect, actual ); 53} 54 55/* 56 * TestCase constructor 57 * 58 */ 59 60function TestCase( n, d, e, a ) { 61 this.name = n; 62 this.description = d; 63 this.expect = e; 64 this.actual = a; 65 this.passed = true; 66 this.reason = ""; 67 this.bugnumber = BUGNUMBER; 68 69 this.passed = getTestCaseResult( this.expect, this.actual ); 70 if ( DEBUG ) { 71 writeLineToLog( "added " + this.description ); 72 } 73} 74 75/* 76 * Set up test environment. 77 * 78 */ 79function startTest() { 80 if ( version ) { 81 // JavaScript 1.3 is supposed to be compliant ecma version 1.0 82 if ( VERSION == "ECMA_1" ) { 83 version ( "130" ); 84 } 85 if ( VERSION == "JS_1.3" ) { 86 version ( "130" ); 87 } 88 if ( VERSION == "JS_1.2" ) { 89 version ( "120" ); 90 } 91 if ( VERSION == "JS_1.1" ) { 92 version ( "110" ); 93 } 94 // for ecma version 2.0, we will leave the javascript version to 95 // the default ( for now ). 96 } 97 98 // print out bugnumber 99 100 if ( BUGNUMBER ) { 101 writeLineToLog ("BUGNUMBER: " + BUGNUMBER ); 102 } 103 104 testcases = new Array(); 105 tc = 0; 106} 107 108 109function test() { 110 for ( tc=0; tc < testcases.length; tc++ ) { 111 testcases[tc].passed = writeTestCaseResult( 112 testcases[tc].expect, 113 testcases[tc].actual, 114 testcases[tc].description +" = "+ testcases[tc].actual ); 115 testcases[tc].reason += ( testcases[tc].passed ) ? "" : "wrong value "; 116 } 117 stopTest(); 118 return ( testcases ); 119} 120 121/* 122 * Compare expected result to the actual result and figure out whether 123 * the test case passed. 124 */ 125function getTestCaseResult( expect, actual ) { 126 // because ( NaN == NaN ) always returns false, need to do 127 // a special compare to see if we got the right result. 128 if ( actual != actual ) { 129 if ( typeof actual == "object" ) { 130 actual = "NaN object"; 131 } else { 132 actual = "NaN number"; 133 } 134 } 135 if ( expect != expect ) { 136 if ( typeof expect == "object" ) { 137 expect = "NaN object"; 138 } else { 139 expect = "NaN number"; 140 } 141 } 142 143 var passed = ( expect == actual ) ? true : false; 144 145 // if both objects are numbers 146 // need to replace w/ IEEE standard for rounding 147 if ( !passed 148 && typeof(actual) == "number" 149 && typeof(expect) == "number" 150 ) { 151 if ( Math.abs(actual-expect) < 0.0000001 ) { 152 passed = true; 153 } 154 } 155 156 // verify type is the same 157 if ( typeof(expect) != typeof(actual) ) { 158 passed = false; 159 } 160 161 return passed; 162} 163 164/* 165 * Begin printing functions. These functions use the shell's 166 * print function. When running tests in the browser, these 167 * functions, override these functions with functions that use 168 * document.write. 169 */ 170 171function writeTestCaseResult( expect, actual, string ) { 172 var passed = getTestCaseResult( expect, actual ); 173 writeFormattedResult( expect, actual, string, passed ); 174 return passed; 175} 176function writeFormattedResult( expect, actual, string, passed ) { 177 var s = string ; 178 s += ( passed ) ? PASSED : FAILED + expect; 179 writeLineToLog( s); 180 return passed; 181} 182function writeLineToLog( string ) { 183 print( string ); 184} 185function writeHeaderToLog( string ) { 186 print( string ); 187} 188/* end of print functions */ 189 190 191/* 192 * When running in the shell, run the garbage collector after the 193 * test has completed. 194 */ 195 196function stopTest() { 197 var gc; 198 if ( gc != undefined ) { 199 gc(); 200 } 201} 202 203/* 204 * Convenience function for displaying failed test cases. Useful 205 * when running tests manually. 206 * 207 */ 208function getFailedCases() { 209 for ( var i = 0; i < testcases.length; i++ ) { 210 if ( ! testcases[i].passed ) { 211 print( testcases[i].description +" = " +testcases[i].actual +" expected: "+ testcases[i].expect ); 212 } 213 } 214} 215 /* 216 * Date functions used by tests in Date suite 217 * 218 */ 219var msPerDay = 86400000; 220var HoursPerDay = 24; 221var MinutesPerHour = 60; 222var SecondsPerMinute = 60; 223var msPerSecond = 1000; 224var msPerMinute = 60000; // msPerSecond * SecondsPerMinute 225var msPerHour = 3600000; // msPerMinute * MinutesPerHour 226var TZ_DIFF = getTimeZoneDiff(); // offset of tester's timezone from UTC 227var TZ_PST = -8; // offset of Pacific Standard Time from UTC 228var PST_DIFF = TZ_DIFF - TZ_PST; // offset of tester's timezone from PST 229var TIME_1970 = 0; 230var TIME_2000 = 946684800000; 231var TIME_1900 = -2208988800000; 232var TIME_YEAR_0 = -62167219200000; 233 234 235/* 236 * Originally, the test suite used a hard-coded value TZ_DIFF = -8. 237 * But that was only valid for testers in the Pacific Standard Time Zone! 238 * We calculate the proper number dynamically for any tester. We just 239 * have to be careful not to use a date subject to Daylight Savings Time... 240*/ 241function getTimeZoneDiff() 242{ 243 return -((new Date(2000, 1, 1)).getTimezoneOffset())/60; 244} 245 246 247/* 248 * Date test "ResultArrays" are hard-coded for Pacific Standard Time. 249 * We must adjust them for the tester's own timezone - 250 */ 251function adjustResultArray(ResultArray, msMode) 252{ 253 // If the tester's system clock is in PST, no need to continue - 254 if (!PST_DIFF) {return;} 255 256 /* The date testcases instantiate Date objects in two different ways: 257 * 258 * millisecond mode: e.g. dt = new Date(10000000); 259 * year-month-day mode: dt = new Date(2000, 5, 1, ...); 260 * 261 * In the first case, the date is measured from Time 0 in Greenwich (i.e. UTC). 262 * In the second case, it is measured with reference to the tester's local timezone. 263 * 264 * In the first case we must correct those values expected for local measurements, 265 * like dt.getHours() etc. No correction is necessary for dt.getUTCHours() etc. 266 * 267 * In the second case, it is exactly the other way around - 268 */ 269 if (msMode) 270 { 271 // The hard-coded UTC milliseconds from Time 0 derives from a UTC date. 272 // Shift to the right by the offset between UTC and the tester. 273 var t = ResultArray[TIME] + TZ_DIFF*msPerHour; 274 275 // Use our date arithmetic functions to determine the local hour, day, etc. 276 ResultArray[HOURS] = HourFromTime(t); 277 ResultArray[DAY] = WeekDay(t); 278 ResultArray[DATE] = DateFromTime(t); 279 ResultArray[MONTH] = MonthFromTime(t); 280 ResultArray[YEAR] = YearFromTime(t); 281 } 282 else 283 { 284 // The hard-coded UTC milliseconds from Time 0 derives from a PST date. 285 // Shift to the left by the offset between PST and the tester. 286 var t = ResultArray[TIME] - PST_DIFF*msPerHour; 287 288 // Use our date arithmetic functions to determine the UTC hour, day, etc. 289 ResultArray[TIME] = t; 290 ResultArray[UTC_HOURS] = HourFromTime(t); 291 ResultArray[UTC_DAY] = WeekDay(t); 292 ResultArray[UTC_DATE] = DateFromTime(t); 293 ResultArray[UTC_MONTH] = MonthFromTime(t); 294 ResultArray[UTC_YEAR] = YearFromTime(t); 295 } 296} 297 298 299function Day( t ) { 300 return ( Math.floor(t/msPerDay ) ); 301} 302function DaysInYear( y ) { 303 if ( y % 4 != 0 ) { 304 return 365; 305 } 306 if ( (y % 4 == 0) && (y % 100 != 0) ) { 307 return 366; 308 } 309 if ( (y % 100 == 0) && (y % 400 != 0) ) { 310 return 365; 311 } 312 if ( (y % 400 == 0) ){ 313 return 366; 314 } else { 315 return "ERROR: DaysInYear(" + y + ") case not covered"; 316 } 317} 318function TimeInYear( y ) { 319 return ( DaysInYear(y) * msPerDay ); 320} 321function DayNumber( t ) { 322 return ( Math.floor( t / msPerDay ) ); 323} 324function TimeWithinDay( t ) { 325 if ( t < 0 ) { 326 return ( (t % msPerDay) + msPerDay ); 327 } else { 328 return ( t % msPerDay ); 329 } 330} 331function YearNumber( t ) { 332} 333function TimeFromYear( y ) { 334 return ( msPerDay * DayFromYear(y) ); 335} 336function DayFromYear( y ) { 337 return ( 365*(y-1970) + 338 Math.floor((y-1969)/4) - 339 Math.floor((y-1901)/100) + 340 Math.floor((y-1601)/400) ); 341} 342function InLeapYear( t ) { 343 if ( DaysInYear(YearFromTime(t)) == 365 ) { 344 return 0; 345 } 346 if ( DaysInYear(YearFromTime(t)) == 366 ) { 347 return 1; 348 } else { 349 return "ERROR: InLeapYear("+ t + ") case not covered"; 350 } 351} 352function YearFromTime( t ) { 353 t = Number( t ); 354 var sign = ( t < 0 ) ? -1 : 1; 355 var year = ( sign < 0 ) ? 1969 : 1970; 356 for ( var timeToTimeZero = t; ; ) { 357 // subtract the current year's time from the time that's left. 358 timeToTimeZero -= sign * TimeInYear(year) 359 360 // if there's less than the current year's worth of time left, then break. 361 if ( sign < 0 ) { 362 if ( sign * timeToTimeZero <= 0 ) { 363 break; 364 } else { 365 year += sign; 366 } 367 } else { 368 if ( sign * timeToTimeZero < 0 ) { 369 break; 370 } else { 371 year += sign; 372 } 373 } 374 } 375 return ( year ); 376} 377function MonthFromTime( t ) { 378 // i know i could use switch but i'd rather not until it's part of ECMA 379 var day = DayWithinYear( t ); 380 var leap = InLeapYear(t); 381 382 if ( (0 <= day) && (day < 31) ) { 383 return 0; 384 } 385 if ( (31 <= day) && (day < (59+leap)) ) { 386 return 1; 387 } 388 if ( ((59+leap) <= day) && (day < (90+leap)) ) { 389 return 2; 390 } 391 if ( ((90+leap) <= day) && (day < (120+leap)) ) { 392 return 3; 393 } 394 if ( ((120+leap) <= day) && (day < (151+leap)) ) { 395 return 4; 396 } 397 if ( ((151+leap) <= day) && (day < (181+leap)) ) { 398 return 5; 399 } 400 if ( ((181+leap) <= day) && (day < (212+leap)) ) { 401 return 6; 402 } 403 if ( ((212+leap) <= day) && (day < (243+leap)) ) { 404 return 7; 405 } 406 if ( ((243+leap) <= day) && (day < (273+leap)) ) { 407 return 8; 408 } 409 if ( ((273+leap) <= day) && (day < (304+leap)) ) { 410 return 9; 411 } 412 if ( ((304+leap) <= day) && (day < (334+leap)) ) { 413 return 10; 414 } 415 if ( ((334+leap) <= day) && (day < (365+leap)) ) { 416 return 11; 417 } else { 418 return "ERROR: MonthFromTime("+t+") not known"; 419 } 420} 421function DayWithinYear( t ) { 422 return( Day(t) - DayFromYear(YearFromTime(t))); 423} 424function DateFromTime( t ) { 425 var day = DayWithinYear(t); 426 var month = MonthFromTime(t); 427 428 if ( month == 0 ) { 429 return ( day + 1 ); 430 } 431 if ( month == 1 ) { 432 return ( day - 30 ); 433 } 434 if ( month == 2 ) { 435 return ( day - 58 - InLeapYear(t) ); 436 } 437 if ( month == 3 ) { 438 return ( day - 89 - InLeapYear(t)); 439 } 440 if ( month == 4 ) { 441 return ( day - 119 - InLeapYear(t)); 442 } 443 if ( month == 5 ) { 444 return ( day - 150- InLeapYear(t)); 445 } 446 if ( month == 6 ) { 447 return ( day - 180- InLeapYear(t)); 448 } 449 if ( month == 7 ) { 450 return ( day - 211- InLeapYear(t)); 451 } 452 if ( month == 8 ) { 453 return ( day - 242- InLeapYear(t)); 454 } 455 if ( month == 9 ) { 456 return ( day - 272- InLeapYear(t)); 457 } 458 if ( month == 10 ) { 459 return ( day - 303- InLeapYear(t)); 460 } 461 if ( month == 11 ) { 462 return ( day - 333- InLeapYear(t)); 463 } 464 465 return ("ERROR: DateFromTime("+t+") not known" ); 466} 467function WeekDay( t ) { 468 var weekday = (Day(t)+4) % 7; 469 return( weekday < 0 ? 7 + weekday : weekday ); 470} 471 472// missing daylight savins time adjustment 473 474function HourFromTime( t ) { 475 var h = Math.floor( t / msPerHour ) % HoursPerDay; 476 return ( (h<0) ? HoursPerDay + h : h ); 477} 478function MinFromTime( t ) { 479 var min = Math.floor( t / msPerMinute ) % MinutesPerHour; 480 return( ( min < 0 ) ? MinutesPerHour + min : min ); 481} 482function SecFromTime( t ) { 483 var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute; 484 return ( (sec < 0 ) ? SecondsPerMinute + sec : sec ); 485} 486function msFromTime( t ) { 487 var ms = t % msPerSecond; 488 return ( (ms < 0 ) ? msPerSecond + ms : ms ); 489} 490function LocalTZA() { 491 return ( TZ_DIFF * msPerHour ); 492} 493function UTC( t ) { 494 return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) ); 495} 496 497function DaylightSavingTA( t ) { 498 t = t - LocalTZA(); 499 500 var dst_start = GetSecondSundayInMarch(t) + 2*msPerHour; 501 var dst_end = GetFirstSundayInNovember(t)+ 2*msPerHour; 502 503 if ( t >= dst_start && t < dst_end ) { 504 return msPerHour; 505 } else { 506 return 0; 507 } 508 509 // Daylight Savings Time starts on the first Sunday in April at 2:00AM in 510 // PST. Other time zones will need to override this function. 511 512 print( new Date( UTC(dst_start + LocalTZA())) ); 513 514 return UTC(dst_start + LocalTZA()); 515} 516 517function GetFirstSundayInApril( t ) { 518 var year = YearFromTime(t); 519 var leap = InLeapYear(t); 520 521 var april = TimeFromYear(year) + TimeInMonth(0, leap) + TimeInMonth(1,leap) + 522 TimeInMonth(2,leap); 523 524 for ( var first_sunday = april; WeekDay(first_sunday) > 0; 525 first_sunday += msPerDay ) 526 { 527 ; 528 } 529 530 return first_sunday; 531} 532function GetLastSundayInOctober( t ) { 533 var year = YearFromTime(t); 534 var leap = InLeapYear(t); 535 536 for ( var oct = TimeFromYear(year), m = 0; m < 9; m++ ) { 537 oct += TimeInMonth(m, leap); 538 } 539 for ( var last_sunday = oct + 30*msPerDay; WeekDay(last_sunday) > 0; 540 last_sunday -= msPerDay ) 541 { 542 ; 543 } 544 return last_sunday; 545} 546 547// Added these two functions because DST rules changed for the US. 548function GetSecondSundayInMarch( t ) { 549 var year = YearFromTime(t); 550 var leap = InLeapYear(t); 551 552 var march = TimeFromYear(year) + TimeInMonth(0, leap) + TimeInMonth(1,leap); 553 554 var sundayCount = 0; 555 var flag = true; 556 for ( var second_sunday = march; flag; second_sunday += msPerDay ) 557 { 558 if (WeekDay(second_sunday) == 0) { 559 if(++sundayCount == 2) 560 flag = false; 561 } 562 } 563 564 return second_sunday; 565} 566function GetFirstSundayInNovember( t ) { 567 var year = YearFromTime(t); 568 var leap = InLeapYear(t); 569 570 for ( var nov = TimeFromYear(year), m = 0; m < 10; m++ ) { 571 nov += TimeInMonth(m, leap); 572 } 573 for ( var first_sunday = nov; WeekDay(first_sunday) > 0; 574 first_sunday += msPerDay ) 575 { 576 ; 577 } 578 return first_sunday; 579} 580function LocalTime( t ) { 581 return ( t + LocalTZA() + DaylightSavingTA(t) ); 582} 583function MakeTime( hour, min, sec, ms ) { 584 if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) { 585 return Number.NaN; 586 } 587 588 hour = ToInteger(hour); 589 min = ToInteger( min); 590 sec = ToInteger( sec); 591 ms = ToInteger( ms ); 592 593 return( (hour*msPerHour) + (min*msPerMinute) + 594 (sec*msPerSecond) + ms ); 595} 596function MakeDay( year, month, date ) { 597 if ( isNaN(year) || isNaN(month) || isNaN(date) ) { 598 return Number.NaN; 599 } 600 year = ToInteger(year); 601 month = ToInteger(month); 602 date = ToInteger(date ); 603 604 var sign = ( year < 1970 ) ? -1 : 1; 605 var t = ( year < 1970 ) ? 1 : 0; 606 var y = ( year < 1970 ) ? 1969 : 1970; 607 608 var result5 = year + Math.floor( month/12 ); 609 var result6 = month % 12; 610 611 if ( year < 1970 ) { 612 for ( y = 1969; y >= year; y += sign ) { 613 t += sign * TimeInYear(y); 614 } 615 } else { 616 for ( y = 1970 ; y < year; y += sign ) { 617 t += sign * TimeInYear(y); 618 } 619 } 620 621 var leap = InLeapYear( t ); 622 623 for ( var m = 0; m < month; m++ ) { 624 t += TimeInMonth( m, leap ); 625 } 626 627 if ( YearFromTime(t) != result5 ) { 628 return Number.NaN; 629 } 630 if ( MonthFromTime(t) != result6 ) { 631 return Number.NaN; 632 } 633 if ( DateFromTime(t) != 1 ) { 634 return Number.NaN; 635 } 636 637 return ( (Day(t)) + date - 1 ); 638} 639function TimeInMonth( month, leap ) { 640 // september april june november 641 // jan 0 feb 1 mar 2 apr 3 may 4 june 5 jul 6 642 // aug 7 sep 8 oct 9 nov 10 dec 11 643 644 if ( month == 3 || month == 5 || month == 8 || month == 10 ) { 645 return ( 30*msPerDay ); 646 } 647 648 // all the rest 649 if ( month == 0 || month == 2 || month == 4 || month == 6 || 650 month == 7 || month == 9 || month == 11 ) { 651 return ( 31*msPerDay ); 652 } 653 654 // save february 655 return ( (leap == 0) ? 28*msPerDay : 29*msPerDay ); 656} 657function MakeDate( day, time ) { 658 if ( day == Number.POSITIVE_INFINITY || 659 day == Number.NEGATIVE_INFINITY || 660 day == Number.NaN ) { 661 return Number.NaN; 662 } 663 if ( time == Number.POSITIVE_INFINITY || 664 time == Number.POSITIVE_INFINITY || 665 day == Number.NaN) { 666 return Number.NaN; 667 } 668 return ( day * msPerDay ) + time; 669} 670function TimeClip( t ) { 671 if ( isNaN( t ) ) { 672 return ( Number.NaN ); 673 } 674 if ( Math.abs( t ) > 8.64e15 ) { 675 return ( Number.NaN ); 676 } 677 678 return ( ToInteger( t ) ); 679} 680function ToInteger( t ) { 681 t = Number( t ); 682 683 if ( isNaN( t ) ){ 684 return ( Number.NaN ); 685 } 686 if ( t == 0 || t == -0 || 687 t == Number.POSITIVE_INFINITY || t == Number.NEGATIVE_INFINITY ) { 688 return 0; 689 } 690 691 var sign = ( t < 0 ) ? -1 : 1; 692 693 return ( sign * Math.floor( Math.abs( t ) ) ); 694} 695function Enumerate ( o ) { 696 var p; 697 for ( p in o ) { 698 print( p +": " + o[p] ); 699 } 700} 701 702/* these functions are useful for running tests manually in Rhino */ 703 704function GetContext() { 705 return Packages.com.netscape.javascript.Context.getCurrentContext(); 706} 707function OptLevel( i ) { 708 i = Number(i); 709 var cx = GetContext(); 710 cx.setOptimizationLevel(i); 711} 712/* end of Rhino functions */ 713