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