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: ";
42var DEBUG = false;
43
44
45/*
46* Wrapper for test case constructor that doesn't require the SECTION argument.
47 */
48function AddTestCase( description, expect, actual )
49{
50  testcases[tc++] = new TestCase( SECTION, description, expect, actual );
51}
52
53
54/*
55 * TestCase constructor
56*/
57function 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*/
74function 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
99function 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 */
120function 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 */
156function writeTestCaseResult( expect, actual, string )
157{
158  var passed = getTestCaseResult(expect, actual );
159  writeFormattedResult( expect, actual, string, passed );
160  return passed;
161}
162
163
164function 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
173function writeLineToLog( string )
174{
175  print( string );
176}
177
178
179function 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 */
189function 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*/
203function 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*/
218var msPerDay = 86400000;
219var HoursPerDay = 24;
220var MinutesPerHour = 60;
221var SecondsPerMinute = 60;
222var msPerSecond = 1000;
223var msPerMinute = 60000;   // msPerSecond * SecondsPerMinute
224var msPerHour = 3600000;   // msPerMinute * MinutesPerHour
225var TZ_DIFF = getTimeZoneDiff();
226var TZ_ADJUST = TZ_DIFF * msPerHour;
227var TIME_1970 = 0;
228var TIME_2000 = 946684800000;
229var TIME_1900 = -2208988800000;
230var UTC_29_FEB_2000 = TIME_2000 + 31*msPerDay + 28*msPerDay;
231var UTC_1_JAN_2005 = TIME_2000 + TimeInYear(2000) + TimeInYear(2001) +
232       TimeInYear(2002) + TimeInYear(2003) + TimeInYear(2004);
233var now = new Date();
234var 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*/
245function getTimeZoneDiff()
246{
247  return -((new Date(2000, 1, 1)).getTimezoneOffset())/60;
248}
249
250
251function Day( t)
252{
253  return ( Math.floor( t/msPerDay ) );
254}
255
256
257function 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
270function TimeInYear( y )
271{
272  return ( DaysInYear(y) * msPerDay );
273}
274
275
276function DayNumber( t )
277{
278  return ( Math.floor( t / msPerDay ) );
279}
280
281
282function TimeWithinDay( t )
283{
284  if ( t < 0 ) {return ( (t%msPerDay) + msPerDay );}
285  else {return ( t % msPerDay );}
286}
287
288
289function YearNumber( t )
290{
291}
292
293
294function TimeFromYear( y )
295{
296  return ( msPerDay * DayFromYear(y) );
297}
298
299
300function 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
307function 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
316function 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
344function 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
366function DayWithinYear( t )
367{
368  return(Day(t) - DayFromYear(YearFromTime(t)) );
369}
370
371
372function 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
393function 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
403function HourFromTime( t )
404{
405  var h = Math.floor( t / msPerHour )%HoursPerDay;
406  return ( (h<0) ? HoursPerDay + h : h  );
407}
408
409
410function MinFromTime( t )
411{
412  var min = Math.floor( t / msPerMinute )%MinutesPerHour;
413  return( (min < 0 ) ?  MinutesPerHour + min : min );
414}
415
416
417function SecFromTime( t )
418{
419  var sec = Math.floor( t / msPerSecond )%SecondsPerMinute;
420  return ( (sec < 0 ) ?  SecondsPerMinute + sec : sec );
421}
422
423
424function msFromTime( t )
425{
426  var ms = t%msPerSecond;
427  return ( (ms < 0 ) ? msPerSecond + ms : ms );
428}
429
430
431function LocalTZA()
432{
433  return ( TZ_DIFF * msPerHour );
434}
435
436
437function UTC( t )
438{
439  return ( t - LocalTZA() - DaylightSavingTA(t  - LocalTZA()) );
440}
441
442
443function 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
456print( new Date( UTC(dst_start + LocalTZA())) );
457return UTC(dst_start + LocalTZA());
458}
459
460function 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}
475function 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.
491function 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}
509function 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
525function LocalTime( t )
526{
527  return ( t + LocalTZA() + DaylightSavingTA(t) );
528}
529
530
531function 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
544function 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
589function 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
605function 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
625function 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
634function 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
653function 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
662function GetContext()
663{
664  return Packages.com.netscape.javascript.Context.getCurrentContext();
665}
666
667
668function OptLevel( i )
669{
670  i = Number(i);
671  var cx = GetContext();
672  cx.setOptimizationLevel(i);
673}
674
675/* end of Rhino functions */
676
677