JavaScriptCore:
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Feb 2008 04:50:47 +0000 (04:50 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Feb 2008 04:50:47 +0000 (04:50 +0000)
        Reviewed by Darin.

        Fix for Bug 16753: date set methods with no args should result in NaN (Acid3 bug)
        The set values result in NaN now when called with no args, NaN or +/- inf values.
        The setYear, setFullYear and setUTCFullYear methods used on NaN dates work as
        descripted in the standard.

        * kjs/date_object.cpp:
        (KJS::fillStructuresUsingTimeArgs):
        (KJS::fillStructuresUsingDateArgs):
        (KJS::setNewValueFromTimeArgs):
        (KJS::setNewValueFromDateArgs):
        (KJS::dateProtoFuncSetYear):

LayoutTests:

        Reviewed by Darin.

        - test for Bug 16753: date set methods with no args should result in NaN (Acid3 bug)

        * fast/js/date-set-to-nan-expected.txt: Added.
        * fast/js/date-set-to-nan.html: Added.
        * fast/js/resources/date-set-to-nan.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30453 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/date_object.cpp
LayoutTests/ChangeLog
LayoutTests/fast/js/date-set-to-nan-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/date-set-to-nan.html [new file with mode: 0644]
LayoutTests/fast/js/resources/date-set-to-nan.js [new file with mode: 0644]

index a60e2351cae1aa370359501032692440cc14361f..e1eb843be75b8093c0a4158761f44b4171fe2ca1 100644 (file)
@@ -1,3 +1,19 @@
+2008-02-20  Michael Knaup  <michael.knaup@mac.com>
+
+        Reviewed by Darin.
+
+        Fix for Bug 16753: date set methods with no args should result in NaN (Acid3 bug)
+        The set values result in NaN now when called with no args, NaN or +/- inf values.
+        The setYear, setFullYear and setUTCFullYear methods used on NaN dates work as 
+        descripted in the standard.
+
+        * kjs/date_object.cpp:
+        (KJS::fillStructuresUsingTimeArgs):
+        (KJS::fillStructuresUsingDateArgs):
+        (KJS::setNewValueFromTimeArgs):
+        (KJS::setNewValueFromDateArgs):
+        (KJS::dateProtoFuncSetYear):
+
 2008-02-19  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Darin.
index 2b34923901f1b487dc58497babc0e92bb93d99ba..303be5045cdd4191b7ec4b66ee81319447eeac27 100644 (file)
@@ -246,9 +246,10 @@ static UString formatTime(const GregorianDateTime &t, bool utc)
 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
 //
 // Format of member function: f([hour,] [min,] [sec,] [ms])
-static void fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t)
+static bool fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t)
 {
     double milliseconds = 0;
+    bool ok = true;
     int idx = 0;
     int numArgs = args.size();
     
@@ -259,37 +260,44 @@ static void fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int m
     // hours
     if (maxArgs >= 4 && idx < numArgs) {
         t->hour = 0;
-        milliseconds += args[idx++]->toInt32(exec) * msPerHour;
+        milliseconds += args[idx++]->toInt32(exec, ok) * msPerHour;
     }
 
     // minutes
-    if (maxArgs >= 3 && idx < numArgs) {
+    if (maxArgs >= 3 && idx < numArgs && ok) {
         t->minute = 0;
-        milliseconds += args[idx++]->toInt32(exec) * msPerMinute;
+        milliseconds += args[idx++]->toInt32(exec, ok) * msPerMinute;
     }
     
     // seconds
-    if (maxArgs >= 2 && idx < numArgs) {
+    if (maxArgs >= 2 && idx < numArgs && ok) {
         t->second = 0;
-        milliseconds += args[idx++]->toInt32(exec) * msPerSecond;
+        milliseconds += args[idx++]->toInt32(exec, ok) * msPerSecond;
     }
     
+    if (!ok)
+        return false;
+        
     // milliseconds
-    if (idx < numArgs)
-        milliseconds += args[idx]->toNumber(exec);
-    else
+    if (idx < numArgs) {
+        double millis = args[idx]->toNumber(exec);
+        ok = isfinite(millis);
+        milliseconds += millis;
+    } else
         milliseconds += *ms;
     
     *ms = milliseconds;
+    return ok;
 }
 
 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
 //
 // Format of member function: f([years,] [months,] [days])
-static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
+static bool fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
 {
     int idx = 0;
+    bool ok = true;
     int numArgs = args.size();
   
     // JS allows extra trailing arguments -- ignore them
@@ -298,17 +306,19 @@ static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int m
   
     // years
     if (maxArgs >= 3 && idx < numArgs)
-        t->year = args[idx++]->toInt32(exec) - 1900;
-  
+        t->year = args[idx++]->toInt32(exec, ok) - 1900;
+    
     // months
-    if (maxArgs >= 2 && idx < numArgs)
-        t->month = args[idx++]->toInt32(exec);
-  
+    if (maxArgs >= 2 && idx < numArgs && ok)   
+        t->month = args[idx++]->toInt32(exec, ok);
+    
     // days
-    if (idx < numArgs) {
+    if (idx < numArgs && ok) {   
         t->monthDay = 0;
-        *ms += args[idx]->toInt32(exec) * msPerDay;
+        *ms += args[idx]->toInt32(exec, ok) * msPerDay;
     }
+    
+    return ok;
 }
 
 // ------------------------------ DateInstance ------------------------------
@@ -1449,14 +1459,25 @@ static JSValue* setNewValueFromTimeArgs(ExecState* exec, JSObject* thisObj, cons
     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
     JSValue* v = thisDateObj->internalValue();
     double milli = v->toNumber(exec);
+    
+    if (args.isEmpty() || isnan(milli)) {
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    }
+     
     double secs = floor(milli / msPerSecond);
     double ms = milli - secs * msPerSecond;
 
     GregorianDateTime t;
     msToGregorianDateTime(milli, inputIsUTC, t);
 
-    fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t);
-
+    if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t)) {
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    } 
+    
     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
     thisDateObj->setInternalValue(result);
     return result;
@@ -1468,16 +1489,33 @@ static JSValue* setNewValueFromDateArgs(ExecState* exec, JSObject* thisObj, cons
         return throwError(exec, TypeError);
 
     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+    if (args.isEmpty()) {
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    }      
+    
     JSValue* v = thisDateObj->internalValue();
     double milli = v->toNumber(exec);
-    double secs = floor(milli / msPerSecond);
-    double ms = milli - secs * msPerSecond;
+    double ms = 0;
 
     GregorianDateTime t;
-    msToGregorianDateTime(milli, inputIsUTC, t);
-
-    fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t);
-
+    if (numArgsToUse == 3 && isnan(milli))
+        // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear)
+        // the time must be reset to +0 if it is NaN. 
+        msToGregorianDateTime(0, true, t);
+    else {
+        double secs = floor(milli / msPerSecond);
+        ms = milli - secs * msPerSecond;
+        msToGregorianDateTime(milli, inputIsUTC, t);
+    }
+    
+    if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) {
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    } 
+           
     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
     thisDateObj->setInternalValue(result);
     return result;
