зеркало из https://github.com/mozilla/pjs.git
Bug 584811 - Date.prototype.toJSON isn't to spec. r=sayrer
This commit is contained in:
Родитель
9878311f34
Коммит
d87ea1a7e8
|
@ -332,3 +332,4 @@ MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed wh
|
|||
MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
|
||||
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
|
||||
MSG_DEF(JSMSG_THROW_TYPE_ERROR, 252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
|
||||
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
|
||||
|
|
|
@ -148,6 +148,7 @@ const char *const js_common_atom_names[] = {
|
|||
js_ignoreCase_str, /* ignoreCaseAtom */
|
||||
js_index_str, /* indexAtom */
|
||||
js_input_str, /* inputAtom */
|
||||
"toISOString", /* toISOStringAtom */
|
||||
js_iterator_str, /* iteratorAtom */
|
||||
js_join_str, /* joinAtom */
|
||||
js_lastIndex_str, /* lastIndexAtom */
|
||||
|
|
|
@ -340,6 +340,7 @@ struct JSAtomState
|
|||
JSAtom *ignoreCaseAtom;
|
||||
JSAtom *indexAtom;
|
||||
JSAtom *inputAtom;
|
||||
JSAtom *toISOStringAtom;
|
||||
JSAtom *iteratorAtom;
|
||||
JSAtom *joinAtom;
|
||||
JSAtom *lastIndexAtom;
|
||||
|
|
|
@ -2012,6 +2012,58 @@ date_toISOString(JSContext *cx, uintN argc, Value *vp)
|
|||
return date_utc_format(cx, vp, print_iso_string);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* ES5 15.9.5.44. */
|
||||
JSBool
|
||||
date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Step 1. */
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Step 2. */
|
||||
Value &tv = vp[0];
|
||||
if (!DefaultValue(cx, obj, JSTYPE_NUMBER, &tv))
|
||||
return false;
|
||||
|
||||
/* Step 3. */
|
||||
if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
|
||||
vp->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Step 4. */
|
||||
Value &toISO = vp[0];
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.toISOStringAtom), &toISO))
|
||||
return false;
|
||||
|
||||
/* Step 5. */
|
||||
if (!js_IsCallable(toISO)) {
|
||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_TOISOSTRING_PROP);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Step 6. */
|
||||
LeaveTrace(cx);
|
||||
InvokeArgsGuard args;
|
||||
if (!cx->stack().pushInvokeArgs(cx, 0, args))
|
||||
return false;
|
||||
|
||||
args.callee() = toISO;
|
||||
args.thisv().setObject(*obj);
|
||||
|
||||
if (!Invoke(cx, args, 0))
|
||||
return false;
|
||||
|
||||
*vp = args.rval();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* for Date.toLocaleString; interface to PRMJTime date struct.
|
||||
*/
|
||||
static void
|
||||
|
@ -2407,7 +2459,7 @@ static JSFunctionSpec date_methods[] = {
|
|||
JS_FN("toDateString", date_toDateString, 0,0),
|
||||
JS_FN("toTimeString", date_toTimeString, 0,0),
|
||||
JS_FN("toISOString", date_toISOString, 0,0),
|
||||
JS_FN(js_toJSON_str, date_toISOString, 0,0),
|
||||
JS_FN(js_toJSON_str, date_toJSON, 1,0),
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, date_toSource, 0,0),
|
||||
#endif
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/Date/
|
||||
script 15.9.4.2.js
|
||||
script toJSON-01.js
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'toJSON-01.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 584811;
|
||||
var summary = "Date.prototype.toJSON isn't to spec";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var called;
|
||||
|
||||
var dateToJSON = Date.prototype.toJSON;
|
||||
assertEq(Date.prototype.hasOwnProperty("toJSON"), true);
|
||||
assertEq(typeof dateToJSON, "function");
|
||||
|
||||
// brief test to exercise this outside of isolation, just for sanity
|
||||
var invalidDate = new Date();
|
||||
invalidDate.setTime(NaN);
|
||||
assertEq(JSON.stringify({ p: invalidDate }), '{"p":null}');
|
||||
|
||||
|
||||
/* 15.9.5.44 Date.prototype.toJSON ( key ) */
|
||||
assertEq(dateToJSON.length, 1);
|
||||
|
||||
/*
|
||||
* 1. Let O be the result of calling ToObject, giving it the this value as its
|
||||
* argument.
|
||||
*/
|
||||
function strictThis() { "use strict"; return this; }
|
||||
if (strictThis.call(null) === null)
|
||||
{
|
||||
try
|
||||
{
|
||||
dateToJSON.call(null);
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"ToObject throws TypeError for null/undefined");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dateToJSON.call(undefined);
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"ToObject throws TypeError for null/undefined");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 2. Let tv be ToPrimitive(O, hint Number).
|
||||
* ...expands to:
|
||||
* 1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
|
||||
* 2. If IsCallable(valueOf) is true then,
|
||||
* a. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and
|
||||
* an empty argument list.
|
||||
* b. If val is a primitive value, return val.
|
||||
* 3. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
|
||||
* 4. If IsCallable(toString) is true then,
|
||||
* a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and
|
||||
* an empty argument list.
|
||||
* b. If str is a primitive value, return str.
|
||||
* 5. Throw a TypeError exception.
|
||||
*/
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ get valueOf() { throw 17; } });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e, 17, "bad exception: " + e);
|
||||
}
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: null,
|
||||
toString: function() { called = true; return 12; },
|
||||
toISOString: function() { return "ohai"; } }),
|
||||
"ohai");
|
||||
assertEq(called, true);
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return 42; },
|
||||
toISOString: function() { return null; } }),
|
||||
null);
|
||||
assertEq(called, true);
|
||||
|
||||
try
|
||||
{
|
||||
called = false;
|
||||
dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString() { throw 42; } });
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(called, true);
|
||||
assertEq(e, 42, "bad exception: " + e);
|
||||
}
|
||||
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString() { return function() { return 8675309; }; },
|
||||
toISOString: function() { return true; } }),
|
||||
true);
|
||||
assertEq(called, true);
|
||||
|
||||
var asserted = false;
|
||||
called = false;
|
||||
assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
|
||||
get toString()
|
||||
{
|
||||
assertEq(called, true);
|
||||
asserted = true;
|
||||
return function() { return 8675309; };
|
||||
},
|
||||
toISOString: function() { return NaN; } }),
|
||||
NaN);
|
||||
assertEq(asserted, true);
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ valueOf: null, toString: null,
|
||||
get toISOString()
|
||||
{
|
||||
throw new Error("shouldn't have been gotten");
|
||||
} });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/* 3. If tv is a Number and is not finite, return null. */
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return Infinity; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return NaN; } }), null);
|
||||
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return Infinity; },
|
||||
toISOString: function() { return {}; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; },
|
||||
toISOString: function() { return []; } }), null);
|
||||
assertEq(dateToJSON.call({ valueOf: function() { return NaN; },
|
||||
toISOString: function() { return undefined; } }), null);
|
||||
|
||||
|
||||
/*
|
||||
* 4. Let toISO be the result of calling the [[Get]] internal method of O with
|
||||
* argument "toISOString".
|
||||
*/
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ get toISOString() { throw 42; } });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e, 42, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/* 5. If IsCallable(toISO) is false, throw a TypeError exception. */
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: null });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: undefined });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: "oogabooga" });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = dateToJSON.call({ toISOString: Math.PI });
|
||||
throw new Error("didn't throw, returned: " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true, "bad exception: " + e);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 6. Return the result of calling the [[Call]] internal method of toISO with O
|
||||
* as the this value and an empty argument list.
|
||||
*/
|
||||
var o =
|
||||
{
|
||||
toISOString: function(a)
|
||||
{
|
||||
called = true;
|
||||
assertEq(this, o);
|
||||
assertEq(a, undefined);
|
||||
assertEq(arguments.length, 0);
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
var obj = {};
|
||||
called = false;
|
||||
assertEq(dateToJSON.call(o), obj, "should have gotten obj back");
|
||||
assertEq(called, true);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
Загрузка…
Ссылка в новой задаче