1var completed = false;
2var testcases;
3var tc = 0;
4
5SECTION	= "";
6VERSION	= "";
7BUGNUMBER =	"";
8TITLE  = "";
9
10/*
11 * constant strings
12 */
13var	GLOBAL = "[object global]";
14var PASSED = " PASSED!"
15var FAILED = " FAILED! expected: ";
16var	DEBUG =	false;
17
18TZ_DIFF = -8;
19
20var TT = "";
21var TT_ = "";
22var BR = "";
23var NBSP = " ";
24var CR = "\n";
25var FONT = "";
26var FONT_ = "";
27var FONT_RED = "";
28var FONT_GREEN = "";
29var B = "";
30var B_ = ""
31var H2 = "";
32var H2_ = "";
33var HR = "";
34var DEBUG = false;
35
36var PASSED = " PASSED!"
37var FAILED = " FAILED! expected: ";
38
39function test() {
40    for ( tc=0; tc < testcases.length; tc++ ) {
41        testcases[tc].passed = writeTestCaseResult(
42                            testcases[tc].expect,
43                            testcases[tc].actual,
44                            testcases[tc].description +" = "+
45                            testcases[tc].actual );
46
47        testcases[tc].reason += ( testcases[tc].passed ) ? "" : "wrong value ";
48    }
49    stopTest();
50    return ( testcases );
51}
52/* wrapper for test cas constructor that doesn't require the SECTION
53 * argument.
54 */
55
56function AddTestCase( description, expect, actual ) {
57    testcases[tc++] = new TestCase( SECTION, description, expect, actual );
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
122function getTestCaseResult( expect, actual ) {
123    //  because ( NaN == NaN ) always returns false, need to do
124    //  a special compare to see if we got the right result.
125        if ( actual != actual ) {
126            if ( typeof actual == "object" ) {
127                actual = "NaN object";
128            } else {
129                actual = "NaN number";
130            }
131        }
132        if ( expect != expect ) {
133            if ( typeof expect == "object" ) {
134                expect = "NaN object";
135            } else {
136                expect = "NaN number";
137            }
138        }
139
140        var passed = ( expect == actual ) ? true : false;
141
142    //  if both objects are numbers
143    // need to replace w/ IEEE standard for rounding
144        if (    !passed
145                && typeof(actual) == "number"
146                && typeof(expect) == "number"
147            ) {
148                if ( Math.abs(actual-expect) < 0.0000001 ) {
149                    passed = true;
150                }
151        }
152
153    //  verify type is the same
154        if ( typeof(expect) != typeof(actual) ) {
155            passed = false;
156        }
157
158        return passed;
159}
160function writeTestCaseResult( expect, actual, string ) {
161        var passed = getTestCaseResult( expect, actual );
162        writeFormattedResult( expect, actual, string, passed );
163        return passed;
164}
165function writeFormattedResult( expect, actual, string, passed ) {
166        var s = TT + string ;
167
168        for ( k = 0;
169              k <  (60 - string.length >= 0 ? 60 - string.length : 5) ;
170              k++ ) {
171        }
172
173        s += B ;
174        s += ( passed ) ? FONT_GREEN + NBSP + PASSED : FONT_RED + NBSP + FAILED + expect + TT_ ;
175
176        writeLineToLog( s + FONT_ + B_ + TT_ );
177
178        return passed;
179}
180
181function writeLineToLog( string ) {
182    print( string + BR + CR );
183}
184function writeHeaderToLog( string ) {
185    print( H2 + string + H2_ );
186}
187function stopTest()
188{
189    var sizeTag  = "<#TEST CASES SIZE>";
190    var doneTag  = "<#TEST CASES DONE>";
191    var beginTag = "<#TEST CASE ";
192    var endTag   = ">";
193
194    print(sizeTag);
195    print(testcases.length);
196    for (tc = 0; tc < testcases.length; tc++)
197    {
198        print(beginTag + 'PASSED'      + endTag);
199        print(testcases[tc].passed);
200        print(beginTag + 'NAME'        + endTag);
201        print(testcases[tc].name);
202        print(beginTag + 'EXPECTED'    + endTag);
203        print(testcases[tc].expect);
204        print(beginTag + 'ACTUAL'      + endTag);
205        print(testcases[tc].actual);
206        print(beginTag + 'DESCRIPTION' + endTag);
207        print(testcases[tc].description);
208        print(beginTag + 'REASON'      + endTag);
209        print(( testcases[tc].passed ) ? "" : "wrong value ");
210        print(beginTag + 'BUGNUMBER'   + endTag);
211        print( BUGNUMBER );
212    }
213    print(doneTag);
214    print( HR );
215    gc();
216}
217function getFailedCases() {
218  for ( var i = 0; i < testcases.length; i++ ) {
219     if ( ! testcases[i].passed ) {
220        print( testcases[i].description +" = " +testcases[i].actual +" expected: "+ testcases[i].expect );
221     }
222  }
223}
224function err( msg, page, line ) {
225    testcases[tc].actual = "error";
226    testcases[tc].reason = msg;
227    writeTestCaseResult( testcases[tc].expect,
228                         testcases[tc].actual,
229                         testcases[tc].description +" = "+ testcases[tc].actual +
230                         ": " + testcases[tc].reason );
231    stopTest();
232    return true;
233}
234
235/**
236 *  Type Conversion functions used by Type Conversion
237 *
238 */
239
240
241
242 /*
243  * Date functions used by tests in Date suite
244  *
245  */
246var msPerDay =          86400000;
247var HoursPerDay =       24;
248var MinutesPerHour =    60;
249var SecondsPerMinute =  60;
250var msPerSecond =       1000;
251var msPerMinute =       60000;      //  msPerSecond * SecondsPerMinute
252var msPerHour =         3600000;    //  msPerMinute * MinutesPerHour
253
254var TIME_1970    = 0;
255var TIME_2000    = 946684800000;
256var TIME_1900    = -2208988800000;
257
258function Day( t ) {
259    return ( Math.floor(t/msPerDay ) );
260}
261function DaysInYear( y ) {
262    if ( y % 4 != 0 ) {
263        return 365;
264    }
265    if ( (y % 4 == 0) && (y % 100 != 0) ) {
266        return 366;
267    }
268    if ( (y % 100 == 0) &&  (y % 400 != 0) ) {
269        return 365;
270    }
271    if ( (y % 400 == 0) ){
272        return 366;
273    } else {
274        return "ERROR: DaysInYear(" + y + ") case not covered";
275    }
276}
277function TimeInYear( y ) {
278    return ( DaysInYear(y) * msPerDay );
279}
280function DayNumber( t ) {
281    return ( Math.floor( t / msPerDay ) );
282}
283function TimeWithinDay( t ) {
284    if ( t < 0 ) {
285        return ( (t % msPerDay) + msPerDay );
286    } else {
287        return ( t % msPerDay );
288    }
289}
290function YearNumber( t ) {
291}
292function TimeFromYear( y ) {
293    return ( msPerDay * DayFromYear(y) );
294}
295function DayFromYear( y ) {
296    return (    365*(y-1970) +
297                Math.floor((y-1969)/4) -
298                Math.floor((y-1901)/100) +
299                Math.floor((y-1601)/400) );
300}
301function InLeapYear( t ) {
302    if ( DaysInYear(YearFromTime(t)) == 365 ) {
303        return 0;
304    }
305    if ( DaysInYear(YearFromTime(t)) == 366 ) {
306        return 1;
307    } else {
308        return "ERROR:  InLeapYear("+t+") case not covered";
309    }
310}
311function YearFromTime( t ) {
312    t = Number( t );
313    var sign = ( t < 0 ) ? -1 : 1;
314    var year = ( sign < 0 ) ? 1969 : 1970;
315    for (   var timeToTimeZero = t; ;  ) {
316    //  subtract the current year's time from the time that's left.
317        timeToTimeZero -= sign * TimeInYear(year)
318
319    //  if there's less than the current year's worth of time left, then break.
320        if ( sign < 0 ) {
321            if ( sign * timeToTimeZero <= 0 ) {
322                break;
323            } else {
324                year += sign;
325            }
326        } else {
327            if ( sign * timeToTimeZero < 0 ) {
328                break;
329            } else {
330                year += sign;
331            }
332        }
333    }
334    return ( year );
335}
336function MonthFromTime( t ) {
337    //  i know i could use switch but i'd rather not until it's part of ECMA
338    var day = DayWithinYear( t );
339    var leap = InLeapYear(t);
340
341    if ( (0 <= day) && (day < 31) ) {
342        return 0;
343    }
344    if ( (31 <= day) && (day < (59+leap)) ) {
345        return 1;
346    }
347    if ( ((59+leap) <= day) && (day < (90+leap)) ) {
348        return 2;
349    }
350    if ( ((90+leap) <= day) && (day < (120+leap)) ) {
351        return 3;
352    }
353    if ( ((120+leap) <= day) && (day < (151+leap)) ) {
354        return 4;
355    }
356    if ( ((151+leap) <= day) && (day < (181+leap)) ) {
357        return 5;
358    }
359    if ( ((181+leap) <= day) && (day < (212+leap)) ) {
360        return 6;
361    }
362    if ( ((212+leap) <= day) && (day < (243+leap)) ) {
363        return 7;
364    }
365    if ( ((243+leap) <= day) && (day < (273+leap)) ) {
366        return 8;
367    }
368    if ( ((273+leap) <= day) && (day < (304+leap)) ) {
369        return 9;
370    }
371    if ( ((304+leap) <= day) && (day < (334+leap)) ) {
372        return 10;
373    }
374    if ( ((334+leap) <= day) && (day < (365+leap)) ) {
375        return 11;
376    } else {
377        return "ERROR:  MonthFromTime("+t+") not known";
378    }
379}
380function DayWithinYear( t ) {
381        return( Day(t) - DayFromYear(YearFromTime(t)));
382}
383function DateFromTime( t ) {
384    var day = DayWithinYear(t);
385    var month = MonthFromTime(t);
386
387    if ( month == 0 ) {
388        return ( day + 1 );
389    }
390    if ( month == 1 ) {
391        return ( day - 30 );
392    }
393    if ( month == 2 ) {
394        return ( day - 58 - InLeapYear(t) );
395    }
396    if ( month == 3 ) {
397        return ( day - 89 - InLeapYear(t));
398    }
399    if ( month == 4 ) {
400        return ( day - 119 - InLeapYear(t));
401    }
402    if ( month == 5 ) {
403        return ( day - 150- InLeapYear(t));
404    }
405    if ( month == 6 ) {
406        return ( day - 180- InLeapYear(t));
407    }
408    if ( month == 7 ) {
409        return ( day - 211- InLeapYear(t));
410    }
411    if ( month == 8 ) {
412        return ( day - 242- InLeapYear(t));
413    }
414    if ( month == 9 ) {
415        return ( day - 272- InLeapYear(t));
416    }
417    if ( month == 10 ) {
418        return ( day - 303- InLeapYear(t));
419    }
420    if ( month == 11 ) {
421        return ( day - 333- InLeapYear(t));
422    }
423
424    return ("ERROR:  DateFromTime("+t+") not known" );
425}
426function WeekDay( t ) {
427    var weekday = (Day(t)+4) % 7;
428    return( weekday < 0 ? 7 + weekday : weekday );
429}
430
431// missing daylight savins time adjustment
432
433function HourFromTime( t ) {
434    var h = Math.floor( t / msPerHour ) % HoursPerDay;
435    return ( (h<0) ? HoursPerDay + h : h  );
436}
437function MinFromTime( t ) {
438    var min = Math.floor( t / msPerMinute ) % MinutesPerHour;
439    return( ( min < 0 ) ? MinutesPerHour + min : min  );
440}
441function SecFromTime( t ) {
442    var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute;
443    return ( (sec < 0 ) ? SecondsPerMinute + sec : sec );
444}
445function msFromTime( t ) {
446    var ms = t % msPerSecond;
447    return ( (ms < 0 ) ? msPerSecond + ms : ms );
448}
449function LocalTZA() {
450    return ( TZ_DIFF * msPerHour );
451}
452function UTC( t ) {
453    return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) );
454}
455function DaylightSavingTA( t ) {
456    t = t - LocalTZA();
457
458    var dst_start = GetSecondSundayInMarch(t) + 2*msPerHour;
459    var dst_end   = GetFirstSundayInNovember(t)+ 2*msPerHour;
460
461    if ( t >= dst_start && t < dst_end ) {
462        return msPerHour;
463    } else {
464        return 0;
465    }
466
467    // Daylight Savings Time starts on the first Sunday in April at 2:00AM in
468    // PST.  Other time zones will need to override this function.
469
470    print( new Date( UTC(dst_start + LocalTZA())) );
471
472    return UTC(dst_start  + LocalTZA());
473}
474function GetFirstSundayInApril( t ) {
475    var year = YearFromTime(t);
476    var leap = InLeapYear(t);
477
478    var april = TimeFromYear(year) + TimeInMonth(0, leap) + TimeInMonth(1,leap) +
479    TimeInMonth(2,leap);
480
481    for ( var first_sunday = april; WeekDay(first_sunday) > 0;
482        first_sunday += msPerDay )
483    {
484        ;
485    }
486
487    return first_sunday;
488}
489function GetLastSundayInOctober( t ) {
490    var year = YearFromTime(t);
491    var leap = InLeapYear(t);
492
493    for ( var oct = TimeFromYear(year), m = 0; m < 9; m++ ) {
494        oct += TimeInMonth(m, leap);
495    }
496    for ( var last_sunday = oct + 30*msPerDay; WeekDay(last_sunday) > 0;
497        last_sunday -= msPerDay )
498    {
499        ;
500    }
501    return last_sunday;
502}
503
504// Added these two functions because DST rules changed for the US.
505function GetSecondSundayInMarch( t ) {
506	var	year = YearFromTime(t);
507	var	leap = InLeapYear(t);
508
509	var	march =	TimeFromYear(year) + TimeInMonth(0, leap) + TimeInMonth(1,leap);
510
511	var sundayCount = 0;
512	var flag = true;
513	for ( var second_sunday = march; flag; second_sunday += msPerDay )
514	{
515		if (WeekDay(second_sunday) == 0) {
516			if(++sundayCount == 2)
517				flag = false;
518		}
519	}
520
521	return second_sunday;
522}
523function GetFirstSundayInNovember( t ) {
524	var year = YearFromTime(t);
525	var leap = InLeapYear(t);
526
527	for ( var nov = TimeFromYear(year), m =	0; m < 10; m++ ) {
528		nov += TimeInMonth(m, leap);
529	}
530	for ( var first_sunday = nov; WeekDay(first_sunday) > 0;
531		first_sunday += msPerDay	)
532	{
533		;
534	}
535	return first_sunday;
536}
537function LocalTime( t ) {
538    return ( t + LocalTZA() + DaylightSavingTA(t) );
539}
540function MakeTime( hour, min, sec, ms ) {
541    if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) {
542        return Number.NaN;
543    }
544
545    hour = ToInteger(hour);
546    min  = ToInteger( min);
547    sec  = ToInteger( sec);
548    ms   = ToInteger( ms );
549
550    return( (hour*msPerHour) + (min*msPerMinute) +
551            (sec*msPerSecond) + ms );
552}
553function MakeDay( year, month, date ) {
554    if ( isNaN(year) || isNaN(month) || isNaN(date) ) {
555        return Number.NaN;
556    }
557    year = ToInteger(year);
558    month = ToInteger(month);
559    date = ToInteger(date );
560
561    var sign = ( year < 1970 ) ? -1 : 1;
562    var t =    ( year < 1970 ) ? 1 :  0;
563    var y =    ( year < 1970 ) ? 1969 : 1970;
564
565    var result5 = year + Math.floor( month/12 );
566    var result6 = month % 12;
567
568    if ( year < 1970 ) {
569       for ( y = 1969; y >= year; y += sign ) {
570         t += sign * TimeInYear(y);
571       }
572    } else {
573        for ( y = 1970 ; y < year; y += sign ) {
574            t += sign * TimeInYear(y);
575        }
576    }
577
578    var leap = InLeapYear( t );
579
580    for ( var m = 0; m < month; m++ ) {
581        t += TimeInMonth( m, leap );
582    }
583
584    if ( YearFromTime(t) != result5 ) {
585        return Number.NaN;
586    }
587    if ( MonthFromTime(t) != result6 ) {
588        return Number.NaN;
589    }
590    if ( DateFromTime(t) != 1 ) {
591        return Number.NaN;
592    }
593
594    return ( (Day(t)) + date - 1 );
595}
596function TimeInMonth( month, leap ) {
597    // september april june november
598    // jan 0  feb 1  mar 2  apr 3   may 4  june 5  jul 6
599    // aug 7  sep 8  oct 9  nov 10  dec 11
600
601    if ( month == 3 || month == 5 || month == 8 || month == 10 ) {
602        return ( 30*msPerDay );
603    }
604
605    // all the rest
606    if ( month == 0 || month == 2 || month == 4 || month == 6 ||
607         month == 7 || month == 9 || month == 11 ) {
608        return ( 31*msPerDay );
609     }
610
611    // save february
612    return ( (leap == 0) ? 28*msPerDay : 29*msPerDay );
613}
614function MakeDate( day, time ) {
615    if (    day == Number.POSITIVE_INFINITY ||
616            day == Number.NEGATIVE_INFINITY ||
617            day == Number.NaN ) {
618        return Number.NaN;
619    }
620    if (    time == Number.POSITIVE_INFINITY ||
621            time == Number.POSITIVE_INFINITY ||
622            day == Number.NaN) {
623        return Number.NaN;
624    }
625    return ( day * msPerDay ) + time;
626}
627function TimeClip( t ) {
628    if ( isNaN( t ) ) {
629        return ( Number.NaN );
630    }
631    if ( Math.abs( t ) > 8.64e15 ) {
632        return ( Number.NaN );
633    }
634
635    return ( ToInteger( t ) );
636}
637function ToInteger( t ) {
638    t = Number( t );
639
640    if ( isNaN( t ) ){
641        return ( Number.NaN );
642    }
643    if ( t == 0 || t == -0 ||
644         t == Number.POSITIVE_INFINITY || t == Number.NEGATIVE_INFINITY ) {
645         return 0;
646    }
647
648    var sign = ( t < 0 ) ? -1 : 1;
649
650    return ( sign * Math.floor( Math.abs( t ) ) );
651}
652function Enumerate ( o ) {
653    var properties = new Array();
654    for ( p in o ) {
655       properties[ properties.length ] = new Array( p, o[p] );
656    }
657    return properties;
658}
659function AddTestCase( description, expect, actual ) {
660    testcases[tc++] = new TestCase( SECTION, description, expect, actual );
661}
662
663function getFailedCases() {
664  for ( var i = 0; i < testcases.length; i++ ) {
665     if ( ! testcases[i].passed ) {
666        print( testcases[i].description +" = " +testcases[i].actual +" expected: "+ testcases[i].expect );
667     }
668  }
669}
670