@@ -1574,17 +1612,37 @@ JSValue* dateProtoFuncSetYear(ExecState* exec, JSObject* thisObj, const List& ar
 
     const bool utc = false;
 
-    DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
+    DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);     
+    if (args.isEmpty()) { 
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    }
+    
     JSValue* v = thisDateObj->internalValue();
     double milli = v->toNumber(exec);
-    double secs = floor(milli / msPerSecond);
-    double ms = milli - secs * msPerSecond;
+    double ms = 0;
 
     GregorianDateTime t;
-    msToGregorianDateTime(milli, utc, t);
-
-    t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
-
+    if (isnan(milli))
+        // Based on ECMA 262 B.2.5 (setYear)
+        // the time must be reset to +0 if it is NaN. 
+        msToGregorianDateTime(0, true, t);
+    else {   
+        double secs = floor(milli / msPerSecond);
+        ms = milli - secs * msPerSecond;
+        msToGregorianDateTime(milli, utc, t);
+    }
+    
+    bool ok = true;
+    int32_t year = args[0]->toInt32(exec, ok);
+    if (!ok) {
+        JSValue* result = jsNaN();
+        thisDateObj->setInternalValue(result);
+        return result;
+    }
+            
+    t.year = (year > 99 || year < 0) ? year - 1900 : year;
     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
     thisDateObj->setInternalValue(result);
     return result;
