8011382: Data prototype methods and constructor do not call user defined toISOString, valueOf methods per spec

Reviewed-by: lagergren, jlaskey
This commit is contained in:
Athijegannathan Sundararajan 2013-04-03 20:17:05 +05:30
parent 6b89fa96a3
commit 84f1ee1581
2 changed files with 134 additions and 10 deletions

View File

@ -844,10 +844,6 @@ public final class NativeDate extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object toJSON(final Object self, final Object key) {
if (self instanceof NativeDate) {
final NativeDate nd = (NativeDate)self;
return (isNaN(nd.getTime())) ? null : toISOStringImpl(nd);
}
// NOTE: Date.prototype.toJSON is generic. Accepts other objects as well.
final Object selfObj = Global.toObject(self);
if (!(selfObj instanceof ScriptObject)) {
@ -1200,13 +1196,18 @@ public final class NativeDate extends ScriptObject {
// Convert Date constructor args, checking for NaN, filling in defaults etc.
private static double[] convertCtorArgs(final Object[] args) {
final double[] d = new double[7];
boolean nullReturn = false;
// should not bailout on first NaN or infinite. Need to convert all
// subsequent args for possible side-effects via valueOf/toString overrides
// on argument objects.
for (int i = 0; i < d.length; i++) {
if (i < args.length) {
final double darg = JSType.toNumber(args[i]);
if (isNaN(darg) || isInfinite(darg)) {
return null;
nullReturn = true;
}
d[i] = (long)darg;
} else {
d[i] = i == 2 ? 1 : 0; // day in month defaults to 1
@ -1217,31 +1218,39 @@ public final class NativeDate extends ScriptObject {
d[0] += 1900;
}
return d;
return nullReturn? null : d;
}
// This method does the hard work for all setter methods: If a value is provided
// as argument it is used, otherwise the value is calculated from the existing time value.
private static double[] convertArgs(final Object[] args, final double time, final int fieldId, final int start, final int length) {
final double[] d = new double[length];
boolean nullReturn = false;
// Need to call toNumber on all args for side-effects - even if an argument
// fails to convert to number, subsequent toNumber calls needed for possible
// side-effects via valueOf/toString overrides.
for (int i = start; i < start + length; i++) {
if (fieldId <= i && i < fieldId + args.length) {
final double darg = JSType.toNumber(args[i - fieldId]);
if (isNaN(darg) || isInfinite(darg)) {
return null;
nullReturn = true;
}
d[i - start] = (long) darg;
} else {
// Date.prototype.set* methods require first argument to be defined
if (i == fieldId) {
return null;
nullReturn = true;
}
if (! nullReturn) {
d[i - start] = valueFromTime(i, time);
}
d[i - start] = valueFromTime(i, time);
}
}
return d;
return nullReturn? null : d;
}
// ECMA 15.9.1.14 TimeClip (time)

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8011382: Data prototype methods and constructor do not call user defined toISOString, valueOf methods per spec.
*
* @test
* @run
*/
var yearValueOf = 0;
var monthValueOf = 0;
var dayValueOf = 0;
var d = new Date(
{
valueOf: function() { yearValueOf++; return NaN; }
},
{
valueOf: function() { monthValueOf++; return NaN; }
},
{
valueOf: function() { dayValueOf++; return NaN; }
}
);
if (yearValueOf !== 1) {
fail("Date constructor does not call valueOf on year argument once");
}
if (monthValueOf !== 1) {
fail("Date constructor does not call valueOf on month argument once");
}
if (dayValueOf !== 1) {
fail("Date constructor does not call valueOf on day argument once");
}
yearValueOf = 0;
monthValueOf = 0;
dayValueOf = 0;
d = new Date();
d.setFullYear(
{
valueOf: function() { yearValueOf++; return NaN; }
},
{
valueOf: function() { monthValueOf++; return NaN; }
},
{
valueOf: function() { dayValueOf++; return NaN; }
}
);
if (yearValueOf !== 1) {
fail("Date setFullYear does not call valueOf on year argument once");
}
if (monthValueOf !== 1) {
fail("Date setFullYear does not call valueOf on month argument once");
}
if (dayValueOf !== 1) {
fail("Date setFullYear does not call valueOf on day argument once");
}
// check toJSON calls toISOString override
var toISOStringCalled = 0;
d = new Date();
d.toISOString = function() {
toISOStringCalled++;
};
d.toJSON();
if (toISOStringCalled !== 1) {
fail("toISOString was not called by Date.prototype.toJSON once");
}
toISOStringCalled = 0;
// toJSON is generic - try for non-Date object
Date.prototype.toJSON.call({
toISOString: function() {
toISOStringCalled++;
},
valueOf: function() {
return 12;
}
});
if (toISOStringCalled !== 1) {
fail("toISOString was not called by Date.prototype.toJSON once");
}