index a30b4b19cc48f45489dc5c9f5f16e528e7ea1832..55cd7e0a012d096608bd961bafe6fced1cafda84 100644 (file)
@@ -1,3 +1,13 @@
+2008-02-20  Michael Knaup  <michael.knaup@mac.com>
+
+        Reviewed by Darin.
+
+        - test for Bug 16753: date set methods with no args should result in NaN (Acid3 bug)
+
+        * fast/js/date-set-to-nan-expected.txt: Added.
+        * fast/js/date-set-to-nan.html: Added.
+        * fast/js/resources/date-set-to-nan.js: Added.
+
 2008-02-20  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Hyatt.
diff --git a/LayoutTests/fast/js/date-set-to-nan-expected.txt b/LayoutTests/fast/js/date-set-to-nan-expected.txt
new file mode 100644 (file)
index 0000000..a643278
--- /dev/null
@@ -0,0 +1,106 @@
+This tests if the Date setters handle invalid parameters correctly resulting in a NaN date and if a recovery from such a NaN date is only possible by using the date.setTime() and date.set[[UTC]Full]Year() functions.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS date.setTime(arg0)
+PASS date.setTime()
+PASS recover from NaN date using date.setTime()
+PASS date.setTime passed all tests
+PASS date.setMilliseconds(arg0)
+PASS date.setMilliseconds()
+PASS no recovering from NaN date using date.setMilliseconds(arg0)
+PASS date.setMilliseconds passed all tests
+PASS date.setUTCMilliseconds(arg0)
+PASS date.setUTCMilliseconds()
+PASS no recovering from NaN date using date.setUTCMilliseconds(arg0)
+PASS date.setUTCMilliseconds passed all tests
+PASS date.setSeconds(arg0, arg1)
+PASS no recovering from NaN date using date.setSeconds(arg0, 0)
+PASS date.setSeconds(arg0)
+PASS date.setSeconds()
+PASS no recovering from NaN date using date.setSeconds(arg0)
+PASS date.setSeconds passed all tests
+PASS date.setUTCSeconds(arg0, arg1)
+PASS no recovering from NaN date using date.setUTCSeconds(arg0, 0)
+PASS date.setUTCSeconds(arg0)
+PASS date.setUTCSeconds()
+PASS no recovering from NaN date using date.setUTCSeconds(arg0)
+PASS date.setUTCSeconds passed all tests
+PASS date.setMinutes(arg0, arg1, arg2)
+PASS no recovering from NaN date using date.setMinutes(arg0, 0, 0)
+PASS date.setMinutes(arg0, arg1)
+PASS no recovering from NaN date using date.setMinutes(arg0, 0)
+PASS date.setMinutes(arg0)
+PASS date.setMinutes()
+PASS no recovering from NaN date using date.setMinutes(arg0)
+PASS date.setMinutes passed all tests
+PASS date.setUTCMinutes(arg0, arg1, arg2)
+PASS no recovering from NaN date using date.setUTCMinutes(arg0, 0, 0)
+PASS date.setUTCMinutes(arg0, arg1)
+PASS no recovering from NaN date using date.setUTCMinutes(arg0, 0)
+PASS date.setUTCMinutes(arg0)
+PASS date.setUTCMinutes()
+PASS no recovering from NaN date using date.setUTCMinutes(arg0)
+PASS date.setUTCMinutes passed all tests
+PASS date.setHours(arg0, arg1, arg2, arg3)
+PASS no recovering from NaN date using date.setHours(arg0, 0, 0, 0)
+PASS date.setHours(arg0, arg1, arg2)
+PASS no recovering from NaN date using date.setHours(arg0, 0, 0)
+PASS date.setHours(arg0, arg1)
+PASS no recovering from NaN date using date.setHours(arg0, 0)
+PASS date.setHours(arg0)
+PASS date.setHours()
+PASS no recovering from NaN date using date.setHours(arg0)
+PASS date.setHours passed all tests
+PASS date.setUTCHours(arg0, arg1, arg2, arg3)
+PASS no recovering from NaN date using date.setUTCHours(arg0, 0, 0, 0)
+PASS date.setUTCHours(arg0, arg1, arg2)
+PASS no recovering from NaN date using date.setUTCHours(arg0, 0, 0)
+PASS date.setUTCHours(arg0, arg1)
+PASS no recovering from NaN date using date.setUTCHours(arg0, 0)
+PASS date.setUTCHours(arg0)
+PASS date.setUTCHours()
+PASS no recovering from NaN date using date.setUTCHours(arg0)
+PASS date.setUTCHours passed all tests
+PASS date.setDate(arg0)
+PASS date.setDate()
+PASS no recovering from NaN date using date.setDate(arg0)
+PASS date.setDate passed all tests
+PASS date.setUTCDate(arg0)
+PASS date.setUTCDate()
+PASS no recovering from NaN date using date.setUTCDate(arg0)
+PASS date.setUTCDate passed all tests
+PASS date.setMonth(arg0, arg1)
+PASS no recovering from NaN date using date.setMonth(arg0, 0)
+PASS date.setMonth(arg0)
+PASS date.setMonth()
+PASS no recovering from NaN date using date.setMonth(arg0)
+PASS date.setMonth passed all tests
+PASS date.setUTCMonth(arg0, arg1)
+PASS no recovering from NaN date using date.setUTCMonth(arg0, 0)
+PASS date.setUTCMonth(arg0)
+PASS date.setUTCMonth()
+PASS no recovering from NaN date using date.setUTCMonth(arg0)
+PASS date.setUTCMonth passed all tests
+PASS date.setFullYear(arg0, arg1, arg2)
+PASS date.setFullYear(arg0, arg1)
+PASS date.setFullYear(arg0)
+PASS date.setFullYear()
+PASS recover from NaN date using date.setFullYear()
+PASS date.setFullYear passed all tests
+PASS date.setUTCFullYear(arg0, arg1, arg2)
+PASS date.setUTCFullYear(arg0, arg1)
+PASS date.setUTCFullYear(arg0)
+PASS date.setUTCFullYear()
+PASS recover from NaN date using date.setUTCFullYear()
+PASS date.setUTCFullYear passed all tests
+PASS date.setYear(arg0)
+PASS date.setYear()
+PASS date.getYear() is compatible to JavaScript 1.3 and later
+PASS recover from NaN date using date.setUTCFullYear()
+PASS date.setYear passed all tests
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/date-set-to-nan.html b/LayoutTests/fast/js/date-set-to-nan.html
new file mode 100644 (file)
index 0000000..3c61925
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/date-set-to-nan.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/resources/date-set-to-nan.js b/LayoutTests/fast/js/resources/date-set-to-nan.js
new file mode 100644 (file)
index 0000000..7af16f2
--- /dev/null
@@ -0,0 +1,452 @@
+description(
+"This tests if the Date setters handle invalid parameters correctly resulting in a NaN date and if a recovery from such a NaN date is only possible by using the date.setTime() and date.set[[UTC]Full]Year() functions."
+);
+
+var dateFunctionNameRoots = [
+    "Time",
+    "Milliseconds",
+    "UTCMilliseconds",
+    "Seconds",
+    "UTCSeconds",
+    "Minutes",
+    "UTCMinutes",
+    "Hours",
+    "UTCHours",
+    "Date",
+    "UTCDate",
+    "Month",
+    "UTCMonth",
+    "FullYear",
+    "UTCFullYear",
+    "Year"
+];
+
+var dateFunctionParameterNum = [
+    1,
+    1,
+    1,
+    2,
+    2,
+    3,
+    3,
+    4,
+    4,
+    1,
+    1,
+    2,
+    2,
+    3,
+    3,
+    1
+];
+
+var testValues = [
+    0,
+    Number.NaN,
+    Number.POSITIVE_INFINITY,
+    Number.NEGATIVE_INFINITY
+];
+
+function testDateFunctionWithValueNoRecoverNaN(functionNameRoot, steps)
+{
+    var date = new Date();
+    var setValue = date["get" + functionNameRoot]();    
+    date.setMilliseconds(Number.NaN);
+    var params = [
+        "",
+        ", 0",
+        ", 0, 0",
+        ", 0, 0, 0"
+    ];
+    var setResult = (1 == steps) ?  date["set" + functionNameRoot](setValue)
+                  : ((2 == steps) ? date["set" + functionNameRoot](setValue, 0)
+                  : ((3 == steps) ? date["set" + functionNameRoot](setValue, 0, 0)
+                  :                  date["set" + functionNameRoot](setValue, 0, 0, 0)));
+    if (!isNaN(setResult)) {
+        testFailed("date(NaN).set" + functionNameRoot + "(" + setValue + params[steps - 1]
+                                   + ") was " + setResult + " instead of NaN");
+        return false;
+    }
+    var getResult = date["get" + functionNameRoot]();
+    if (!isNaN(getResult)) {
+        testFailed("date.get" + functionNameRoot + "() was " + getResult + " instead of NaN");
+        return false;
+    }
+    testPassed ("no recovering from NaN date using date.set" + functionNameRoot 
+        + "(arg0" + params[steps - 1] + ")");
+    return true;
+}
+
+function testDateFunctionWithValueRecoverTime(functionNameRoot)
+{
+    var date = new Date();
+    var setValue = date["get" + functionNameRoot]();    
+    date.setMilliseconds(Number.NaN);
+    var setResult = date["set" + functionNameRoot](setValue);
+    if (setValue != setResult) {
+        testFailed("date(NaN).set" + functionNameRoot + "(" + setValue + ") was " + setResult + " instead of " + setValue);
+        return false;
+    }
+    var getResult = date["get" + functionNameRoot]();
+    if (getResult != setValue) {
+        testFailed("date.get" + functionNameRoot + "() was " + getResult + " instead of " + setValue);
+        return false;
+    }
+    testPassed ("recover from NaN date using date.set" + functionNameRoot + "()");
+    return true;
+}
+
+function testDateFunctionWithValueRecoverFullYear(functionNameRoot)
+{
+    var result = true;
+    var date = new Date();
+    var setValue = date["get" + functionNameRoot]();    
+    date.setMilliseconds(Number.NaN);
+    var setResult = date["set" + functionNameRoot](setValue);    
+    var getResult = date["get" + functionNameRoot]();
+    if (getResult != setValue) {
+        testFailed("date.get" + functionNameRoot + "() was " + getResult + " instead of " + setValue);
+        result = false;
+    }
+    getResult = date.getMilliseconds();
+    if (getResult != 0) {
+        testFailed("date.getMilliseconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getSeconds();
+    if (getResult != 0) {
+        testFailed("date.getSeconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getMinutes();
+    if (getResult != 0) {
+        testFailed("date.getMinutes() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getHours();
+    if (getResult != 0) {
+        testFailed("date.getHours() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getDate();
+    if (getResult != 1) {
+        testFailed("date.getDate() was " + getResult + " instead of 1");
+        result = false;
+    }
+    getResult = date.getMonth();
+    if (getResult != 0) {
+        testFailed("date.getMonth() was " + getResult + " instead of 0");
+        result = false;
+    }
+    if (result)
+        testPassed ("recover from NaN date using date.setFullYear()");
+    else
+        testFailed ("recover from NaN date using date.setFullYear()");
+    return result;
+}
+
+function testDateFunctionWithValueRecoverUTCFullYear(functionNameRoot)
+{
+    var result = true; 
+    var date = new Date();
+    var setValue = date["get" + functionNameRoot]();    
+    date.setMilliseconds(Number.NaN);
+    var setResult = date["set" + functionNameRoot](setValue);    
+    var getResult = date["get" + functionNameRoot]();
+    if (getResult != setValue) {
+        testFailed("date.get" + functionNameRoot + "() was " + getResult + " instead of " + setValue);
+        result = false;
+    }
+    getResult = date.getUTCMilliseconds();
+    if (getResult != 0) {
+        testFailed("date.getUTCMilliseconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getUTCSeconds();
+    if (getResult != 0) {
+        testFailed("date.getUTCSeconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getUTCMinutes();
+    if (getResult != 0) {
+        testFailed("date.getUTCMinutes() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getUTCHours();
+    if (getResult != 0) {
+        testFailed("date.getUTCHours() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getUTCDate();
+    if (getResult != 1) {
+        testFailed("date.getUTCDate() was " + getResult + " instead of 1");
+        result = false;
+    }
+    getResult = date.getUTCMonth();
+    if (getResult != 0) {
+        testFailed("date.getUTCMonth() was " + getResult + " instead of 0");
+        result = false;
+    }
+    if (result)
+        testPassed ("recover from NaN date using date.setUTCFullYear()");
+    else
+        testFailed ("recover from NaN date using date.setUTCFullYear()");
+    return result;
+}
+
+function testDateFunctionWithValueRecoverYear(functionNameRoot)
+{
+    var result = true;
+    var is13Compatible = true;
+    
+    var date = new Date();
+    var setValue = date["get" + functionNameRoot]();
+    var fullYears = date.getFullYear() - 1900;    
+    if (setValue != fullYears) {
+        testFailed("date.get" + functionNameRoot + "() was " + setValue + " instead of " + fullYears);
+        is13Compatible = false;
+    } else 
+        testPassed("date.getYear() is compatible to JavaScript 1.3 and later");
+    
+    date.setMilliseconds(Number.NaN);
+    var setResult = date["set" + functionNameRoot](setValue + 1900);        
+    var getResult = date["get" + functionNameRoot]();
+    if (getResult != setValue) {
+        testFailed("date.get" + functionNameRoot + "() was " + getResult + " instead of " + setValue);
+        result = false;
+    }
+    getResult = date.getMilliseconds();
+    if (getResult != 0) {
+        testFailed("date.getMilliseconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getSeconds();
+    if (getResult != 0) {
+        testFailed("date.getSeconds() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getMinutes();
+    if (getResult != 0) {
+        testFailed("date.getMinutes() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getHours();
+    if (getResult != 0) {
+        testFailed("date.getHours() was " + getResult + " instead of 0");
+        result = false;
+    }
+    getResult = date.getDate();
+    if (getResult != 1) {
+        testFailed("date.getDate() was " + getResult + " instead of 1");
+        result = false;
+    }
+    getResult = date.getMonth();
+    if (getResult != 0) {
+        testFailed("date.getMonth() was " + getResult + " instead of 0");
+        result = false;
+    }
+    if (result)
+        testPassed ("recover from NaN date using date.setUTCFullYear()");
+    else
+        testFailed ("recover from NaN date using date.setUTCFullYear()");
+    return result && is13Compatible;
+}
+
+function makeIEHappy(functionNameRoot, value)
+{    
+    var date = new Date();
+    var setResult = date["set" + functionNameRoot](value);
+    if (!isNaN(setResult)) {
+        testFailed("date.set" + functionNameRoot 
+                              + "() was " 
+                              + setResult + " instead of NaN");                                                                       
+         return false;
+    }
+    var getResult = date["get" + functionNameRoot]();
+    if (!isNaN(getResult)) {
+        testFailed("date.get" + functionNameRoot + "() was "
+                              + getResult + " instead of NaN");
+        return false;
+    }   
+    return true
+}
+
+function testDateFunctionWithValueExpectingNaN1(functionNameRoot)
+{
+    var result = true;
+    for (var idx0 in testValues)
+        if (idx0 != 0) {
+            var date = new Date();
+            var setResult = date["set" + functionNameRoot](testValues[idx0]);
+            if (!isNaN(setResult)) {
+                testFailed("date.set" + functionNameRoot + "(" 
+                                      + testValues[idx0] + ") was " 
+                                      + setResult + " instead of NaN");                                                                       
+                result = false;
+            }
+            var getResult = date["get" + functionNameRoot]();
+            if (!isNaN(getResult)) {
+                testFailed("date.get" + functionNameRoot + "() was "
+                                      + getResult + " instead of NaN");
+                result = false;
+            }                                               
+        } else if (!makeIEHappy(functionNameRoot))
+            result = false;
+    if (result) { 
+        testPassed("date.set" + functionNameRoot + "(arg0)");
+        testPassed("date.set" + functionNameRoot + "()");
+    }
+    return result;
+}
+
+function testDateFunctionWithValueExpectingNaN2(functionNameRoot)
+{
+    var result = true;
+    for (var idx0 in testValues)
+        for (var idx1 in testValues)
+            if (idx0 != 0 || idx1 != 0) {
+                var date = new Date();
+                var setResult = date["set" + functionNameRoot](testValues[idx0],
+                                                               testValues[idx1]);
+                
+                if (!isNaN(setResult)) {
+                    testFailed("date.set" + functionNameRoot + "(" 
+                                          + testValues[idx0] + ", "
+                                          + testValues[idx1] + ") was " 
+                                          + setResult + " instead of NaN");                                                                       
+                    result = false;
+                }
+                var getResult = date["get" + functionNameRoot]();
+                if (!isNaN(getResult)) {
+                    testFailed("date.get" + functionNameRoot + "() was "
+                                          + getResult + " instead of NaN");
+                    result = false;
+                }                                               
+            }
+    
+    if (result) 
+        testPassed("date.set" + functionNameRoot + "(arg0, arg1)");
+    return result;
+}
+
+function testDateFunctionWithValueExpectingNaN3(functionNameRoot)
+{
+    var result = true;
+    for (var idx0 in testValues)
+        for (var idx1 in testValues)
+            for (var idx2 in testValues)
+                if (idx0 != 0 || idx1 != 0 || idx2 != 0) {
+                    var date = new Date();
+                    var setResult = date["set" + functionNameRoot](testValues[idx0],
+                                                                   testValues[idx1],
+                                                                   testValues[idx2]);
+                    if (!isNaN(setResult)) {
+                        testFailed("date.set" + functionNameRoot + "(" 
+                                              + testValues[idx0] + ", "
+                                              + testValues[idx1] + ", "
+                                              + testValues[idx2] + ") was " 
+                                              + setResult + " instead of NaN");                                                                       
+                        result = false;
+                    }
+                    var getResult = date["get" + functionNameRoot]();
+                    if (!isNaN(getResult)) {
+                        testFailed("date.get" + functionNameRoot + "() was "
+                                              + getResult + " instead of NaN");
+                        result = false;
+                    }                                               
+                }
+                
+    if (result) 
+        testPassed("date.set" + functionNameRoot + "(arg0, arg1, arg2)");
+    return result;
+}
+
+function testDateFunctionWithValueExpectingNaN4(functionNameRoot)
+{
+    var result = true;
+    for (var idx0 in testValues)
+        for (var idx1 in testValues)
+            for (var idx2 in testValues)
+                for (var idx3 in testValues)
+                    if (idx0 != 0 || idx1 != 0 || idx2 != 0 || idx3 != 0) {
+                        var date = new Date();
+                        var setResult = date["set" + functionNameRoot](testValues[idx0],
+                                                                       testValues[idx1],
+                                                                       testValues[idx2],
+                                                                       testValues[idx3]);
+                        if (!isNaN(setResult)) {
+                            testFailed("date.set" + functionNameRoot + "(" 
+                                                  + testValues[idx0] + ", "
+                                                  + testValues[idx1] + ", "
+                                                  + testValues[idx2] + ", "
+                                                  + testValues[idx3] + ") was " 
+                                                  + setResult + " instead of NaN");                                                                       
+                            result = false;
+                        }
+                        var getResult = date["get" + functionNameRoot]();
+                        if (!isNaN(getResult)) {
+                            testFailed("date.get" + functionNameRoot + "() was "
+                                                  + getResult + " instead of NaN");
+                            result = false;
+                        }                                          
+                    }
+    if (result) 
+        testPassed("date.set" + functionNameRoot + "(arg0, arg1, arg2, arg3)");
+    return result;
+}
+
+
+
+function testDateFunction(functionNameRoot, functionParamNum)
+{
+    var success = true;
+    
+    switch (functionParamNum) {
+    case 4:
+        success &= testDateFunctionWithValueExpectingNaN4(functionNameRoot);
+        if (functionNameRoot != "Time" &&
+            functionNameRoot != "FullYear" &&
+            functionNameRoot != "UTCFullYear" &&
+            functionNameRoot != "Year")
+            success &= testDateFunctionWithValueNoRecoverNaN(functionNameRoot, 4);
+
+    case 3:
+        success &= testDateFunctionWithValueExpectingNaN3(functionNameRoot);
+        if (functionNameRoot != "Time" &&
+            functionNameRoot != "FullYear" &&
+            functionNameRoot != "UTCFullYear" &&
+            functionNameRoot != "Year")
+            success &= testDateFunctionWithValueNoRecoverNaN(functionNameRoot, 3);
+        
+    case 2:
+        success &= testDateFunctionWithValueExpectingNaN2(functionNameRoot);
+        if (functionNameRoot != "Time" &&
+            functionNameRoot != "FullYear" &&
+            functionNameRoot != "UTCFullYear" &&
+            functionNameRoot != "Year")
+            success &= testDateFunctionWithValueNoRecoverNaN(functionNameRoot, 2);
+        
+    case 1:
+        success &= testDateFunctionWithValueExpectingNaN1(functionNameRoot);
+        if (functionNameRoot == "Time")
+            success &= testDateFunctionWithValueRecoverTime(functionNameRoot);       
+        else if (functionNameRoot == "FullYear")
+            success &= testDateFunctionWithValueRecoverFullYear(functionNameRoot);
+        else if (functionNameRoot == "UTCFullYear")
+            success &= testDateFunctionWithValueRecoverUTCFullYear(functionNameRoot);
+        else if (functionNameRoot == "Year")
+            success &= testDateFunctionWithValueRecoverYear(functionNameRoot);
+        else
+            success &= testDateFunctionWithValueNoRecoverNaN(functionNameRoot, 1);
+    }
+        
+    if (success)
+        testPassed("date.set" + functionNameRoot + " passed all tests");
+}
+
+for (var x in dateFunctionNameRoots)
+{
+    testDateFunction(dateFunctionNameRoots[x], dateFunctionParameterNum[x]);
+}
+
+var successfullyParsed = true;