diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index abc0141f5a9..00000000000 --- a/.jshintrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "predef": ["Intl"], - "esversion": 6 -} diff --git a/harness/propertyHelper.js b/harness/propertyHelper.js index 0ee7e21a928..7068f2560cc 100644 --- a/harness/propertyHelper.js +++ b/harness/propertyHelper.js @@ -6,13 +6,13 @@ description: | property descriptors. defines: - verifyProperty - - verifyEqualTo - - verifyWritable - - verifyNotWritable - - verifyEnumerable - - verifyNotEnumerable - - verifyConfigurable - - verifyNotConfigurable + - verifyEqualTo # deprecated + - verifyWritable # deprecated + - verifyNotWritable # deprecated + - verifyEnumerable # deprecated + - verifyNotEnumerable # deprecated + - verifyConfigurable # deprecated + - verifyNotConfigurable # deprecated ---*/ // @ts-check @@ -173,6 +173,9 @@ function isWritable(obj, name, verifyProp, value) { return writeSucceeded; } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyEqualTo(obj, name, value) { if (!isSameValue(obj[name], value)) { throw new Test262Error("Expected obj[" + String(name) + "] to equal " + value + @@ -180,6 +183,9 @@ function verifyEqualTo(obj, name, value) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyWritable(obj, name, verifyProp, value) { if (!verifyProp) { assert(Object.getOwnPropertyDescriptor(obj, name).writable, @@ -190,6 +196,9 @@ function verifyWritable(obj, name, verifyProp, value) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyNotWritable(obj, name, verifyProp, value) { if (!verifyProp) { assert(!Object.getOwnPropertyDescriptor(obj, name).writable, @@ -200,6 +209,9 @@ function verifyNotWritable(obj, name, verifyProp, value) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyEnumerable(obj, name) { assert(Object.getOwnPropertyDescriptor(obj, name).enumerable, "Expected obj[" + String(name) + "] to have enumerable:true."); @@ -208,6 +220,9 @@ function verifyEnumerable(obj, name) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyNotEnumerable(obj, name) { assert(!Object.getOwnPropertyDescriptor(obj, name).enumerable, "Expected obj[" + String(name) + "] to have enumerable:false."); @@ -216,6 +231,9 @@ function verifyNotEnumerable(obj, name) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyConfigurable(obj, name) { assert(Object.getOwnPropertyDescriptor(obj, name).configurable, "Expected obj[" + String(name) + "] to have configurable:true."); @@ -224,6 +242,9 @@ function verifyConfigurable(obj, name) { } } +/** + * Deprecated; please use `verifyProperty` in new tests. + */ function verifyNotConfigurable(obj, name) { assert(!Object.getOwnPropertyDescriptor(obj, name).configurable, "Expected obj[" + String(name) + "] to have configurable:false."); diff --git a/harness/temporalHelpers.js b/harness/temporalHelpers.js index 3a2ed5e4d45..c9b7645b7f1 100644 --- a/harness/temporalHelpers.js +++ b/harness/temporalHelpers.js @@ -238,39 +238,6 @@ var TemporalHelpers = { }); }, - /* - * checkFractionalSecondDigitsOptionWrongType(temporalObject): - * - * Checks the string-or-number type handling of the fractionalSecondDigits - * option to the various types' toString() methods. temporalObject is an - * instance of the Temporal type under test. - */ - checkFractionalSecondDigitsOptionWrongType(temporalObject) { - // null is not a number, and converts to the string "null", which is an invalid string value - assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: null }), "null"); - // Booleans are not numbers, and convert to the strings "true" or "false", which are invalid - assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: true }), "true"); - assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: false }), "false"); - // Symbols are not numbers and cannot convert to strings - assert.throws(TypeError, () => temporalObject.toString({ fractionalSecondDigits: Symbol() }), "symbol"); - // BigInts are not numbers and convert to strings which are invalid - assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: 2n }), "bigint"); - - // Objects are not numbers and prefer their toString() methods when converting to a string - assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: {} }), "plain object"); - - const toStringExpected = temporalObject.toString({ fractionalSecondDigits: 'auto' }); - const expected = [ - "get fractionalSecondDigits.toString", - "call fractionalSecondDigits.toString", - ]; - const actual = []; - const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); - const result = temporalObject.toString({ fractionalSecondDigits: observer }); - assert.sameValue(result, toStringExpected, "object with toString"); - assert.compareArray(actual, expected, "order of operations"); - }, - /* * checkPlainDateTimeConversionFastPath(func): * @@ -1034,6 +1001,44 @@ var TemporalHelpers = { return new CalendarFieldsIterable(); }, + /* + * A custom calendar that asserts its ...FromFields() methods are called with + * the options parameter having the value undefined. + */ + calendarFromFieldsUndefinedOptions() { + class CalendarFromFieldsUndefinedOptions extends Temporal.Calendar { + constructor() { + super("iso8601"); + this.dateFromFieldsCallCount = 0; + this.monthDayFromFieldsCallCount = 0; + this.yearMonthFromFieldsCallCount = 0; + } + + toString() { + return "from-fields-undef-options"; + } + + dateFromFields(fields, options) { + this.dateFromFieldsCallCount++; + assert.sameValue(options, undefined, "dateFromFields shouldn't be called with options"); + return super.dateFromFields(fields, options); + } + + yearMonthFromFields(fields, options) { + this.yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return super.yearMonthFromFields(fields, options); + } + + monthDayFromFields(fields, options) { + this.monthDayFromFieldsCallCount++; + assert.sameValue(options, undefined, "monthDayFromFields shouldn't be called with options"); + return super.monthDayFromFields(fields, options); + } + } + return new CalendarFromFieldsUndefinedOptions(); + }, + /* * A custom calendar that modifies the fields object passed in to * dateFromFields, sabotaging its time properties. @@ -1312,10 +1317,10 @@ var TemporalHelpers = { if (this._shiftNanoseconds > 0) { if (this._isBeforeShift(instant)) return [instant]; if (instant.epochNanoseconds < this._epoch2) return []; - return [instant.add(this._shift)]; + return [instant.subtract(this._shift)]; } if (instant.epochNanoseconds < this._epoch2) return [instant]; - const shifted = instant.add(this._shift); + const shifted = instant.subtract(this._shift); if (this._isBeforeShift(instant)) return [instant, shifted]; return [shifted]; } diff --git a/implementation-contributed/v8/mjsunit/harmony/to-number.js b/implementation-contributed/v8/mjsunit/harmony/to-number.js index a48a7d83f8c..e145782d4b9 100644 --- a/implementation-contributed/v8/mjsunit/harmony/to-number.js +++ b/implementation-contributed/v8/mjsunit/harmony/to-number.js @@ -19,6 +19,8 @@ assertEquals(NaN, %ToNumber(undefined)); assertEquals(-1, %ToNumber("-1")); assertEquals(123, %ToNumber("123")); assertEquals(NaN, %ToNumber("random text")); +assertEquals(NaN, %ToNumber("INFINITY")); +assertEquals(NaN, %ToNumber("infinity")); assertThrows(function() { %ToNumber(Symbol.toPrimitive) }, TypeError); diff --git a/test/built-ins/Function/prototype/bind/instance-length-tointeger.js b/test/built-ins/Function/prototype/bind/instance-length-tointeger.js index 876ed47b516..92aaf1a3160 100644 --- a/test/built-ins/Function/prototype/bind/instance-length-tointeger.js +++ b/test/built-ins/Function/prototype/bind/instance-length-tointeger.js @@ -13,12 +13,15 @@ info: | 5. Let targetHasLength be ? HasOwnProperty(Target, "length"). 6. If targetHasLength is true, then a. Let targetLen be ? Get(Target, "length"). - b. If Type(targetLen) is not Number, let L be 0. - c. Else, - i. Set targetLen to ! ToInteger(targetLen). - ii. Let L be the larger of 0 and the result of targetLen minus the number of elements of args. - 7. Else, let L be 0. - 8. Perform ! SetFunctionLength(F, L). + b. If Type(targetLen) is Number, then + i. If targetLen is +∞𝔽, set L to +∞. + ii. Else if targetLen is -∞𝔽, set L to 0. + iii. Else, + 1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen). + 2. Assert: targetLenAsInt is finite. + 3. Let argCount be the number of elements in args. + 4. Set L to max(targetLenAsInt - argCount, 0). + 7. Perform ! SetFunctionLength(F, L). [...] ToInteger ( argument ) @@ -40,10 +43,12 @@ Object.defineProperty(fn, "length", {value: -0}); assert.sameValue(fn.bind().length, 0); Object.defineProperty(fn, "length", {value: Infinity}); -assert.sameValue(fn.bind().length, Infinity); +assert.sameValue(fn.bind().length, Infinity, "target length of infinity, zero bound arguments"); +assert.sameValue(fn.bind(0, 0).length, Infinity, "target length of infinity, one bound argument"); Object.defineProperty(fn, "length", {value: -Infinity}); -assert.sameValue(fn.bind().length, 0); +assert.sameValue(fn.bind().length, 0, "target length of negative infinity, zero bound arguments"); +assert.sameValue(fn.bind(0, 0).length, 0, "target length of negative infinity, one bound argument"); Object.defineProperty(fn, "length", {value: 3.66}); assert.sameValue(fn.bind().length, 3); diff --git a/test/built-ins/Number/S15.7.1.1_A1.js b/test/built-ins/Number/S15.7.1.1_A1.js index 3ccfaf32ae3..adf4f19515e 100644 --- a/test/built-ins/Number/S15.7.1.1_A1.js +++ b/test/built-ins/Number/S15.7.1.1_A1.js @@ -24,3 +24,5 @@ assert.sameValue( ); assert.sameValue(Number("abc"), NaN, 'Number("abc") returns NaN'); +assert.sameValue(Number("INFINITY"), NaN, 'Number("INFINITY") returns NaN'); +assert.sameValue(Number("infinity"), NaN, 'Number("infinity") returns NaN'); diff --git a/test/built-ins/ShadowRealm/WrappedFunction/throws-typeerror-on-revoked-proxy.js b/test/built-ins/ShadowRealm/WrappedFunction/throws-typeerror-on-revoked-proxy.js index b05d708a78d..ee964823a24 100644 --- a/test/built-ins/ShadowRealm/WrappedFunction/throws-typeerror-on-revoked-proxy.js +++ b/test/built-ins/ShadowRealm/WrappedFunction/throws-typeerror-on-revoked-proxy.js @@ -3,7 +3,7 @@ /*--- esid: sec-wrapped-function-exotic-objects-call-thisargument-argumentslist description: > - WrappedFunctionCreate throws a TypeError the target is a revoked proxy. + WrappedFunctionCreate throws a TypeError the target is a revoked proxy. info: | WrappedFunctionCreate ( callerRealm: a Realm Record, Target: a function object, ) diff --git a/test/built-ins/ShadowRealm/prototype/evaluate/globalthis-orginary-object.js b/test/built-ins/ShadowRealm/prototype/evaluate/globalthis-ordinary-object.js similarity index 81% rename from test/built-ins/ShadowRealm/prototype/evaluate/globalthis-orginary-object.js rename to test/built-ins/ShadowRealm/prototype/evaluate/globalthis-ordinary-object.js index fd71e910268..d59e77078d1 100644 --- a/test/built-ins/ShadowRealm/prototype/evaluate/globalthis-orginary-object.js +++ b/test/built-ins/ShadowRealm/prototype/evaluate/globalthis-ordinary-object.js @@ -64,3 +64,27 @@ assert.sameValue( true, 'globalThis.constructor is Object' ); + +assert.sameValue( + r.evaluate(` + let result; + try { + globalThis.__proto__ = {x: 2}; + result = true; + } catch (e) { + result = false; + } + result; + `), + true, + 'Can assign to globalThis.__proto__ directly' +); + +assert.sameValue( + r.evaluate(` + Reflect.set(globalThis, '__proto__', {x: 1}) && + Reflect.setPrototypeOf(globalThis.__proto__, {x: 2}); + `), + true, + 'Can set an ordinary globalThis.__proto__' +); diff --git a/test/built-ins/ShadowRealm/prototype/evaluate/throws-typeerror-wrap-throwing.js b/test/built-ins/ShadowRealm/prototype/evaluate/throws-typeerror-wrap-throwing.js index 4f1dacf0eb4..b3cec5b115e 100644 --- a/test/built-ins/ShadowRealm/prototype/evaluate/throws-typeerror-wrap-throwing.js +++ b/test/built-ins/ShadowRealm/prototype/evaluate/throws-typeerror-wrap-throwing.js @@ -3,7 +3,7 @@ /*--- esid: sec-wrappedfunctioncreate description: > - WrappedFunctionCreate throws a TypeError if the accessing target's property may throw. + WrappedFunctionCreate throws a TypeError if the accessing target's property may throw. info: | WrappedFunctionCreate ( callerRealm: a Realm Record, Target: a function object, ) diff --git a/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js b/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js index 06d9453fa10..55fd38f54b0 100644 --- a/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js +++ b/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js @@ -1,15 +1,21 @@ // Copyright 2012 Norbert Lindenberg. All rights reserved. // Copyright 2012 Mozilla Corporation. All rights reserved. // Copyright 2013 Microsoft Corporation. All rights reserved. +// Copyright (C) 2022 Richard Gibson. All rights reserved. // This code is governed by the license found in the LICENSE file. /*--- -es5id: 15.5.4.9_CE description: > - Tests that String.prototype.localeCompare returns 0 when - comparing Strings that are considered canonically equivalent by - the Unicode standard. -author: Norbert Lindenberg + String.prototype.localeCompare must return 0 when + comparing Strings that are considered canonically equivalent by + the Unicode Standard. +esid: sec-string.prototype.localecompare +info: | + String.prototype.localeCompare ( _that_ [ , _reserved1_ [ , _reserved2_ ] ] ) + + This function must treat Strings that are canonically equivalent + according to the Unicode standard as identical and must return `0` + when comparing Strings that are considered canonically equivalent. ---*/ // pairs with characters not in Unicode 3.0 are commented out @@ -49,26 +55,12 @@ var pairs = [ // ["\uD87E\uDC2B", "北"] ]; -// Detect whether we are using locale-sensitive comparisons or a bitwise comparison -if ("a".localeCompare("Z") < 0) { - // We are using locale-sensitive comparison, so all pairs should be canonically equivalent - var i; - for (i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - if (pair[0].localeCompare(pair[1]) !== 0) { - throw new Test262Error("String.prototype.localeCompare considers " + pair[0] + " (" + toU(pair[0]) + - ") ≠ " + pair[1] + " (" + toU(pair[1]) + ")."); - } - } -} else { - // We are using bitwise comparison, so all pairs should not be equivalent - var i; - for (i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - if (pair[0].localeCompare(pair[1]) === 0) { - throw new Test262Error("String.prototype.localeCompare considers " + pair[0] + " (" + toU(pair[0]) + - ") = " + pair[1] + " (" + toU(pair[1]) + ")."); - } +var i; +for (i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + if (pair[0].localeCompare(pair[1]) !== 0) { + throw new Test262Error("String.prototype.localeCompare considers " + pair[0] + " (" + toU(pair[0]) + + ") ≠ " + pair[1] + " (" + toU(pair[1]) + ")."); } } diff --git a/test/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js new file mode 100644 index 00000000000..834d82a7ebb --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateadd +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.dateAdd(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..b76329860a7 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateadd +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.dateAdd({ year: 2000, month: 5, day: 2, calendar }, new Temporal.Duration(1)); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js b/test/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js new file mode 100644 index 00000000000..8f135256c93 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateadd +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Calendar("iso8601"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.dateAdd(new Temporal.PlainDate(1976, 11, 18), new Temporal.Duration(1), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js b/test/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js index 3197c54007c..df173c933f7 100644 --- a/test/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js +++ b/test/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js @@ -17,6 +17,11 @@ features: [Temporal, arrow-function] const calendar = new Temporal.Calendar("iso8601"); const date = new Temporal.PlainDate(2000, 5, 2, calendar); const duration = new Temporal.Duration(3, 3, 0, 3); -assert.throws(RangeError, - () => calendar.dateAdd(date, duration, { overflow: "other string" }), - "Value for overflow not one of the allowed string values"); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => calendar.dateAdd(date, duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js b/test/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js new file mode 100644 index 00000000000..011851c7550 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.datefromfields +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Calendar("iso8601"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.dateFromFields({ year: 1976, month: 11, day: 18 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js b/test/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js index 6cc0d01724d..28e81de7ceb 100644 --- a/test/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js +++ b/test/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js @@ -17,6 +17,12 @@ features: [Temporal, arrow-function] ---*/ const calendar = new Temporal.Calendar("iso8601"); -assert.throws(RangeError, () => calendar.dateFromFields({ year: 2000, month: 5, day: 2 }, - { overflow: "other string" }), - "Value for overflow not one of the allowed string values"); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => calendar.dateFromFields({ year: 2000, month: 5, day: 2 }, + { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js new file mode 100644 index 00000000000..a3ecc5814d1 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js @@ -0,0 +1,67 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateuntil +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a %%%conversion_target%%% +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +const other = new Temporal.PlainDate(2020, 1, 1, instance); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.dateUntil(arg, other), + `"${arg}" should not be a valid ISO string for a PlainDate (first argument)` + ); + assert.throws( + RangeError, + () => instance.dateUntil(other, arg), + `"${arg}" should not be a valid ISO string for a PlainDate (second argument)` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..419334f252e --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateuntil +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.dateUntil({ year: 2000, month: 5, day: 2, calendar }, { year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); diff --git a/test/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js b/test/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js new file mode 100644 index 00000000000..1191edf29fe --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dateuntil +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Calendar("iso8601"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.dateUntil(new Temporal.PlainDate(1976, 11, 18), new Temporal.PlainDate(1984, 5, 31), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js new file mode 100644 index 00000000000..95a33903b79 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.day +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.day(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..80cd4dae2e1 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.day +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.day({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js new file mode 100644 index 00000000000..77d600bffde --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dayofweek +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.dayOfWeek(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..e67d34fdcc0 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dayofweek +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.dayOfWeek({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js new file mode 100644 index 00000000000..8768faa6381 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dayofyear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.dayOfYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..2ebc1c96f30 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.dayofyear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.dayOfYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js new file mode 100644 index 00000000000..97ecac0fa8f --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinmonth +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.daysInMonth(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..86e25eb109a --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinmonth +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.daysInMonth({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js new file mode 100644 index 00000000000..9c98bd32957 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinweek +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.daysInWeek(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..68e86ffc1e5 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinweek +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.daysInWeek({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js new file mode 100644 index 00000000000..8d92ef970d0 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinyear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.daysInYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..20b64607d61 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.daysinyear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.daysInYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js new file mode 100644 index 00000000000..6a1c1d5d6b7 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.inleapyear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.inLeapYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js new file mode 100644 index 00000000000..1c4272fbd72 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js @@ -0,0 +1,26 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.inleapyear +description: An ISO 8601 date string should be converted as input +info: | + 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then + a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike). + 5. Return ! IsISOLeapYear(temporalDateLike.[[ISOYear]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +assert.sameValue(cal.inLeapYear("2019-03-18"), false); +assert.sameValue(cal.inLeapYear("2020-03-18"), true); + +assert.sameValue(cal.inLeapYear("+002023-03-18"), false); +assert.sameValue(cal.inLeapYear("+002024-03-18"), true); + +assert.sameValue(cal.inLeapYear("2019-03-18T13:00:00+00:00[UTC]"), false); +assert.sameValue(cal.inLeapYear("2020-12-31T23:59:59+00:00[UTC]"), true); + +assert.sameValue(cal.inLeapYear("+002023-03-18T13:00:00+00:00[UTC]"), false); +assert.sameValue(cal.inLeapYear("+002024-03-18T13:00:00+00:00[UTC]"), true); diff --git a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js index 4359c4c8d44..7e8d3cf048b 100644 --- a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js +++ b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js @@ -8,10 +8,19 @@ features: [Temporal] ---*/ const iso = Temporal.Calendar.from("iso8601"); -const res = false; -assert.sameValue(iso.inLeapYear(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate"); -assert.sameValue(iso.inLeapYear(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime"); -assert.sameValue(iso.inLeapYear(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth"); +let res = false; + +assert.sameValue(iso.inLeapYear(new Temporal.PlainDate(1994, 11, 5)), res, "PlainDate"); +assert.sameValue(iso.inLeapYear(new Temporal.PlainDateTime(1994, 11, 5, 8, 15, 30)), res, "PlainDateTime"); +assert.sameValue(iso.inLeapYear(new Temporal.PlainYearMonth(1994, 11)), res, "PlainYearMonth"); assert.sameValue(iso.inLeapYear({ year: 1994, month: 11, day: 5 }), res, "property bag"); assert.sameValue(iso.inLeapYear("1994-11-05"), res, "string"); + +res = true; +assert.sameValue(iso.inLeapYear(new Temporal.PlainDate(1996, 7, 15)), res, "PlainDate in leap year"); +assert.sameValue(iso.inLeapYear(new Temporal.PlainDateTime(1996, 7, 15, 5, 30, 13)), res, "PlainDateTime in leap year"); +assert.sameValue(iso.inLeapYear(new Temporal.PlainYearMonth(1996, 7)), res, "PlainYearMonth in leap year"); +assert.sameValue(iso.inLeapYear({ year: 1996, month: 7, day: 15 }), res, "property bag in leap year"); +assert.sameValue(iso.inLeapYear("1996-07-15"), res, "string in leap year"); + assert.throws(TypeError, () => iso.inLeapYear({ year: 2000 }), "property bag with missing properties"); diff --git a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js index 8b3e5de8a2f..003cf490ab0 100644 --- a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js +++ b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js @@ -11,12 +11,14 @@ const inLeapYear = Temporal.Calendar.prototype.inLeapYear; assert.sameValue(typeof inLeapYear, "function"); -assert.throws(TypeError, () => inLeapYear.call(undefined), "undefined"); -assert.throws(TypeError, () => inLeapYear.call(null), "null"); -assert.throws(TypeError, () => inLeapYear.call(true), "true"); -assert.throws(TypeError, () => inLeapYear.call(""), "empty string"); -assert.throws(TypeError, () => inLeapYear.call(Symbol()), "symbol"); -assert.throws(TypeError, () => inLeapYear.call(1), "1"); -assert.throws(TypeError, () => inLeapYear.call({}), "plain object"); -assert.throws(TypeError, () => inLeapYear.call(Temporal.Calendar), "Temporal.Calendar"); -assert.throws(TypeError, () => inLeapYear.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype"); +const arg = new Temporal.PlainDate(2021, 3, 4); + +assert.throws(TypeError, () => inLeapYear.call(undefined, arg), "undefined"); +assert.throws(TypeError, () => inLeapYear.call(null, arg), "null"); +assert.throws(TypeError, () => inLeapYear.call(true, arg), "true"); +assert.throws(TypeError, () => inLeapYear.call("", arg), "empty string"); +assert.throws(TypeError, () => inLeapYear.call(Symbol(), arg), "symbol"); +assert.throws(TypeError, () => inLeapYear.call(1, arg), "1"); +assert.throws(TypeError, () => inLeapYear.call({}, arg), "plain object"); +assert.throws(TypeError, () => inLeapYear.call(Temporal.Calendar, arg), "Temporal.Calendar"); +assert.throws(TypeError, () => inLeapYear.call(Temporal.Calendar.prototype, arg), "Temporal.Calendar.prototype"); diff --git a/test/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..2b89a6b531a --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.inleapyear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.inLeapYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js b/test/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js new file mode 100644 index 00000000000..72483362e8b --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js @@ -0,0 +1,33 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.mergefields +description: > + Temporal.Calendar.prototype.mergeFields will merge own data properties on its + arguments +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. Set fields to ? ToObject(fields). + 5. Set additionalFields to ? ToObject(additionalFields). + 6. Return ? DefaultMergeFields(fields, additionalFields). +features: [Temporal] +includes: [deepEqual.js] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2 }, { c: 3, d: 4 }), + { a: 1, b: 2, c: 3, d: 4 }, + "properties are merged" +); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4 }), + { a: 1, b: 3, c: 4 }, + "property in additionalFields should overwrite one in fields" +); diff --git a/test/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js b/test/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js new file mode 100644 index 00000000000..e322a791e13 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js @@ -0,0 +1,99 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.mergefields +description: > + The default mergeFields algorithm from the ISO 8601 calendar should correctly + merge the month and monthCode properties +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. Set fields to ? ToObject(fields). + 5. Set additionalFields to ? ToObject(additionalFields). + 6. Return ? DefaultMergeFields(fields, additionalFields). +features: [Temporal] +includes: [deepEqual.js] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4 }), + { a: 1, b: 3, c: 4, month: 7 }, + "month is copied from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, monthCode: "M08" }, { b: 3, c: 4 }), + { a: 1, b: 3, c: 4, monthCode: "M08" }, + "monthCode is copied from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4 }), + { a: 1, b: 3, c: 4, month: 7, monthCode: "M08" }, + "both month and monthCode are copied from fields, no validation is performed" +); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, month: 5 }), + { a: 1, b: 3, c: 4, month: 5 }, + "month is copied from additionalFields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, monthCode: "M06" }), + { a: 1, b: 3, c: 4, monthCode: "M06" }, + "monthCode is copied from additionalFields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, month: 5, monthCode: "M06" }), + { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" }, + "both month and monthCode are copied from additionalFields, no validation is performed" +); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, month: 5 }), + { a: 1, b: 3, c: 4, month: 5 }, + "month from additionalFields overrides month from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, monthCode: "M05" }), + { a: 1, b: 3, c: 4, monthCode: "M05" }, + "monthCode from additionalFields overrides monthCode from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, month: 6 }), + { a: 1, b: 3, c: 4, month: 6 }, + "month's presence on additionalFields blocks monthCode from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, monthCode: "M06" }), + { a: 1, b: 3, c: 4, monthCode: "M06"}, + "monthCode's presence on additionalFields blocks month from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" },{ b: 3, c: 4, month: 5 }), + { a: 1, b: 3, c: 4, month: 5 }, + "month's presence on additionalFields blocks both month and monthCode from fields" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4, monthCode: "M06" }), + { a: 1, b: 3, c: 4, monthCode: "M06" }, + "monthCode's presence on additionalFields blocks both month and monthCode from fields" +); + +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, month: 5, monthCode: "M06" }), + { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" }, + "both month and monthCode are copied from additionalFields even when fields has month" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, month: 5, monthCode: "M06" }), + { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" }, + "both month and monthCode are copied from additionalFields even when fields has monthCode" +); +assert.deepEqual( + cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4, month: 5, monthCode: "M06" }), + { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" }, + "both month and monthCode are copied from additionalFields even when fields has both month and monthCode" +); diff --git a/test/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js b/test/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js new file mode 100644 index 00000000000..2908be90ba8 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js @@ -0,0 +1,34 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.mergefields +description: Only string keys from the arguments are merged +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. Set fields to ? ToObject(fields). + 5. Set additionalFields to ? ToObject(additionalFields). + 6. Return ? DefaultMergeFields(fields, additionalFields). +features: [Temporal] +includes: [deepEqual.js] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +assert.deepEqual( + cal.mergeFields({ 1: 2 }, { 3: 4 }), + { "1": 2, "3": 4 }, + "number keys are actually string keys and are merged as such" +); +assert.deepEqual( + cal.mergeFields({ 1n: 2 }, { 2n: 4 }), + { "1": 2, "2": 4 }, + "bigint keys are actually string keys and are merged as such" +); + +const foo = Symbol("foo"); +const bar = Symbol("bar"); +assert.deepEqual(cal.mergeFields({ [foo]: 1 }, { [bar]: 2 }), {}, "symbol keys are not merged"); diff --git a/test/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js new file mode 100644 index 00000000000..e314a1d01e3 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.month +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.month(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..77c6e75f829 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.month +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.month({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js new file mode 100644 index 00000000000..3994dee3bc9 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthcode +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.monthCode(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..18111f2f165 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthcode +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.monthCode({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js new file mode 100644 index 00000000000..e79389fe36e --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js @@ -0,0 +1,40 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Temporal.Calendar.prototype.monthDayFromFields will return correctly with valid data. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOMonthDayFromFields(fields, options). + 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +let result = cal.monthDayFromFields({ year: 2021, month: 7, day: 3 }); +TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "month 7, day 3, with year"); +result = cal.monthDayFromFields({ year: 2021, month: 12, day: 31 }); +TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "month 12, day 31, with year"); +result = cal.monthDayFromFields({ monthCode: "M07", day: 3 }); +TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "monthCode M07, day 3"); +result = cal.monthDayFromFields({ monthCode: "M12", day: 31 }); +TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "monthCode M12, day 31"); + +["constrain", "reject"].forEach(function (overflow) { + const opt = { overflow }; + result = cal.monthDayFromFields({ year: 2021, month: 7, day: 3 }, opt); + TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "month 7, day 3, with year"); + result = cal.monthDayFromFields({ year: 2021, month: 12, day: 31 }, opt); + TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "month 12, day 31, with year"); + result = cal.monthDayFromFields({ monthCode: "M07", day: 3 }, opt); + TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "monthCode M07, day 3"); + result = cal.monthDayFromFields({ monthCode: "M12", day: 31 }, opt); + TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "monthCode M12, day 31"); +}); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js new file mode 100644 index 00000000000..d642ab4302e --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js @@ -0,0 +1,24 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Temporal.Calendar.prototype.monthDayFromFields will throw TypeError with incorrect input data type. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOMonthDayFromFields(fields, options). + 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]). +features: [Temporal] +---*/ + +let cal = new Temporal.Calendar("iso8601") + +assert.throws(TypeError, () => cal.monthDayFromFields({}), "at least one correctly spelled property is required"); +assert.throws(TypeError, () => cal.monthDayFromFields({ monthCode: "M12" }), "day is required with monthCode"); +assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, month: 12 }), "day is required with year and month"); +assert.throws(TypeError, () => cal.monthDayFromFields({ month: 1, day: 17 }), "year is required if month is present"); +assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, day: 17 }), "either month or monthCode is required"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js index f8400f71854..88c229f074c 100644 --- a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js @@ -7,7 +7,7 @@ description: Throw a TypeError if the fields is not an object features: [Symbol, Temporal] ---*/ -const tests = [undefined, null, false, "string", Symbol("sym"), Math.PI, 42n]; +const tests = [undefined, null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n]; const iso = Temporal.Calendar.from("iso8601"); for (const fields of tests) { assert.throws(TypeError, () => iso.monthDayFromFields(fields, {})); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js new file mode 100644 index 00000000000..29e5c4f0984 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js @@ -0,0 +1,31 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Throw RangeError for an out-of-range, conflicting, or ill-formed monthCode +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOMonthDayFromFields(fields, options). + 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +["m1", "M1", "m01"].forEach((monthCode) => { + assert.throws(RangeError, () => cal.monthDayFromFields({ monthCode, day: 17 }), + `monthCode '${monthCode}' is not well-formed`); +}); + +assert.throws(RangeError, () => cal.monthDayFromFields({ year: 2021, month: 12, monthCode: "M11", day: 17 }), + "monthCode and month conflict"); + +["M00", "M19", "M99", "M13"].forEach((monthCode) => { + assert.throws(RangeError, () => cal.monthDayFromFields({ monthCode, day: 17 }), + `monthCode '${monthCode}' is not valid for ISO 8601 calendar`); +}); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js new file mode 100644 index 00000000000..f19f381f5d0 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Calendar("iso8601"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.monthDayFromFields({ monthCode: "M12", day: 15 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js new file mode 100644 index 00000000000..0ad71fe6d07 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js @@ -0,0 +1,91 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Temporal.Calendar.prototype.monthDayFromFields will return correctly with data and overflow set to 'constrain'. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOMonthDayFromFields(fields, options). + 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); +const opt = { overflow: "constrain" }; + +let result = cal.monthDayFromFields({ year: 2021, month: 1, day: 133 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M01", 31, "day is constrained to 31 in month 1"); +result = cal.monthDayFromFields({ year: 2021, month: 2, day: 133 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M02", 28, "day is constrained to 28 in month 2 (year 2021)"); +result = cal.monthDayFromFields({ year: 2021, month: 3, day: 9033 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M03", 31, "day is constrained to 31 in month 3"); +result = cal.monthDayFromFields({ year: 2021, month: 4, day: 50 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M04", 30, "day is constrained to 30 in month 4"); +result = cal.monthDayFromFields({ year: 2021, month: 5, day: 77 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M05", 31, "day is constrained to 31 in month 5"); +result = cal.monthDayFromFields({ year: 2021, month: 6, day: 33 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M06", 30, "day is constrained to 30 in month 6"); +result = cal.monthDayFromFields({ year: 2021, month: 7, day: 33 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M07", 31, "day is constrained to 31 in month 7"); +result = cal.monthDayFromFields({ year: 2021, month: 8, day: 300 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M08", 31, "day is constrained to 31 in month 8"); +result = cal.monthDayFromFields({ year: 2021, month: 9, day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M09", 30, "day is constrained to 30 in month 9"); +result = cal.monthDayFromFields({ year: 2021, month: 10, day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M10", 31, "day is constrained to 31 in month 10"); +result = cal.monthDayFromFields({ year: 2021, month: 11, day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M11", 30, "day is constrained to 30 in month 11"); +result = cal.monthDayFromFields({ year: 2021, month: 12, day: 500 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "day is constrained to 31 in month 12"); + +assert.throws( + RangeError, + () => cal.monthDayFromFields({ year: 2021, month: -99999, day: 1 }, opt), + "negative month -99999 is out of range even with overflow constrain" +) +assert.throws( + RangeError, + () => cal.monthDayFromFields({ year: 2021, month: -1, day: 1 }, opt), + "negative month -1 is out of range even with overflow constrain" +) +assert.throws( + RangeError, + () => cal.monthDayFromFields({ year: 2021, month: 0, day: 1 }, opt), + "month zero is out of range even with overflow constrain" +) + +result = cal.monthDayFromFields({ year: 2021, month: 13, day: 1 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M12", 1, "month 13 is constrained to 12"); +result = cal.monthDayFromFields({ year: 2021, month: 999999, day: 500 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "month 999999 is constrained to 12 and day constrained to 31"); + +result = cal.monthDayFromFields({ monthCode: "M01", day: 133 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M01", 31, "day is constrained to 31 in monthCode M01"); +result = cal.monthDayFromFields({ monthCode: "M02", day: 133 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M02", 29, "day is constrained to 29 in monthCode M02"); +result = cal.monthDayFromFields({ monthCode: "M03", day: 9033 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M03", 31, "day is constrained to 31 in monthCode M03"); +result = cal.monthDayFromFields({ monthCode: "M04", day: 50 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M04", 30, "day is constrained to 30 in monthCode M04"); +result = cal.monthDayFromFields({ monthCode: "M05", day: 77 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M05", 31, "day is constrained to 31 in monthCode M05"); +result = cal.monthDayFromFields({ monthCode: "M06", day: 33 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M06", 30, "day is constrained to 30 in monthCode M06"); +result = cal.monthDayFromFields({ monthCode: "M07", day: 33 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M07", 31, "day is constrained to 31 in monthCode M07"); +result = cal.monthDayFromFields({ monthCode: "M08", day: 300 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M08", 31, "day is constrained to 31 in monthCode M08"); +result = cal.monthDayFromFields({ monthCode: "M09", day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M09", 30, "day is constrained to 30 in monthCode M09"); +result = cal.monthDayFromFields({ monthCode: "M10", day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M10", 31, "day is constrained to 31 in monthCode M10"); +result = cal.monthDayFromFields({ monthCode: "M11", day: 400 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M11", 30, "day is constrained to 30 in monthCode M11"); +result = cal.monthDayFromFields({ monthCode: "M12", day: 500 }, opt); +TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "day is constrained to 31 in monthCode M12"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js index 2e87dc1a67a..6844c7e3d2b 100644 --- a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js @@ -17,4 +17,11 @@ features: [Temporal] ---*/ const calendar = new Temporal.Calendar("iso8601"); -assert.throws(RangeError, () => calendar.monthDayFromFields({ year: 2000, month: 5, day: 2 }, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => calendar.monthDayFromFields({ year: 2000, month: 5, day: 2 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js new file mode 100644 index 00000000000..5db608b3359 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js @@ -0,0 +1,64 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Throw RangeError for input data out of range with overflow reject +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOMonthDayFromFields(fields, options). + 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +[-1, 0, 13, 9995].forEach((month) => { + assert.throws( + RangeError, + () => cal.monthDayFromFields({year: 2021, month, day: 5}, { overflow: "reject" }), + `Month ${month} is out of range for 2021 with overflow: reject` + ); +}); + +[-1, 0, 32, 999].forEach((day) => { + assert.throws( + RangeError, + () => cal.monthDayFromFields({ year: 2021, month: 12, day }, { overflow: "reject" }), + `Day ${day} is out of range for 2021-12 with overflow: reject` + ); + assert.throws( + RangeError, + () => cal.monthDayFromFields({ monthCode: "M12", day }, { overflow: "reject" }), + `Day ${day} is out of range for 2021-M12 with overflow: reject` + ); +}); + +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M01", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M01"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M02", day: 30 }, { overflow: "reject" }), "Day 30 is out of range for monthCode M02"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M03", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M03"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M04", day: 31 }, { overflow: "reject" }), "Day 31 is out of range for monthCode M04"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M05", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M05"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M06", day: 31 }, { overflow: "reject" }), "Day 31 is out of range for monthCode M06"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M07", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M07"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M08", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M08"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M09", day: 31 }, { overflow: "reject" }), "Day 31 is out of range for monthCode M09"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M10", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M10"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M11", day: 31 }, { overflow: "reject" }), "Day 31 is out of range for monthCode M11"); +assert.throws(RangeError, () => cal.monthDayFromFields( + { monthCode: "M12", day: 32 }, { overflow: "reject" }), "Day 32 is out of range for monthCode M12"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js new file mode 100644 index 00000000000..e0b942007d6 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js @@ -0,0 +1,23 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthdayfromfields +description: Use a leap year as the reference year if monthCode is given +info: | + sec-temporal-isomonthdayfromfields: + 12. If _monthCode_ is *undefined*, then + a. Let _result_ be ? RegulateISODate(_year_, _month_, _day_, _overflow_). + 13. Else, + a. Let _result_ be ? RegulateISODate(_referenceISOYear_, _month_, _day_, _overflow_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +let result = cal.monthDayFromFields({ year: 2021, monthCode: "M02", day: 29 }); +TemporalHelpers.assertPlainMonthDay(result, "M02", 29, "year is ignored and reference year should be a leap year if monthCode is given"); + +result = cal.monthDayFromFields({ year: 2021, month: 2, day: 29 }, { overflow: "constrain" }); +TemporalHelpers.assertPlainMonthDay(result, "M02", 28, "year should not be ignored if monthCode is not given"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js new file mode 100644 index 00000000000..811a6e00cb3 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthsinyear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.monthsInYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js new file mode 100644 index 00000000000..9a8748d8771 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js @@ -0,0 +1,18 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthsinyear +description: An ISO 8601 date string should be converted as input +info: | + a. Perform ? ToTemporalDate(temporalDateLike). + 5. Return 12𝔽. +features: [Temporal] +---*/ + +let cal = new Temporal.Calendar("iso8601"); + +assert.sameValue(cal.monthsInYear("3456-12-20"), 12); +assert.sameValue(cal.monthsInYear("+000998-01-28"), 12); +assert.sameValue(cal.monthsInYear("3456-12-20T03:04:05+00:00[UTC]"), 12); +assert.sameValue(cal.monthsInYear("+000998-01-28T03:04:05+00:00[UTC]"), 12); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js index fcf4e35084a..9edcee17457 100644 --- a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js +++ b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js @@ -9,9 +9,9 @@ features: [Temporal] const iso = Temporal.Calendar.from("iso8601"); const res = 12; -assert.sameValue(iso.monthsInYear(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate"); -assert.sameValue(iso.monthsInYear(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime"); -assert.sameValue(iso.monthsInYear(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth"); +assert.sameValue(iso.monthsInYear(new Temporal.PlainDate(1994, 11, 5)), res, "PlainDate"); +assert.sameValue(iso.monthsInYear(new Temporal.PlainDateTime(1994, 11, 5, 8, 15, 30)), res, "PlainDateTime"); +assert.sameValue(iso.monthsInYear(new Temporal.PlainYearMonth(1994, 11)), res, "PlainYearMonth"); assert.sameValue(iso.monthsInYear({ year: 1994, month: 11, day: 5 }), res, "property bag"); assert.sameValue(iso.monthsInYear("1994-11-05"), res, "string"); assert.throws(TypeError, () => iso.monthsInYear({ year: 2000 }), "property bag with missing properties"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js index e86c5f50e22..4d16a000786 100644 --- a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js +++ b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js @@ -11,12 +11,14 @@ const monthsInYear = Temporal.Calendar.prototype.monthsInYear; assert.sameValue(typeof monthsInYear, "function"); -assert.throws(TypeError, () => monthsInYear.call(undefined), "undefined"); -assert.throws(TypeError, () => monthsInYear.call(null), "null"); -assert.throws(TypeError, () => monthsInYear.call(true), "true"); -assert.throws(TypeError, () => monthsInYear.call(""), "empty string"); -assert.throws(TypeError, () => monthsInYear.call(Symbol()), "symbol"); -assert.throws(TypeError, () => monthsInYear.call(1), "1"); -assert.throws(TypeError, () => monthsInYear.call({}), "plain object"); -assert.throws(TypeError, () => monthsInYear.call(Temporal.Calendar), "Temporal.Calendar"); -assert.throws(TypeError, () => monthsInYear.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype"); +const arg = new Temporal.PlainDate(2021, 3, 4); + +assert.throws(TypeError, () => monthsInYear.call(undefined, arg), "undefined"); +assert.throws(TypeError, () => monthsInYear.call(null, arg), "null"); +assert.throws(TypeError, () => monthsInYear.call(true, arg), "true"); +assert.throws(TypeError, () => monthsInYear.call("", arg), "empty string"); +assert.throws(TypeError, () => monthsInYear.call(Symbol(), arg), "symbol"); +assert.throws(TypeError, () => monthsInYear.call(1, arg), "1"); +assert.throws(TypeError, () => monthsInYear.call({}, arg), "plain object"); +assert.throws(TypeError, () => monthsInYear.call(Temporal.Calendar, arg), "Temporal.Calendar"); +assert.throws(TypeError, () => monthsInYear.call(Temporal.Calendar.prototype, arg), "Temporal.Calendar.prototype"); diff --git a/test/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..838aff96f6f --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.monthsinyear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.monthsInYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js new file mode 100644 index 00000000000..5f9f4da0d49 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js @@ -0,0 +1,76 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.weekofyear +description: > + Temporal.Calendar.prototype.weekOfYear will take Temporal.PlainDate object + and return the week of year of that date. +info: | + 4. Let temporalDate be ? ToTemporalDate(temporalDateLike). + 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +// The following week numbers are taken from the table "Examples of contemporary +// dates around New Year's Day" from +// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar + +let d = new Temporal.PlainDate(1977, 1, 1); +assert.sameValue(cal.weekOfYear(d), 53, "1977-01-01 is in w53"); + +d = new Temporal.PlainDate(1977, 1, 2); +assert.sameValue(cal.weekOfYear(d), 53, "1977-01-02 is in w53"); + +d = new Temporal.PlainDate(1977, 12, 31); +assert.sameValue(cal.weekOfYear(d), 52, "1977-12-31 is in w52"); + +d = new Temporal.PlainDate(1978, 1, 1); +assert.sameValue(cal.weekOfYear(d), 52, "1978-01-01 is in w52"); + +d = new Temporal.PlainDate(1978, 1, 2); +assert.sameValue(cal.weekOfYear(d), 1, "1978-01-02 is in w01"); + +d = new Temporal.PlainDate(1978, 12, 31); +assert.sameValue(cal.weekOfYear(d), 52, "1978-12-31 is in w52"); + +d = new Temporal.PlainDate(1979, 1, 1); +assert.sameValue(cal.weekOfYear(d), 1, "1979-01-01 is in w01"); + +d = new Temporal.PlainDate(1979, 12, 30); +assert.sameValue(cal.weekOfYear(d), 52, "1979-12-30 is in w52"); + +d = new Temporal.PlainDate(1979, 12, 31); +assert.sameValue(cal.weekOfYear(d), 1, "1979-12-31 is in w01"); + +d = new Temporal.PlainDate(1980, 1, 1); +assert.sameValue(cal.weekOfYear(d), 1, "1980-01-01 is in w01"); + +d = new Temporal.PlainDate(1980, 12, 28); +assert.sameValue(cal.weekOfYear(d), 52, "1980-12-28 is in w52"); + +d = new Temporal.PlainDate(1980, 12, 29); +assert.sameValue(cal.weekOfYear(d), 1, "1980-12-29 is in w01"); + +d = new Temporal.PlainDate(1980, 12, 30); +assert.sameValue(cal.weekOfYear(d), 1, "1980-12-30 is in w01"); + +d = new Temporal.PlainDate(1980, 12, 31); +assert.sameValue(cal.weekOfYear(d), 1, "1980-12-31 is in w01"); + +d = new Temporal.PlainDate(1981, 1, 1); +assert.sameValue(cal.weekOfYear(d), 1, "1981-01-01 is in w01"); + +d = new Temporal.PlainDate(1981, 12, 31); +assert.sameValue(cal.weekOfYear(d), 53, "1981-12-31 is in w53"); + +d = new Temporal.PlainDate(1982, 1, 1); +assert.sameValue(cal.weekOfYear(d), 53, "1982-01-01 is in w53"); + +d = new Temporal.PlainDate(1982, 1, 2); +assert.sameValue(cal.weekOfYear(d), 53, "1982-01-02 is in w53"); + +d = new Temporal.PlainDate(1982, 1, 3); +assert.sameValue(cal.weekOfYear(d), 53, "1982-01-03 is in w53"); diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js new file mode 100644 index 00000000000..e7546bb7119 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js @@ -0,0 +1,76 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.weekofyear +description: > + Temporal.Calendar.prototype.weekOfYear will take Temporal.PlainDateTime object + and return the week of year of that date. +info: | + 4. Let temporalDate be ? ToTemporalDate(temporalDateLike). + 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +// The following week numbers are taken from the table "Examples of contemporary +// dates around New Year's Day" from +// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar + +let dt = new Temporal.PlainDateTime(1977, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1977-01-01 is in w53"); + +dt = new Temporal.PlainDateTime(1977, 1, 2, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1977-01-02 is in w53"); + +dt = new Temporal.PlainDateTime(1977, 12, 31, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 52, "1977-12-31 is in w52"); + +dt = new Temporal.PlainDateTime(1978, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 52, "1978-01-01 is in w52"); + +dt = new Temporal.PlainDateTime(1978, 1, 2, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1978-01-02 is in w01"); + +dt = new Temporal.PlainDateTime(1978, 12, 31, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 52, "1978-12-31 is in w52"); + +dt = new Temporal.PlainDateTime(1979, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1979-01-01 is in w01"); + +dt = new Temporal.PlainDateTime(1979, 12, 30, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 52, "1979-12-30 is in w52"); + +dt = new Temporal.PlainDateTime(1979, 12, 31, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1979-12-31 is in w01"); + +dt = new Temporal.PlainDateTime(1980, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1980-01-01 is in w01"); + +dt = new Temporal.PlainDateTime(1980, 12, 28, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 52, "1980-12-28 is in w52"); + +dt = new Temporal.PlainDateTime(1980, 12, 29, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-29 is in w01"); + +dt = new Temporal.PlainDateTime(1980, 12, 30, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-30 is in w01"); + +dt = new Temporal.PlainDateTime(1980, 12, 31, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-31 is in w01"); + +dt = new Temporal.PlainDateTime(1981, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 1, "1981-01-01 is in w01"); + +dt = new Temporal.PlainDateTime(1981, 12, 31, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1981-12-31 is in w53"); + +dt = new Temporal.PlainDateTime(1982, 1, 1, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-01 is in w53"); + +dt = new Temporal.PlainDateTime(1982, 1, 2, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-02 is in w53"); + +dt = new Temporal.PlainDateTime(1982, 1, 3, 9, 8); +assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-03 is in w53"); diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js new file mode 100644 index 00000000000..7b8e721b7e3 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.weekofyear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.weekOfYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js new file mode 100644 index 00000000000..f031d046900 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js @@ -0,0 +1,39 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.weekofyear +description: > + Temporal.Calendar.prototype.weekOfYear will take an ISO 8601 date string and + return the week of year of that date. +info: | + 4. Let temporalDate be ? ToTemporalDate(temporalDateLike). + 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +// The following week numbers are taken from the table "Examples of contemporary +// dates around New Year's Day" from +// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar + +assert.sameValue(cal.weekOfYear("1977-01-01"), 53, "1977-01-01 is in w53"); +assert.sameValue(cal.weekOfYear("1977-01-02"), 53, "1977-01-02 is in w53"); +assert.sameValue(cal.weekOfYear("1977-12-31"), 52, "1977-12-31 is in w52"); +assert.sameValue(cal.weekOfYear("1978-01-01"), 52, "1978-01-01 is in w52"); +assert.sameValue(cal.weekOfYear("1978-01-02"), 1, "1978-01-02 is in w01"); +assert.sameValue(cal.weekOfYear("1978-12-31"), 52, "1978-12-31 is in w52"); +assert.sameValue(cal.weekOfYear("1979-01-01"), 1, "1979-01-01 is in w01"); +assert.sameValue(cal.weekOfYear("1979-12-30"), 52, "1979-12-30 is in w52"); +assert.sameValue(cal.weekOfYear("1979-12-31"), 1, "1979-12-31 is in w01"); +assert.sameValue(cal.weekOfYear("1980-01-01"), 1, "1980-01-01 is in w01"); +assert.sameValue(cal.weekOfYear("1980-12-28"), 52, "1980-12-28 is in w52"); +assert.sameValue(cal.weekOfYear("1980-12-29"), 1, "1980-12-29 is in w01"); +assert.sameValue(cal.weekOfYear("1980-12-30"), 1, "1980-12-30 is in w01"); +assert.sameValue(cal.weekOfYear("1980-12-31"), 1, "1980-12-31 is in w01"); +assert.sameValue(cal.weekOfYear("1981-01-01"), 1, "1981-01-01 is in w01"); +assert.sameValue(cal.weekOfYear("1981-12-31"), 53, "1981-12-31 is in w53"); +assert.sameValue(cal.weekOfYear("1982-01-01"), 53, "1982-01-01 is in w53"); +assert.sameValue(cal.weekOfYear("1982-01-02"), 53, "1982-01-02 is in w53"); +assert.sameValue(cal.weekOfYear("1982-01-03"), 53, "1982-01-03 is in w53"); diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js index 82f80e27c74..d6b5a0f0cf1 100644 --- a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js @@ -11,12 +11,14 @@ const weekOfYear = Temporal.Calendar.prototype.weekOfYear; assert.sameValue(typeof weekOfYear, "function"); -assert.throws(TypeError, () => weekOfYear.call(undefined), "undefined"); -assert.throws(TypeError, () => weekOfYear.call(null), "null"); -assert.throws(TypeError, () => weekOfYear.call(true), "true"); -assert.throws(TypeError, () => weekOfYear.call(""), "empty string"); -assert.throws(TypeError, () => weekOfYear.call(Symbol()), "symbol"); -assert.throws(TypeError, () => weekOfYear.call(1), "1"); -assert.throws(TypeError, () => weekOfYear.call({}), "plain object"); -assert.throws(TypeError, () => weekOfYear.call(Temporal.Calendar), "Temporal.Calendar"); -assert.throws(TypeError, () => weekOfYear.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype"); +const arg = new Temporal.PlainDate(2021, 7, 20); + +assert.throws(TypeError, () => weekOfYear.call(undefined, arg), "undefined"); +assert.throws(TypeError, () => weekOfYear.call(null, arg), "null"); +assert.throws(TypeError, () => weekOfYear.call(true, arg), "true"); +assert.throws(TypeError, () => weekOfYear.call("", arg), "empty string"); +assert.throws(TypeError, () => weekOfYear.call(Symbol(), arg), "symbol"); +assert.throws(TypeError, () => weekOfYear.call(1, arg), "1"); +assert.throws(TypeError, () => weekOfYear.call({}, arg), "plain object"); +assert.throws(TypeError, () => weekOfYear.call(Temporal.Calendar, arg), "Temporal.Calendar"); +assert.throws(TypeError, () => weekOfYear.call(Temporal.Calendar.prototype, arg), "Temporal.Calendar.prototype"); diff --git a/test/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..c75c1d52145 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.weekofyear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.weekOfYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js b/test/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js new file mode 100644 index 00000000000..e186a2321f8 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.year +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.year(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..31549636a44 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.year +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.year({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js new file mode 100644 index 00000000000..2624bc7b651 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js @@ -0,0 +1,40 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Temporal.Calendar.prototype.yearMonthFromFields return correctly with valid data. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOYearMonthFromFields(fields, options). + 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601") + +let result = cal.yearMonthFromFields({ year: 2021, month: 7 }); +TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "year 2021, month 7"); +result = cal.yearMonthFromFields({ year: 2021, month: 12 }); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "year 2021, month 12"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" }); +TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "year 2021, monthCode M07"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" }); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "year 2021, monthCode M12"); + +["constrain", "reject"].forEach((overflow) => { + const opt = { overflow }; + result = cal.yearMonthFromFields({ year: 2021, month: 7 }, opt); + TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", `year 2021, month 7, overflow ${overflow}`); + result = cal.yearMonthFromFields({ year: 2021, month: 12 }, opt); + TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", `year 2021, month 12, overflow ${overflow}`); + result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" }, opt); + TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", `year 2021, monthCode M07, overflow ${overflow}`); + result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" }, opt); + TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", `year 2021, monthCode M12, overflow ${overflow}`); +}); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js index 0839394ca96..7212b7f1d6c 100644 --- a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js @@ -11,12 +11,14 @@ const yearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; assert.sameValue(typeof yearMonthFromFields, "function"); -assert.throws(TypeError, () => yearMonthFromFields.call(undefined), "undefined"); -assert.throws(TypeError, () => yearMonthFromFields.call(null), "null"); -assert.throws(TypeError, () => yearMonthFromFields.call(true), "true"); -assert.throws(TypeError, () => yearMonthFromFields.call(""), "empty string"); -assert.throws(TypeError, () => yearMonthFromFields.call(Symbol()), "symbol"); -assert.throws(TypeError, () => yearMonthFromFields.call(1), "1"); -assert.throws(TypeError, () => yearMonthFromFields.call({}), "plain object"); -assert.throws(TypeError, () => yearMonthFromFields.call(Temporal.Calendar), "Temporal.Calendar"); -assert.throws(TypeError, () => yearMonthFromFields.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype"); +const arg = { year: 2021, month: 1 }; + +assert.throws(TypeError, () => yearMonthFromFields.call(undefined, arg), "undefined"); +assert.throws(TypeError, () => yearMonthFromFields.call(null, arg), "null"); +assert.throws(TypeError, () => yearMonthFromFields.call(true, arg), "true"); +assert.throws(TypeError, () => yearMonthFromFields.call("", arg), "empty string"); +assert.throws(TypeError, () => yearMonthFromFields.call(Symbol(), arg), "symbol"); +assert.throws(TypeError, () => yearMonthFromFields.call(1, arg), "1"); +assert.throws(TypeError, () => yearMonthFromFields.call({}, arg), "plain object"); +assert.throws(TypeError, () => yearMonthFromFields.call(Temporal.Calendar, arg), "Temporal.Calendar"); +assert.throws(TypeError, () => yearMonthFromFields.call(Temporal.Calendar.prototype, arg), "Temporal.Calendar.prototype"); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js new file mode 100644 index 00000000000..c63d8f39e6c --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js @@ -0,0 +1,22 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Temporal.Calendar.prototype.yearMonthFromFields will throw TypeError with incorrect input data type. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOYearMonthFromFields(fields, options). + 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601") + +assert.throws(TypeError, () => cal.yearMonthFromFields({}), "at least one correctly spelled property is required"); +assert.throws(TypeError, () => cal.yearMonthFromFields({ month: 1 }), "year is required"); +assert.throws(TypeError, () => cal.yearMonthFromFields({ year: 2021 }), "month or monthCode is required"); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js index 7969ba6e441..e04972b2dde 100644 --- a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js @@ -7,7 +7,7 @@ description: Throw a TypeError if the fields is not an object features: [Symbol, Temporal] ---*/ -const tests = [undefined, null, false, "string", Symbol("sym"), Math.PI, 42n]; +const tests = [undefined, null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n]; const iso = Temporal.Calendar.from("iso8601"); for (const fields of tests) { assert.throws(TypeError, () => iso.yearMonthFromFields(fields, {})); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js new file mode 100644 index 00000000000..0b01bf85a75 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js @@ -0,0 +1,31 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Throw RangeError for an out-of-range, conflicting, or ill-formed monthCode +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOYearMonthFromFields(fields, options). + 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +["m1", "M1", "m01"].forEach((monthCode) => { + assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, monthCode }), + `monthCode '${monthCode}' is not well-formed`); +}); + +assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, month: 12, monthCode: "M11" }), + "monthCode and month conflict"); + +["M00", "M19", "M99", "M13"].forEach((monthCode) => { + assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, monthCode }), + `monthCode '${monthCode}' is not valid for year 2021`); +}); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js new file mode 100644 index 00000000000..0246e70bbcc --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js @@ -0,0 +1,17 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Throw a TypeError if options is not an object or undefined +info: | + 5. Set options to ? GetOptionsObject(options). +features: [Symbol, Temporal] +---*/ + +const tests = [null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n]; +const iso = new Temporal.Calendar("iso8601"); +for (const options of tests) { + assert.throws(TypeError, () => iso.yearMonthFromFields({ year: 2021, month: 7 }, options), + "options is not object"); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js new file mode 100644 index 00000000000..625fcec62a5 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Calendar("iso8601"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.yearMonthFromFields({ year: 2000, monthCode: "M05" }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js new file mode 100644 index 00000000000..6384d42a285 --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js @@ -0,0 +1,91 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Temporal.Calendar.prototype.yearMonthFromFields will return correctly with data and overflow set to 'constrain'. +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOYearMonthFromFields(fields, options). + 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601") +const opt = { overflow: "constrain" }; + +let result = cal.yearMonthFromFields({ year: 2021, month: 1 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 1, "M01", "month 1 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 2 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 2, "M02", "month 2 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 3 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 3, "M03", "month 3 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 4 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 4, "M04", "month 4 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 5 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 5, "M05", "month 5 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 6 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 6, "M06", "month 6 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 7 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "month 7 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 8 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 8, "M08", "month 8 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 9 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 9, "M09", "month 9 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 10 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 10, "M10", "month 10 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 11 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 11, "M11", "month 11 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, month: 12 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 12 with overflow constrain"); + +assert.throws( + RangeError, + () => cal.yearMonthFromFields({ year: 2021, month: -99999 }, opt), + "negative month -99999 is out of range even with overflow constrain" +) +assert.throws( + RangeError, + () => cal.yearMonthFromFields({ year: 2021, month: -1 }, opt), + "negative month -1 is out of range even with overflow constrain" +) +assert.throws( + RangeError, + () => cal.yearMonthFromFields({ year: 2021, month: 0 }, opt), + "month zero is out of range even with overflow constrain" +) + +result = cal.yearMonthFromFields({ year: 2021, month: 13 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 13 is constrained to 12"); +result = cal.yearMonthFromFields({ year: 2021, month: 99999 }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 99999 is constrained to 12"); + +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M01" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 1, "M01", "monthCode M01 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M02" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 2, "M02", "monthCode M02 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M03" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 3, "M03", "monthCode M03 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M04" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 4, "M04", "monthCode M04 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M05" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 5, "M05", "monthCode M05 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M06" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 6, "M06", "monthCode M06 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "monthCode M07 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M08" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 8, "M08", "monthCode M08 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M09" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 9, "M09", "monthCode M09 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M10" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 10, "M10", "monthCode M10 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M11" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 11, "M11", "monthCode M11 with overflow constrain"); +result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" }, opt); +TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "monthCode M12 with overflow constrain"); diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js index 99ffe6af277..77c14141097 100644 --- a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js @@ -17,4 +17,11 @@ features: [Temporal] ---*/ const calendar = new Temporal.Calendar("iso8601"); -assert.throws(RangeError, () => calendar.yearMonthFromFields({ year: 2000, month: 5 }, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => calendar.yearMonthFromFields({ year: 2000, month: 5 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js new file mode 100644 index 00000000000..d0d475d9e7b --- /dev/null +++ b/test/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js @@ -0,0 +1,26 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.yearmonthfromfields +description: Throw RangeError for input data out of range with overflow reject +info: | + 1. Let calendar be the this value. + 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). + 3. Assert: calendar.[[Identifier]] is "iso8601". + 4. If Type(fields) is not Object, throw a TypeError exception. + 5. Set options to ? GetOptionsObject(options). + 6. Let result be ? ISOYearMonthFromFields(fields, options). + 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]). +features: [Temporal] +---*/ + +const cal = new Temporal.Calendar("iso8601"); + +[-1, 0, 13, 9995].forEach((month) => { + assert.throws( + RangeError, + () => cal.yearMonthFromFields({year: 2021, month, day: 5}, { overflow: "reject" }), + `Month ${month} is out of range for 2021 with overflow: reject` + ); +}); diff --git a/test/built-ins/Temporal/Duration/compare/calendar-dateadd-called-with-options-undefined.js b/test/built-ins/Temporal/Duration/compare/calendar-dateadd-called-with-options-undefined.js new file mode 100644 index 00000000000..c2169e338a3 --- /dev/null +++ b/test/built-ins/Temporal/Duration/compare/calendar-dateadd-called-with-options-undefined.js @@ -0,0 +1,22 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.compare +description: > + BuiltinTimeZoneGetInstantFor calls Calendar.dateAdd with undefined as the + options value +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddUndefinedOptions(); +const timeZone = TemporalHelpers.oneShiftTimeZone(new Temporal.Instant(0n), 3600e9); +const relativeTo = new Temporal.ZonedDateTime(0n, timeZone, calendar); + +const duration1 = new Temporal.Duration(0, 0, 1); +const duration2 = new Temporal.Duration(0, 0, 1); +Temporal.Duration.compare(duration1, duration2, { relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 4); +// one call in CalculateOffsetShift for each duration argument, plus one in +// UnbalanceDurationRelative for each duration argument diff --git a/test/built-ins/Temporal/Duration/compare/options-wrong-type.js b/test/built-ins/Temporal/Duration/compare/options-wrong-type.js new file mode 100644 index 00000000000..427dd9fee8c --- /dev/null +++ b/test/built-ins/Temporal/Duration/compare/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.compare +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.Duration.compare({ hours: 1 }, { minutes: 60 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/compare/twenty-five-hour-day.js b/test/built-ins/Temporal/Duration/compare/twenty-five-hour-day.js new file mode 100644 index 00000000000..9aeee2d44b5 --- /dev/null +++ b/test/built-ins/Temporal/Duration/compare/twenty-five-hour-day.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.compare +description: Unbalancing handles DST days with more than 24 hours +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tz = TemporalHelpers.springForwardFallBackTimeZone(); + +// 2000-10-29 is a 25-hour day according to this time zone... + +const relativeTo = new Temporal.ZonedDateTime(941187600_000_000_000n, tz); + +// confirm that we have rewound one year and one day: +assert.sameValue('1999-10-29T01:00:00-08:00[Custom/Spring_Fall]', relativeTo.toString()); + +const d1 = new Temporal.Duration(1, 0, 0, 1); +const d2 = new Temporal.Duration(1, 0, 0, 0, 25); + +// ...so the durations should be equal relative to relativeTo: + +assert.sameValue(0, + Temporal.Duration.compare(d1, d2, { relativeTo }), + "2000-10-29 is a 25-hour day" +); + +assert.sameValue(1, + Temporal.Duration.compare(d1, { years: 1, hours: 24 }, { relativeTo }), + "2020-10-29 has more than 24 hours" +); diff --git a/test/built-ins/Temporal/Duration/prototype/abs/basic.js b/test/built-ins/Temporal/Duration/prototype/abs/basic.js new file mode 100644 index 00000000000..ecc2ecf18a2 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/abs/basic.js @@ -0,0 +1,39 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.abs +description: Temporal.Duration.prototype.abs will return absolute value of the input duration. +info: | + 1. Let duration be the this value. + 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + 3. Return ? CreateTemporalDuration(abs(duration.[[Years]]), abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]), abs(duration.[[Hours]]), abs(duration.[[Minutes]]), abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]), abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])). + +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +let d1 = new Temporal.Duration(); +TemporalHelpers.assertDuration( + d1.abs(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "empty"); + +let d2 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +TemporalHelpers.assertDuration( + d2.abs(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "positive"); + +let d3 = new Temporal.Duration(1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5); +TemporalHelpers.assertDuration( + d3.abs(), 1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5, "large positive"); + +let d4 = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10); +TemporalHelpers.assertDuration( + d4.abs(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "negative"); + +// Test with some zeros +let d5 = new Temporal.Duration(1, 0, 3, 0, 5, 0, 7, 0, 9, 0); +TemporalHelpers.assertDuration( + d5.abs(), 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, "some zeros"); + +let d6 = new Temporal.Duration(0, 2, 0, 4, 0, 6, 0, 8, 0, 10); +TemporalHelpers.assertDuration( + d6.abs(), 0, 2, 0, 4, 0, 6, 0, 8, 0, 10, "other zeros"); diff --git a/test/built-ins/Temporal/Duration/prototype/add/options-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/add/options-wrong-type.js new file mode 100644 index 00000000000..37500a0214b --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/add/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Duration(0, 0, 0, 0, 1); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ hours: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/prototype/negated/basic.js b/test/built-ins/Temporal/Duration/prototype/negated/basic.js new file mode 100644 index 00000000000..f2bae4848a7 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/negated/basic.js @@ -0,0 +1,51 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.negated +description: Temporal.Duration.prototype.negated will return negated value of the input duration. +info: | + 3. Return ? CreateTemporalDuration(abs(duration.[[Years]]), abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]), abs(duration.[[Hours]]), abs(duration.[[Minutes]]), abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]), abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])). +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +let d1 = new Temporal.Duration(); +TemporalHelpers.assertDuration( + d1.negated(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "zeros"); + +let d2 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +TemporalHelpers.assertDuration( + d2.negated(), -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, + "positive values"); + +let d3 = new Temporal.Duration(1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5); +TemporalHelpers.assertDuration( + d3.negated(), -1e5, -2e5, -3e5, -4e5, -5e5, -6e5, -7e5, -8e5, -9e5, -10e5, + "large positive values"); + +let d4 = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10); +TemporalHelpers.assertDuration( + d4.negated(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + "negative values"); + +let d5 = new Temporal.Duration(-1e5, -2e5, -3e5, -4e5, -5e5, -6e5, -7e5, -8e5, -9e5, -10e5); +TemporalHelpers.assertDuration( + d5.negated(), 1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5, + "large negative values"); + +let d6 = new Temporal.Duration(1, 0, 3, 0, 5, 0, 7, 0, 9, 0); +TemporalHelpers.assertDuration( + d6.negated(), -1, 0, -3, 0, -5, 0, -7, 0, -9, 0, + "some zeros with positive values"); + +let d7 = new Temporal.Duration(-1, 0, -3, 0, -5, 0, -7, 0, -9, 0); +TemporalHelpers.assertDuration( + d7.negated(), 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, + "some zeros with negative values"); + +let d8 = new Temporal.Duration(0, -2, 0, -4, 0, -6, 0, -8, 0, -10); +TemporalHelpers.assertDuration( + d8.negated(), 0, 2, 0, 4, 0, 6, 0, 8, 0, 10, + "other zeros with negative values"); diff --git a/test/built-ins/Temporal/Duration/prototype/round/calendar-dateadd-called-with-options-undefined.js b/test/built-ins/Temporal/Duration/prototype/round/calendar-dateadd-called-with-options-undefined.js new file mode 100644 index 00000000000..2c81eabfa02 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/round/calendar-dateadd-called-with-options-undefined.js @@ -0,0 +1,73 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.round +description: > + BuiltinTimeZoneGetInstantFor calls Calendar.dateAdd with undefined as the + options value +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddUndefinedOptions(); +const timeZone = TemporalHelpers.oneShiftTimeZone(new Temporal.Instant(0n), 3600e9); +const relativeTo = new Temporal.ZonedDateTime(0n, timeZone, calendar); + +// Rounding with smallestUnit a calendar unit. +// The calls come from these paths: +// Duration.round() -> +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// BalanceDurationRelative -> +// MoveRelativeDate -> calendar.dateAdd() (2x) +// calendar.dateAdd() +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// BalanceDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) + +const instance1 = new Temporal.Duration(1, 1, 1, 1, 1); +instance1.round({ smallestUnit: "days", relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 9, "rounding with calendar smallestUnit"); + +// Rounding with a non-default largestUnit to cover the path in +// UnbalanceDurationRelative where larger units are converted into smaller +// units; and with a smallestUnit larger than days to cover the path in +// RoundDuration where days are converted into larger units. +// The calls come from these paths: +// Duration.round() -> +// UnbalanceDurationRelative -> MoveRelativeDate -> calendar.dateAdd() +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// MoveRelativeDate -> calendar.dateAdd() (5x) +// BalanceDurationRelative +// MoveRelativeDate -> calendar.dateAdd() +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() + +calendar.dateAddCallCount = 0; + +const instance2 = new Temporal.Duration(0, 1, 1, 1); +instance2.round({ largestUnit: "weeks", smallestUnit: "weeks", relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 9, "rounding with non-default largestUnit and calendar smallestUnit"); + +// Rounding with smallestUnit a non-calendar unit, and having the resulting time +// difference be longer than a calendar day, covering the paths that go through +// AdjustRoundedDurationDays. +// The calls come from these paths: +// Duration.round() -> +// AdjustRoundedDurationDays -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// AddDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) +// BalanceDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) + +calendar.dateAddCallCount = 0; + +const instance3 = new Temporal.Duration(0, 0, 0, 0, 23, 59, 59, 999, 999, 999); +instance3.round({ largestUnit: "days", smallestUnit: "hours", roundingMode: "ceil", relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 7, "rounding with time difference exceeding calendar day"); diff --git a/test/built-ins/Temporal/Duration/prototype/round/options-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/round/options-wrong-type.js new file mode 100644 index 00000000000..a224a6e737a --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/round/options-wrong-type.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.round +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + undefined, + null, + true, + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Duration(0, 0, 0, 0, 1); +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/prototype/round/smallestunit-invalid-string.js b/test/built-ins/Temporal/Duration/prototype/round/smallestunit-invalid-string.js index 3d5d884b527..0904c0ccc84 100644 --- a/test/built-ins/Temporal/Duration/prototype/round/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Duration/prototype/round/smallestunit-invalid-string.js @@ -8,4 +8,20 @@ features: [Temporal] ---*/ const duration = new Temporal.Duration(0, 0, 0, 0, 12, 34, 56, 123, 987, 500); -assert.throws(RangeError, () => duration.round({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => duration.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/options-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/subtract/options-wrong-type.js new file mode 100644 index 00000000000..4bb257b88b2 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/subtract/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Duration(0, 0, 0, 0, 1); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ hours: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/prototype/toJSON/basic.js b/test/built-ins/Temporal/Duration/prototype/toJSON/basic.js new file mode 100644 index 00000000000..8cadc51661c --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toJSON/basic.js @@ -0,0 +1,240 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tojson +description: Temporal.Duration.prototype.toJSON will return correct iso8601 string for the given duration. +info: | + 1. Let duration be the this value. + 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + 3. Return ! TemporalDurationToString(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], "auto"). +features: [Temporal] +---*/ + +let d = new Temporal.Duration(); +assert.sameValue(d.toJSON(), "PT0S", "zero duration"); + +d = new Temporal.Duration(1); +assert.sameValue(d.toJSON(), "P1Y", "positive small years"); +d = new Temporal.Duration(-1); +assert.sameValue(d.toJSON(), "-P1Y", "negative small years"); +d = new Temporal.Duration(1234567890); +assert.sameValue(d.toJSON(), "P1234567890Y", "positive large years"); +d = new Temporal.Duration(-1234567890); +assert.sameValue(d.toJSON(), "-P1234567890Y", "negative large years"); + +d = new Temporal.Duration(1, 2); +assert.sameValue(d.toJSON(), "P1Y2M", "positive years and months"); +d = new Temporal.Duration(-1, -2); +assert.sameValue(d.toJSON(), "-P1Y2M", "negative years and months"); +d = new Temporal.Duration(0, 2); +assert.sameValue(d.toJSON(), "P2M", "positive small months"); +d = new Temporal.Duration(0,-2); +assert.sameValue(d.toJSON(), "-P2M", "negative small months"); +d = new Temporal.Duration(0, 1234567890); +assert.sameValue(d.toJSON(), "P1234567890M", "positive large months"); +d = new Temporal.Duration(0,-1234567890); +assert.sameValue(d.toJSON(), "-P1234567890M", "negative large months"); + +d = new Temporal.Duration(1, 2, 3); +assert.sameValue(d.toJSON(), "P1Y2M3W", "positive years, months, weeks"); +d = new Temporal.Duration(-1, -2, -3); +assert.sameValue(d.toJSON(), "-P1Y2M3W", "negative years, months, weeks"); +d = new Temporal.Duration(0, 0, 3); +assert.sameValue(d.toJSON(), "P3W", "positive small weeks"); +d = new Temporal.Duration(0, 0, -3); +assert.sameValue(d.toJSON(), "-P3W", "negative small weeks"); +d = new Temporal.Duration(1, 0, 3); +assert.sameValue(d.toJSON(), "P1Y3W", "positive years and weeks"); +d = new Temporal.Duration(-1, 0, -3); +assert.sameValue(d.toJSON(), "-P1Y3W", "negative years and weeks"); +d = new Temporal.Duration(0, 2, 3); +assert.sameValue(d.toJSON(), "P2M3W", "positive months and weeks"); +d = new Temporal.Duration(0, -2, -3); +assert.sameValue(d.toJSON(), "-P2M3W", "negative months and weeks"); +d = new Temporal.Duration(0, 0, 1234567890); +assert.sameValue(d.toJSON(), "P1234567890W", "positive large weeks"); +d = new Temporal.Duration(0, 0, -1234567890); +assert.sameValue(d.toJSON(), "-P1234567890W", "negative large weeks"); + +d = new Temporal.Duration(1, 2, 3, 4); +assert.sameValue(d.toJSON(), "P1Y2M3W4D", "positive years, months, weeks, days"); +d = new Temporal.Duration(-1, -2, -3, -4); +assert.sameValue(d.toJSON(), "-P1Y2M3W4D", "negative years, months, weeks, days"); +d = new Temporal.Duration(0, 0, 0, 1234567890); +assert.sameValue(d.toJSON(), "P1234567890D", "positive large days"); +d = new Temporal.Duration(0, 0, 0, -1234567890); +assert.sameValue(d.toJSON(), "-P1234567890D", "negative large days"); +d = new Temporal.Duration(0, 0, 0, 4); +assert.sameValue(d.toJSON(), "P4D", "positive small days"); +d = new Temporal.Duration(0, 0, 0, -4); +assert.sameValue(d.toJSON(), "-P4D", "negative small days"); +d = new Temporal.Duration(1, 0, 0, 4); +assert.sameValue(d.toJSON(), "P1Y4D", "positive years and days"); +d = new Temporal.Duration(-1, 0, 0, -4); +assert.sameValue(d.toJSON(), "-P1Y4D", "negative years and days"); +d = new Temporal.Duration(0, 2, 0, 4); +assert.sameValue(d.toJSON(), "P2M4D", "positive months and days"); +d = new Temporal.Duration(0, -2, 0, -4); +assert.sameValue(d.toJSON(), "-P2M4D", "negative months and days"); +d = new Temporal.Duration(0, 0, 3, 4); +assert.sameValue(d.toJSON(), "P3W4D", "positive weeks and days"); +d = new Temporal.Duration(0, 0, -3, -4); +assert.sameValue(d.toJSON(), "-P3W4D", "negative weeks and days"); + +d = new Temporal.Duration(0, 0, 0, 0, 5); +assert.sameValue(d.toJSON(), "PT5H", "positive hours"); +d = new Temporal.Duration(0, 0, 0, 0, -5); +assert.sameValue(d.toJSON(), "-PT5H", "negative hours"); +d = new Temporal.Duration(1, 0, 0, 0, 5); +assert.sameValue(d.toJSON(), "P1YT5H", "positive years and hours"); +d = new Temporal.Duration(-1, 0, 0, 0, -5); +assert.sameValue(d.toJSON(), "-P1YT5H", "negative years and hours"); +d = new Temporal.Duration(0, 2, 0, 0, 5); +assert.sameValue(d.toJSON(), "P2MT5H", "positive months and hours"); +d = new Temporal.Duration(0, -2, 0, 0, -5); +assert.sameValue(d.toJSON(), "-P2MT5H", "negative months and hours"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 6); +assert.sameValue(d.toJSON(), "PT6M", "positive minutes"); +d = new Temporal.Duration(0, 0, 0, 0, 0, -6); +assert.sameValue(d.toJSON(), "-PT6M", "negative minutes"); +d = new Temporal.Duration(0, 0, 0, 0, 5, 6); +assert.sameValue(d.toJSON(), "PT5H6M", "positive hours and minutes"); +d = new Temporal.Duration(0, 0, 0, 0, -5, -6); +assert.sameValue(d.toJSON(), "-PT5H6M", "negative hours and minutes"); +d = new Temporal.Duration(0, 0, 3, 0, 0, 6); +assert.sameValue(d.toJSON(), "P3WT6M", "positive weeks and minutes"); +d = new Temporal.Duration(0, 0, -3, 0, 0, -6); +assert.sameValue(d.toJSON(), "-P3WT6M", "negative weeks and minutes"); +d = new Temporal.Duration(0, 0, 0, 4, 0, 6); +assert.sameValue(d.toJSON(), "P4DT6M", "positive days and minutes"); +d = new Temporal.Duration(0, 0, 0, -4, 0, -6); +assert.sameValue(d.toJSON(), "-P4DT6M", "negative days and minutes"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 7); +assert.sameValue(d.toJSON(), "PT7S", "positive seconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, -7); +assert.sameValue(d.toJSON(), "-PT7S", "negative seconds"); +d = new Temporal.Duration(0, 0, 0, 0, 5, 0, 7); +assert.sameValue(d.toJSON(), "PT5H7S", "positive hours and seconds"); +d = new Temporal.Duration(0, 0, 0, 0, -5, 0, -7); +assert.sameValue(d.toJSON(), "-PT5H7S", "negative hours and seconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 6, 7); +assert.sameValue(d.toJSON(), "PT6M7S", "positive minutes and seconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, -6, -7); +assert.sameValue(d.toJSON(), "-PT6M7S", "negative minutes and seconds"); +d = new Temporal.Duration(0, 0, 0, 0, 5, 6, 7); +assert.sameValue(d.toJSON(), "PT5H6M7S", "positive hours, minutes, seconds"); +d = new Temporal.Duration(0, 0, 0, 0, -5, -6, -7); +assert.sameValue(d.toJSON(), "-PT5H6M7S", "negative hours, minutes, seconds"); +d = new Temporal.Duration(1, 0, 0, 0, 5, 6, 7); +assert.sameValue(d.toJSON(), "P1YT5H6M7S", "positive years, hours, minutes, seconds"); +d = new Temporal.Duration(-1, 0, 0, 0, -5, -6, -7); +assert.sameValue(d.toJSON(), "-P1YT5H6M7S", "negative years, hours, minutes, seconds"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 8); +assert.sameValue(d.toJSON(), "PT0.008S", "positive milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -8); +assert.sameValue(d.toJSON(), "-PT0.008S", "negative milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 80); +assert.sameValue(d.toJSON(), "PT0.08S", "positive milliseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -80); +assert.sameValue(d.toJSON(), "-PT0.08S", "negative milliseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 87); +assert.sameValue(d.toJSON(), "PT0.087S", "positive two-digit milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -87); +assert.sameValue(d.toJSON(), "-PT0.087S", "negative two-digit milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 876); +assert.sameValue(d.toJSON(), "PT0.876S", "positive three-digit milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -876); +assert.sameValue(d.toJSON(), "-PT0.876S", "negative three-digit milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 876543); +assert.sameValue(d.toJSON(), "PT876.543S", "positive large milliseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -876543); +assert.sameValue(d.toJSON(), "-PT876.543S", "negative large milliseconds"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 9); +assert.sameValue(d.toJSON(), "PT0.000009S", "positive microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -9); +assert.sameValue(d.toJSON(), "-PT0.000009S", "negative microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 90); +assert.sameValue(d.toJSON(), "PT0.00009S", "positive microseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -90); +assert.sameValue(d.toJSON(), "-PT0.00009S", "negative microseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 98); +assert.sameValue(d.toJSON(), "PT0.000098S", "positive two-digit microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -98); +assert.sameValue(d.toJSON(), "-PT0.000098S", "negative two-digit microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 900); +assert.sameValue(d.toJSON(), "PT0.0009S", "positive microseconds multiple of 100"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -900); +assert.sameValue(d.toJSON(), "-PT0.0009S", "negative microseconds multiple of 100"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 987); +assert.sameValue(d.toJSON(), "PT0.000987S", "positive three-digit microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -987); +assert.sameValue(d.toJSON(), "-PT0.000987S", "negative three-digit microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 987654); +assert.sameValue(d.toJSON(), "PT0.987654S", "positive large microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -987654); +assert.sameValue(d.toJSON(), "-PT0.987654S", "negative large microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 987654321); +assert.sameValue(d.toJSON(), "PT987.654321S", "positive larger microseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -987654321); +assert.sameValue(d.toJSON(), "-PT987.654321S", "negative larger microseconds"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 1); +assert.sameValue(d.toJSON(), "PT0.000000001S", "positive nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -1); +assert.sameValue(d.toJSON(), "-PT0.000000001S", "negative nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 10); +assert.sameValue(d.toJSON(), "PT0.00000001S", "positive nanoseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -10); +assert.sameValue(d.toJSON(), "-PT0.00000001S", "negative nanoseconds multiple of 10"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 12); +assert.sameValue(d.toJSON(), "PT0.000000012S", "positive two-digit nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -12); +assert.sameValue(d.toJSON(), "-PT0.000000012S", "negative two-digit nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 100); +assert.sameValue(d.toJSON(), "PT0.0000001S", "positive nanoseconds multiple of 100"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -100); +assert.sameValue(d.toJSON(), "-PT0.0000001S", "negative nanoseconds multiple of 100"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 123); +assert.sameValue(d.toJSON(), "PT0.000000123S", "positive three-digit nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -123); +assert.sameValue(d.toJSON(), "-PT0.000000123S", "negative three-digit nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 123456); +assert.sameValue(d.toJSON(), "PT0.000123456S", "positive large nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -123456); +assert.sameValue(d.toJSON(), "-PT0.000123456S", "negative large nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 123456789); +assert.sameValue(d.toJSON(), "PT0.123456789S", "positive larger nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -123456789); +assert.sameValue(d.toJSON(), "-PT0.123456789S", "negative larger nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 1234567891); +assert.sameValue(d.toJSON(), "PT1.234567891S", "positive even larger nanoseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -1234567891); +assert.sameValue(d.toJSON(), "-PT1.234567891S", "negative even larger nanoseconds"); + +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 4, 3, 2, 1); +assert.sameValue(d.toJSON(), "PT4.003002001S", "positive seconds and subseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, -4, -3, -2, -1); +assert.sameValue(d.toJSON(), "-PT4.003002001S", "negative seconds and subseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 4, 3, 2, 90001); +assert.sameValue(d.toJSON(), "PT4.003092001S", "positive seconds and large subseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, -4, -3, -2, -90001); +assert.sameValue(d.toJSON(), "-PT4.003092001S", "negative seconds and large subseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, 4, 3, 2, 90080001); +assert.sameValue(d.toJSON(), "PT4.093082001S", "positive seconds and larger subseconds"); +d = new Temporal.Duration(0, 0, 0, 0, 0, 0, -4, -3, -2, -90080001); +assert.sameValue(d.toJSON(), "-PT4.093082001S", "negative seconds and larger subseconds"); + +d = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 1); +assert.sameValue(d.toJSON(), "P1Y2M3W4DT5H6M7.008009001S", "all fields positive"); +d = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -1); +assert.sameValue(d.toJSON(), "-P1Y2M3W4DT5H6M7.008009001S", "all fields negative"); + +d = new Temporal.Duration(1234, 2345, 3456, 4567, 5678, 6789, 7890, 890, 901, 123); +assert.sameValue(d.toJSON(), "P1234Y2345M3456W4567DT5678H6789M7890.890901123S", "all fields large and positive"); +d = new Temporal.Duration(-1234, -2345, -3456, -4567, -5678, -6789, -7890, -890, -901, -123); +assert.sameValue(d.toJSON(), "-P1234Y2345M3456W4567DT5678H6789M7890.890901123S", "all fields large and negative"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-auto.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-auto.js new file mode 100644 index 00000000000..941b9dce931 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-auto.js @@ -0,0 +1,21 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: auto value for fractionalSecondDigits option +features: [Temporal] +---*/ + +const wholeSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7); +const subSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650); + +const tests = [ + [wholeSeconds, "P1Y2M3W4DT5H6M7S"], + [subSeconds, "P1Y2M3W4DT5H6M7.98765S"], +]; + +for (const [duration, expected] of tests) { + assert.sameValue(duration.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(duration.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); +} diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js index 036b977ad16..5af9938e232 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js @@ -16,6 +16,7 @@ features: [Temporal] const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0); -for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos"]) { - assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits })); +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); } diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-number.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-number.js new file mode 100644 index 00000000000..764986cb2e4 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-number.js @@ -0,0 +1,28 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: Number for fractionalSecondDigits option +features: [Temporal] +---*/ + +const wholeSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7); +const subSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650); + +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "P1Y2M3W4DT5H6M7S", + "truncates 4 decimal places to 0"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "P1Y2M3W4DT5H6M7.00S", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "P1Y2M3W4DT5H6M7.98S", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "P1Y2M3W4DT5H6M7.987S", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "P1Y2M3W4DT5H6M7.987650S", + "pads 4 decimal places to 6"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "P1Y2M3W4DT5H6M7.0000000S", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "P1Y2M3W4DT5H6M7.9876500S", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "P1Y2M3W4DT5H6M7.987650000S", + "pads 4 decimal places to 9"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js index 9a20541c19f..ab73ad69bd1 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js @@ -16,7 +16,11 @@ features: [Temporal] const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0); -assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -Infinity })); -assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -1 })); -assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 10 })); -assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: Infinity })); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js index 2c3af23ae92..292b8df300a 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js @@ -16,10 +16,21 @@ info: | features: [Temporal] ---*/ -const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0); +const wholeSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7); +const subSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650); -const explicit = duration.toString({ fractionalSecondDigits: undefined }); -assert.sameValue(explicit, "P1Y2M3W4DT5H6M7.98765S", "default fractionalSecondDigits is auto"); +const tests = [ + [wholeSeconds, "P1Y2M3W4DT5H6M7S"], + [subSeconds, "P1Y2M3W4DT5H6M7.98765S"], +]; -const implicit = duration.toString({}); -assert.sameValue(implicit, "P1Y2M3W4DT5H6M7.98765S", "default fractionalSecondDigits is auto"); +for (const [duration, expected] of tests) { + const explicit = duration.toString({ fractionalSecondDigits: undefined }); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); + + const implicit = duration.toString({}); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); + + const lambda = duration.toString(() => {}); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); +} diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js index 143de7c3440..625daaff1da 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js @@ -22,4 +22,26 @@ features: [Temporal] ---*/ const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0); -TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(duration); + +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => duration.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = duration.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "P1Y2M3W4DT5H6M7.98765S", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..7cd68050a11 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Duration(0, 0, 0, 0, 1); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-ceil.js b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-ceil.js new file mode 100644 index 00000000000..cdef0c52741 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-ceil.js @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: ceil value for roundingMode option +features: [Temporal] +---*/ + +const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 123, 987, 500); + +const result1 = duration.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); +assert.sameValue(result1, "P1Y2M3W4DT5H6M7.123988S", + "roundingMode is ceil (with 6 digits from smallestUnit)"); + +const result2 = duration.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "P1Y2M3W4DT5H6M7.123988S", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); + +const result3 = duration.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "P1Y2M3W4DT5H6M7.124S", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = duration.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "P1Y2M3W4DT5H6M7.124S", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = duration.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "P1Y2M3W4DT5H6M8S", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = duration.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "P1Y2M3W4DT5H6M8S", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-floor.js b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-floor.js new file mode 100644 index 00000000000..e1ee18b5c8e --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-floor.js @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: floor value for roundingMode option +features: [Temporal] +---*/ + +const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 123, 987, 500); + +const result1 = duration.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); +assert.sameValue(result1, "P1Y2M3W4DT5H6M7.123987S", + "roundingMode is floor (with 6 digits from smallestUnit)"); + +const result2 = duration.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "P1Y2M3W4DT5H6M7.123987S", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); + +const result3 = duration.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "P1Y2M3W4DT5H6M7.123S", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = duration.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "P1Y2M3W4DT5H6M7.123S", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = duration.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "P1Y2M3W4DT5H6M7S", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = duration.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "P1Y2M3W4DT5H6M7S", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-halfExpand.js b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-halfExpand.js new file mode 100644 index 00000000000..9a11468a126 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-halfExpand.js @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: halfExpand value for roundingMode option +features: [Temporal] +---*/ + +const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 123, 987, 500); + +const result1 = duration.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); +assert.sameValue(result1, "P1Y2M3W4DT5H6M7.123988S", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); + +const result2 = duration.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "P1Y2M3W4DT5H6M7.123988S", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); + +const result3 = duration.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "P1Y2M3W4DT5H6M7.124S", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = duration.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "P1Y2M3W4DT5H6M7.124S", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = duration.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "P1Y2M3W4DT5H6M7S", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = duration.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "P1Y2M3W4DT5H6M7S", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-trunc.js b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-trunc.js new file mode 100644 index 00000000000..3b66fb5201a --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/roundingmode-trunc.js @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: trunc value for roundingMode option +features: [Temporal] +---*/ + +const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 123, 987, 500); + +const result1 = duration.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); +assert.sameValue(result1, "P1Y2M3W4DT5H6M7.123987S", + "roundingMode is trunc (with 6 digits from smallestUnit)"); + +const result2 = duration.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "P1Y2M3W4DT5H6M7.123987S", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = duration.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "P1Y2M3W4DT5H6M7.123S", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = duration.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "P1Y2M3W4DT5H6M7.123S", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = duration.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "P1Y2M3W4DT5H6M7S", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = duration.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "P1Y2M3W4DT5H6M7S", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-fractionalseconddigits.js b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-fractionalseconddigits.js new file mode 100644 index 00000000000..19d10523801 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-fractionalseconddigits.js @@ -0,0 +1,29 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.tostring +description: fractionalSecondDigits option is not used with smallestUnit present +features: [Temporal] +---*/ + +const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 789, 999, 999); +const tests = [ + ["second", "P1Y2M3W4DT5H6M7S"], + ["millisecond", "P1Y2M3W4DT5H6M7.789S"], + ["microsecond", "P1Y2M3W4DT5H6M7.789999S"], + ["nanosecond", "P1Y2M3W4DT5H6M7.789999999S"], +]; + +for (const [smallestUnit, expected] of tests) { + const string = duration.toString({ + smallestUnit, + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } + }); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); +} + +assert.throws(RangeError, () => duration.toString({ + smallestUnit: "hour", + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-invalid-string.js b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-invalid-string.js index 046b4a99f70..5405996c5df 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-invalid-string.js @@ -8,7 +8,32 @@ features: [Temporal] ---*/ const duration = new Temporal.Duration(0, 0, 0, 0, 12, 34, 56, 123, 987, 500); -const values = ["eras", "years", "months", "weeks", "days", "hours", "minutes", "nonsense", "other string", "mill\u0131seconds", "SECONDS"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => duration.toString({ smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "minute", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "minutes", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => duration.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js index fce836b31b1..24880177e23 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js @@ -9,12 +9,37 @@ features: [Temporal] const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321); -assert.sameValue(duration.toString({ smallestUnit: "second" }), "P1Y2M3W4DT5H6M7S"); -assert.sameValue(duration.toString({ smallestUnit: "millisecond" }), "P1Y2M3W4DT5H6M7.987S"); -assert.sameValue(duration.toString({ smallestUnit: "microsecond" }), "P1Y2M3W4DT5H6M7.987654S"); -assert.sameValue(duration.toString({ smallestUnit: "nanosecond" }), "P1Y2M3W4DT5H6M7.987654321S"); +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + duration, + [ + ["seconds", "P1Y2M3W4DT5H6M7S"], + ["milliseconds", "P1Y2M3W4DT5H6M7.987S"], + ["microseconds", "P1Y2M3W4DT5H6M7.987654S"], + ["nanoseconds", "P1Y2M3W4DT5H6M7.987654321S"], + ], + "subseconds toString" +); + +test( + new Temporal.Duration(1, 2, 3, 4, 5, 6, 7), + [ + ["seconds", "P1Y2M3W4DT5H6M7S"], + ["milliseconds", "P1Y2M3W4DT5H6M7.000S"], + ["microseconds", "P1Y2M3W4DT5H6M7.000000S"], + ["nanoseconds", "P1Y2M3W4DT5H6M7.000000000S"], + ], + "whole seconds toString" +); const notValid = [ + "era", "year", "month", "week", @@ -24,5 +49,6 @@ const notValid = [ ]; notValid.forEach((smallestUnit) => { - assert.throws(RangeError, () => duration.toString({ smallestUnit }), smallestUnit); + assert.throws(RangeError, () => duration.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); }); diff --git a/test/built-ins/Temporal/Duration/prototype/total/calendar-dateadd-called-with-options-undefined.js b/test/built-ins/Temporal/Duration/prototype/total/calendar-dateadd-called-with-options-undefined.js new file mode 100644 index 00000000000..6ae88e1d942 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/total/calendar-dateadd-called-with-options-undefined.js @@ -0,0 +1,49 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.total +description: > + BuiltinTimeZoneGetInstantFor calls Calendar.dateAdd with undefined as the + options value +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddUndefinedOptions(); +const timeZone = TemporalHelpers.oneShiftTimeZone(new Temporal.Instant(0n), 3600e9); +const relativeTo = new Temporal.ZonedDateTime(0n, timeZone, calendar); + +// Total of a calendar unit where larger calendar units have to be converted +// down, to cover the path that goes through UnbalanceDurationRelative +// The calls come from these paths: +// Duration.total() -> +// UnbalanceDurationRelative -> MoveRelativeDate -> calendar.dateAdd() (3x) +// BalanceDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() + +const instance1 = new Temporal.Duration(1, 1, 1, 1, 1); +instance1.total({ unit: "days", relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 8, "converting larger calendar units down"); + +// Total of a calendar unit where smaller calendar units have to be converted +// up, to cover the path that goes through MoveRelativeZonedDateTime +// The calls come from these paths: +// Duration.total() -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// BalanceDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// MoveRelativeDate -> calendar.dateAdd() + +calendar.dateAddCallCount = 0; + +const instance2 = new Temporal.Duration(0, 0, 1, 1); +instance2.total({ unit: "weeks", relativeTo }); +assert.sameValue(calendar.dateAddCallCount, 6, "converting smaller calendar units up"); diff --git a/test/built-ins/Temporal/Duration/prototype/total/options-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/total/options-wrong-type.js index 9b92bca4836..ae20fe1b49e 100644 --- a/test/built-ins/Temporal/Duration/prototype/total/options-wrong-type.js +++ b/test/built-ins/Temporal/Duration/prototype/total/options-wrong-type.js @@ -1,13 +1,13 @@ -// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// Copyright (C) 2022 Igalia, S.L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- esid: sec-temporal.duration.prototype.total -description: TypeError thrown when options argument is missing or a primitive +description: TypeError thrown when options argument is missing or a non-string primitive features: [BigInt, Symbol, Temporal] ---*/ -const values = [ +const badOptions = [ undefined, null, true, @@ -17,7 +17,8 @@ const values = [ ]; const instance = new Temporal.Duration(0, 0, 0, 0, 1); -assert.throws(TypeError, () => instance.total(), "TypeError on missing argument"); -values.forEach((value) => { - assert.throws(TypeError, () => instance.total(value), `TypeError on wrong argument type ${typeof(value)}`); -}); +assert.throws(TypeError, () => instance.total(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.total(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Duration/prototype/with/all-negative.js b/test/built-ins/Temporal/Duration/prototype/with/all-negative.js new file mode 100644 index 00000000000..e094455bb8e --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/all-negative.js @@ -0,0 +1,93 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: > + Returns a correctly merged object when the argument replaces the fields with + all negative values. +info: | + 1. Let duration be the this value. + 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + 3. Let temporalDurationLike be ? ToPartialDuration(temporalDurationLike). + 4. If temporalDurationLike.[[Years]] is not undefined, then + a. Let years be temporalDurationLike.[[Years]]. + 5. Else, + a. Let years be duration.[[Years]]. + 6. If temporalDurationLike.[[Months]] is not undefined, then + a. Let months be temporalDurationLike.[[Months]]. + 7. Else, + a. Let months be duration.[[Months]]. + 8. If temporalDurationLike.[[Weeks]] is not undefined, then + a. Let weeks be temporalDurationLike.[[Weeks]]. + 9. Else, + a. Let weeks be duration.[[Weeks]]. + 10. If temporalDurationLike.[[Days]] is not undefined, then + a. Let days be temporalDurationLike.[[Days]]. + 11. Else, + a. Let days be duration.[[Days]]. + 12. If temporalDurationLike.[[Hours]] is not undefined, then + a. Let hours be temporalDurationLike.[[Hours]]. + 13. Else, + a. Let hours be duration.[[Hours]]. + 14. If temporalDurationLike.[[Minutes]] is not undefined, then + a. Let minutes be temporalDurationLike.[[Minutes]]. + 15. Else, + a. Let minutes be duration.[[Minutes]]. + 16. If temporalDurationLike.[[Seconds]] is not undefined, then + a. Let seconds be temporalDurationLike.[[Seconds]]. + 17. Else, + a. Let seconds be duration.[[Seconds]]. + 18. If temporalDurationLike.[[Milliseconds]] is not undefined, then + a. Let milliseconds be temporalDurationLike.[[Milliseconds]]. + 19. Else, + a. Let milliseconds be duration.[[Milliseconds]]. + 20. If temporalDurationLike.[[Microseconds]] is not undefined, then + a. Let microseconds be temporalDurationLike.[[Microseconds]]. + 21. Else, + a. Let microseconds be duration.[[Microseconds]]. + 22. If temporalDurationLike.[[Nanoseconds]] is not undefined, then + a. Let nanoseconds be temporalDurationLike.[[Nanoseconds]]. + 23. Else, + a. Let nanoseconds be duration.[[Nanoseconds]]. + 24. Return ? CreateTemporalDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const argAllNegative = { + years: -9, + months: -8, + weeks: -7, + days: -6, + hours: -5, + minutes: -4, + seconds: -3, + milliseconds: -2, + microseconds: -1, + nanoseconds: -10, +}; + +const d1 = new Temporal.Duration(); +TemporalHelpers.assertDuration( + d1.with(argAllNegative), -9, -8, -7, -6, -5, -4, -3, -2, -1, -10, + "replace all zeroes with all negative" +); + +const d2 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +TemporalHelpers.assertDuration( + d2.with(argAllNegative), -9, -8, -7, -6, -5, -4, -3, -2, -1, -10, + "replace all positive with all negative" +); + +const d3 = new Temporal.Duration(1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5); +TemporalHelpers.assertDuration( + d3.with(argAllNegative), -9, -8, -7, -6, -5, -4, -3, -2, -1, -10, + "replace all positive large numbers with all negative" +); + +const d4 = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10); +TemporalHelpers.assertDuration( + d4.with(argAllNegative), -9, -8, -7, -6, -5, -4, -3, -2, -1, -10, + "replace all negative with all negative" +); diff --git a/test/built-ins/Temporal/Duration/prototype/with/all-positive.js b/test/built-ins/Temporal/Duration/prototype/with/all-positive.js new file mode 100644 index 00000000000..21584232fc0 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/all-positive.js @@ -0,0 +1,92 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: > + Returns a correctly merged object when the argument replaces the fields with + all positive values. +info: | + 1. Let duration be the this value. + 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + 3. Let temporalDurationLike be ? ToPartialDuration(temporalDurationLike). + 4. If temporalDurationLike.[[Years]] is not undefined, then + a. Let years be temporalDurationLike.[[Years]]. + 5. Else, + a. Let years be duration.[[Years]]. + 6. If temporalDurationLike.[[Months]] is not undefined, then + a. Let months be temporalDurationLike.[[Months]]. + 7. Else, + a. Let months be duration.[[Months]]. + 8. If temporalDurationLike.[[Weeks]] is not undefined, then + a. Let weeks be temporalDurationLike.[[Weeks]]. + 9. Else, + a. Let weeks be duration.[[Weeks]]. + 10. If temporalDurationLike.[[Days]] is not undefined, then + a. Let days be temporalDurationLike.[[Days]]. + 11. Else, + a. Let days be duration.[[Days]]. + 12. If temporalDurationLike.[[Hours]] is not undefined, then + a. Let hours be temporalDurationLike.[[Hours]]. + 13. Else, + a. Let hours be duration.[[Hours]]. + 14. If temporalDurationLike.[[Minutes]] is not undefined, then + a. Let minutes be temporalDurationLike.[[Minutes]]. + 15. Else, + a. Let minutes be duration.[[Minutes]]. + 16. If temporalDurationLike.[[Seconds]] is not undefined, then + a. Let seconds be temporalDurationLike.[[Seconds]]. + 17. Else, + a. Let seconds be duration.[[Seconds]]. + 18. If temporalDurationLike.[[Milliseconds]] is not undefined, then + a. Let milliseconds be temporalDurationLike.[[Milliseconds]]. + 19. Else, + a. Let milliseconds be duration.[[Milliseconds]]. + 20. If temporalDurationLike.[[Microseconds]] is not undefined, then + a. Let microseconds be temporalDurationLike.[[Microseconds]]. + 21. Else, + a. Let microseconds be duration.[[Microseconds]]. + 22. If temporalDurationLike.[[Nanoseconds]] is not undefined, then + a. Let nanoseconds be temporalDurationLike.[[Nanoseconds]]. + 23. Else, + a. Let nanoseconds be duration.[[Nanoseconds]]. + 24. Return ? CreateTemporalDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const argAllPositive = { + years: 9, + months: 8, + weeks: 7, + days: 6, + hours: 5, + minutes: 4, + seconds: 3, + milliseconds: 2, + microseconds: 1, + nanoseconds: 10, +}; + +const d1 = new Temporal.Duration(); +TemporalHelpers.assertDuration( + d1.with(argAllPositive), 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, + "replace all zeroes with all positive" +); + +const d2 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +TemporalHelpers.assertDuration( + d2.with(argAllPositive), 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, + "replace all positive with all positive"); + +const d3 = new Temporal.Duration(1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 10e5); +TemporalHelpers.assertDuration( + d3.with(argAllPositive), 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, + "replace all positive large numbers with all positive" +); + +const d4 = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10); +TemporalHelpers.assertDuration( + d4.with(argAllPositive), 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, + "replace all negative with all positive" +); diff --git a/test/built-ins/Temporal/Duration/prototype/with/argument-object-wrong-shape.js b/test/built-ins/Temporal/Duration/prototype/with/argument-object-wrong-shape.js new file mode 100644 index 00000000000..5c17076bec5 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/argument-object-wrong-shape.js @@ -0,0 +1,31 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: > + The durationLike argument must contain at least one correctly spelled property +features: [Temporal] +---*/ + +let d = new Temporal.Duration(1, 2, 3, 4, 5); + +[ + {}, + [], + () => {}, + // objects with only singular keys (plural is the correct spelling) + { year: 1 }, + { month: 2 }, + { week: 3 }, + { day: 4 }, + { hour: 5 }, + { minute: 6 }, + { second: 7 }, + { millisecond: 8 }, + { microsecond: 9 }, + { nanosecond: 10 }, +].forEach((badObject) => { + assert.throws(TypeError, () => d.with(badObject), + "Throw TypeError if temporalDurationLike is not valid"); +}); diff --git a/test/built-ins/Temporal/Duration/prototype/with/argument-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/with/argument-wrong-type.js new file mode 100644 index 00000000000..41163a35da6 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/argument-wrong-type.js @@ -0,0 +1,27 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: Throw TypeError if the temporalDurationLike argument is the wrong type +features: [Temporal] +---*/ + +let d = new Temporal.Duration(1, 2, 3, 4, 5); + +[ + "string", + "P1YT1M", + true, + false, + NaN, + Infinity, + undefined, + null, + 123, + Symbol(), + 456n, +].forEach((badInput) => { + assert.throws(TypeError, () => d.with(badInput), + "Throw TypeError if temporalDurationLike is not valid"); +}); diff --git a/test/built-ins/Temporal/Duration/prototype/with/branding.js b/test/built-ins/Temporal/Duration/prototype/with/branding.js index 2bc9af85bf8..b04b2fefd60 100644 --- a/test/built-ins/Temporal/Duration/prototype/with/branding.js +++ b/test/built-ins/Temporal/Duration/prototype/with/branding.js @@ -11,12 +11,14 @@ const with_ = Temporal.Duration.prototype.with; assert.sameValue(typeof with_, "function"); -assert.throws(TypeError, () => with_.call(undefined), "undefined"); -assert.throws(TypeError, () => with_.call(null), "null"); -assert.throws(TypeError, () => with_.call(true), "true"); -assert.throws(TypeError, () => with_.call(""), "empty string"); -assert.throws(TypeError, () => with_.call(Symbol()), "symbol"); -assert.throws(TypeError, () => with_.call(1), "1"); -assert.throws(TypeError, () => with_.call({}), "plain object"); -assert.throws(TypeError, () => with_.call(Temporal.Duration), "Temporal.Duration"); -assert.throws(TypeError, () => with_.call(Temporal.Duration.prototype), "Temporal.Duration.prototype"); +const arg = { years: 3 }; + +assert.throws(TypeError, () => with_.call(undefined, arg), "undefined"); +assert.throws(TypeError, () => with_.call(null, arg), "null"); +assert.throws(TypeError, () => with_.call(true, arg), "true"); +assert.throws(TypeError, () => with_.call("", arg), "empty string"); +assert.throws(TypeError, () => with_.call(Symbol(), arg), "symbol"); +assert.throws(TypeError, () => with_.call(1, arg), "1"); +assert.throws(TypeError, () => with_.call({}, arg), "plain object"); +assert.throws(TypeError, () => with_.call(Temporal.Duration, arg), "Temporal.Duration"); +assert.throws(TypeError, () => with_.call(Temporal.Duration.prototype, arg), "Temporal.Duration.prototype"); diff --git a/test/built-ins/Temporal/Duration/prototype/with/partial-positive.js b/test/built-ins/Temporal/Duration/prototype/with/partial-positive.js new file mode 100644 index 00000000000..b1425de497f --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/partial-positive.js @@ -0,0 +1,86 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: > + Returns a correctly merged object when the argument replaces only some of the + fields with positive values. +info: | + 1. Let duration be the this value. + 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + 3. Let temporalDurationLike be ? ToPartialDuration(temporalDurationLike). + 4. If temporalDurationLike.[[Years]] is not undefined, then + a. Let years be temporalDurationLike.[[Years]]. + 5. Else, + a. Let years be duration.[[Years]]. + 6. If temporalDurationLike.[[Months]] is not undefined, then + a. Let months be temporalDurationLike.[[Months]]. + 7. Else, + a. Let months be duration.[[Months]]. + 8. If temporalDurationLike.[[Weeks]] is not undefined, then + a. Let weeks be temporalDurationLike.[[Weeks]]. + 9. Else, + a. Let weeks be duration.[[Weeks]]. + 10. If temporalDurationLike.[[Days]] is not undefined, then + a. Let days be temporalDurationLike.[[Days]]. + 11. Else, + a. Let days be duration.[[Days]]. + 12. If temporalDurationLike.[[Hours]] is not undefined, then + a. Let hours be temporalDurationLike.[[Hours]]. + 13. Else, + a. Let hours be duration.[[Hours]]. + 14. If temporalDurationLike.[[Minutes]] is not undefined, then + a. Let minutes be temporalDurationLike.[[Minutes]]. + 15. Else, + a. Let minutes be duration.[[Minutes]]. + 16. If temporalDurationLike.[[Seconds]] is not undefined, then + a. Let seconds be temporalDurationLike.[[Seconds]]. + 17. Else, + a. Let seconds be duration.[[Seconds]]. + 18. If temporalDurationLike.[[Milliseconds]] is not undefined, then + a. Let milliseconds be temporalDurationLike.[[Milliseconds]]. + 19. Else, + a. Let milliseconds be duration.[[Milliseconds]]. + 20. If temporalDurationLike.[[Microseconds]] is not undefined, then + a. Let microseconds be temporalDurationLike.[[Microseconds]]. + 21. Else, + a. Let microseconds be duration.[[Microseconds]]. + 22. If temporalDurationLike.[[Nanoseconds]] is not undefined, then + a. Let nanoseconds be temporalDurationLike.[[Nanoseconds]]. + 23. Else, + a. Let nanoseconds be duration.[[Nanoseconds]]. + 24. Return ? CreateTemporalDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const durationlike1 = { years: 9, hours: 5 }; +const durationlike2 = { months: 8, minutes: 4 }; +const durationlike3 = { weeks: 7, seconds: 3 }; +const durationlike4 = { days: 6, milliseconds: 2 }; +const durationlike5 = { microseconds: 987, nanoseconds: 123 }; + +const d1 = new Temporal.Duration(); +TemporalHelpers.assertDuration( + d1.with(durationlike1), 9, 0, 0, 0, 5, 0, 0, 0, 0, 0, "replace all zeroes with years and hours"); +TemporalHelpers.assertDuration( + d1.with(durationlike2), 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, "replace all zeroes wtih months and minutes"); +TemporalHelpers.assertDuration( + d1.with(durationlike3), 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, "replace all zeroes with weeks and seconds"); +TemporalHelpers.assertDuration( + d1.with(durationlike4), 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, "replace all zeroes with days and milliseconds"); +TemporalHelpers.assertDuration( + d1.with(durationlike5), 0, 0, 0, 0, 0, 0, 0, 0, 987, 123, "replace all zeroes with microseconds and nanoseconds"); + +const d2 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +TemporalHelpers.assertDuration( + d2.with(durationlike1), 9, 2, 3, 4, 5, 6, 7, 8, 9, 10, "replace all positive with years and hours"); +TemporalHelpers.assertDuration( + d2.with(durationlike2), 1, 8, 3, 4, 5, 4, 7, 8, 9, 10, "replace all positive with months and minutes"); +TemporalHelpers.assertDuration( + d2.with(durationlike3), 1, 2, 7, 4, 5, 6, 3, 8, 9, 10, "replace all positive with weeks and seconds"); +TemporalHelpers.assertDuration( + d2.with(durationlike4), 1, 2, 3, 6, 5, 6, 7, 2, 9, 10, "replace all positive with days and milliseconds"); +TemporalHelpers.assertDuration( + d2.with(durationlike5), 1, 2, 3, 4, 5, 6, 7, 8, 987, 123, "replace all positive with microseconds and nanoseconds"); diff --git a/test/built-ins/Temporal/Duration/prototype/with/sign-conflict-throws-rangeerror.js b/test/built-ins/Temporal/Duration/prototype/with/sign-conflict-throws-rangeerror.js new file mode 100644 index 00000000000..239951b34d1 --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/with/sign-conflict-throws-rangeerror.js @@ -0,0 +1,28 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.duration.prototype.with +description: Throw RangeError if the resulting duration has mixed signs +info: | + 24. Return ? CreateTemporalDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). +features: [Temporal] +---*/ + +const d1 = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +const d2 = new Temporal.Duration(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10); +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +fields.forEach((field) => { + assert.throws( + RangeError, + () => d1.with({ [field]: -1 }), + `sign in argument { ${field}: -1 } conflicting with sign of duration should throw RangeError` + ); + + assert.throws( + RangeError, + () => d2.with({ [field]: 1 }), + `sign in argument { ${field}: 1 } conflicting with sign of duration should throw RangeError` + ); +}); diff --git a/test/built-ins/Temporal/Instant/prototype/round/options-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/round/options-wrong-type.js index 51cba2ff1a1..0cd3a0a985e 100644 --- a/test/built-ins/Temporal/Instant/prototype/round/options-wrong-type.js +++ b/test/built-ins/Temporal/Instant/prototype/round/options-wrong-type.js @@ -1,13 +1,13 @@ -// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// Copyright (C) 2022 Igalia, S.L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- esid: sec-temporal.instant.prototype.round -description: TypeError thrown when options argument is missing or a primitive -features: [Symbol, Temporal] +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] ---*/ -const values = [ +const badOptions = [ undefined, null, true, @@ -17,7 +17,8 @@ const values = [ ]; const instance = new Temporal.Instant(0n); -assert.throws(TypeError, () => instance.round(), "missing argument"); -for (const value of values) { - assert.throws(TypeError, () => instance.round(value), `argument ${String(value)}`); -} +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Instant/prototype/round/rounding-direction.js b/test/built-ins/Temporal/Instant/prototype/round/rounding-direction.js new file mode 100644 index 00000000000..88a6abba4c2 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/round/rounding-direction.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.round +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.Instant(-65_261_246_399_500_000_000n); // -000099-12-15T12:00:00.5Z +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "floor" }).epochNanoseconds, + -65_261_246_400_000_000_000n, // -000099-12-15T12:00:00Z + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode floor)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "trunc" }).epochNanoseconds, + -65_261_246_400_000_000_000n, // -000099-12-15T12:00:00Z + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "ceil" }).epochNanoseconds, + -65_261_246_399_000_000_000n, // -000099-12-15T12:00:01Z + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "halfExpand" }).epochNanoseconds, + -65_261_246_399_000_000_000n, // -000099-12-15T12:00:01Z + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/Instant/prototype/round/smallestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/round/smallestunit-invalid-string.js index 298c3ce64d6..37560379091 100644 --- a/test/built-ins/Temporal/Instant/prototype/round/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/round/smallestunit-invalid-string.js @@ -8,4 +8,28 @@ features: [Temporal] ---*/ const instant = new Temporal.Instant(1_000_000_000_123_987_500n); -assert.throws(RangeError, () => instant.round({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => instant.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/Instant/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/since/largestunit-invalid-string.js index 57aa9977ef2..48befae1256 100644 --- a/test/built-ins/Temporal/Instant/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.Instant(1_000_000_000_000_000_000n); const later = new Temporal.Instant(1_000_090_061_987_654_321n); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/Instant/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..52978927974 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Instant(0n); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.Instant(3600_000_000_000n), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Instant/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/since/smallestunit-invalid-string.js index 0e91f3e745d..25f795a89ae 100644 --- a/test/built-ins/Temporal/Instant/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.Instant(1_000_000_000_000_000_000n); const later = new Temporal.Instant(1_000_090_061_987_654_321n); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/Instant/prototype/toJSON/year-format.js b/test/built-ins/Temporal/Instant/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..01ffe822c86 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toJSON/year-format.js @@ -0,0 +1,53 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +function epochNsInYear(year) { + // Return an epoch nanoseconds value near the middle of the given year + const avgNsPerYear = 31_556_952_000_000_000n; + return (year - 1970n) * avgNsPerYear + (avgNsPerYear / 2n); +} + +let instance = new Temporal.Instant(epochNsInYear(-100000n)); +assert.sameValue(instance.toJSON(), "-100000-07-01T21:30:36Z", "large negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-10000n)); +assert.sameValue(instance.toJSON(), "-010000-07-01T21:30:36Z", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-9999n)); +assert.sameValue(instance.toJSON(), "-009999-07-02T03:19:48Z", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-1000n)); +assert.sameValue(instance.toJSON(), "-001000-07-02T09:30:36Z", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-999n)); +assert.sameValue(instance.toJSON(), "-000999-07-02T15:19:48Z", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-1n)); +assert.sameValue(instance.toJSON(), "-000001-07-02T15:41:24Z", "year -1 formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(0n)); +assert.sameValue(instance.toJSON(), "0000-07-01T21:30:36Z", "year 0 formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(1n)); +assert.sameValue(instance.toJSON(), "0001-07-02T03:19:48Z", "year 1 formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(999n)); +assert.sameValue(instance.toJSON(), "0999-07-02T03:41:24Z", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(1000n)); +assert.sameValue(instance.toJSON(), "1000-07-02T09:30:36Z", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(9999n)); +assert.sameValue(instance.toJSON(), "9999-07-02T15:41:24Z", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(10000n)); +assert.sameValue(instance.toJSON(), "+010000-07-01T21:30:36Z", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(100000n)); +assert.sameValue(instance.toJSON(), "+100000-07-01T21:30:36Z", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-auto.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-auto.js new file mode 100644 index 00000000000..5e37b7ffd5c --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-auto.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: auto value for fractionalSecondDigits option +features: [BigInt, Temporal] +---*/ + +const zeroSeconds = new Temporal.Instant(0n); +const wholeSeconds = new Temporal.Instant(30_000_000_000n); +const subSeconds = new Temporal.Instant(30_123_400_000n); + +const tests = [ + [zeroSeconds, "1970-01-01T00:00:00Z"], + [wholeSeconds, "1970-01-01T00:00:30Z"], + [subSeconds, "1970-01-01T00:00:30.1234Z"], +]; + +for (const [instant, expected] of tests) { + assert.sameValue(instant.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(instant.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js index f75db5a7ffc..0a1cc3e3cb8 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js @@ -10,10 +10,13 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.instant.prototype.tostring step 6: - 6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 6. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const instant = new Temporal.Instant(1_000_000_000_987_650_000n); -assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: "other string" })); +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js index beb567b6889..1a3479b5cc6 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js @@ -10,7 +10,7 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.instant.prototype.tostring step 6: - 6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 6. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-number.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-number.js new file mode 100644 index 00000000000..e6ba9634053 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-number.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: Number for fractionalSecondDigits option +features: [BigInt, Temporal] +---*/ + +const zeroSeconds = new Temporal.Instant(0n); +const wholeSeconds = new Temporal.Instant(30_000_000_000n); +const subSeconds = new Temporal.Instant(30_123_400_000n); + +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "1970-01-01T00:00:30Z", + "truncates 4 decimal places to 0"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:00.00Z", + "pads zero seconds to 2 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:30.00Z", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:30.12Z", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "1970-01-01T00:00:30.123Z", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "1970-01-01T00:00:30.123400Z", + "pads 4 decimal places to 6"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:00.0000000Z", + "pads zero seconds to 7 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:30.0000000Z", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:30.1234000Z", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "1970-01-01T00:00:30.123400000Z", + "pads 4 decimal places to 9"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js index 4506d3ef215..a634aee8903 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js @@ -10,13 +10,17 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.instant.prototype.tostring step 6: - 6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 6. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const instant = new Temporal.Instant(1_000_000_000_987_650_000n); -assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -1 })); -assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 10 })); -assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -Infinity })); -assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: Infinity })); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js index 7bed467685f..be0fbf77e38 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js @@ -8,18 +8,31 @@ info: | sec-getoption step 3: 3. If _value_ is *undefined*, return _fallback_. sec-getstringornumberoption step 2: - 2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_). + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.instant.prototype.tostring step 6: - 6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 6. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ -const instant = new Temporal.Instant(1_000_000_000_987_650_000n); +const zeroSeconds = new Temporal.Instant(0n); +const wholeSeconds = new Temporal.Instant(30_000_000_000n); +const subSeconds = new Temporal.Instant(30_123_400_000n); -const explicit = instant.toString({ fractionalSecondDigits: undefined }); -assert.sameValue(explicit, "2001-09-09T01:46:40.98765Z", "default fractionalSecondDigits is auto"); +const tests = [ + [zeroSeconds, "1970-01-01T00:00:00Z"], + [wholeSeconds, "1970-01-01T00:00:30Z"], + [subSeconds, "1970-01-01T00:00:30.1234Z"], +]; -const implicit = instant.toString({}); -assert.sameValue(implicit, "2001-09-09T01:46:40.98765Z", "default fractionalSecondDigits is auto"); +for (const [instant, expected] of tests) { + const explicit = instant.toString({ fractionalSecondDigits: undefined }); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); + + const implicit = instant.toString({}); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); + + const lambda = instant.toString(() => {}); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js index 26eb23a3037..419b4a86d16 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js @@ -22,4 +22,26 @@ features: [Temporal] ---*/ const instant = new Temporal.Instant(1_000_000_000_987_650_000n); -TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(instant); + +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => instant.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = instant.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "2001-09-09T01:46:40.98765Z", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..4da3c9ebbc1 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Instant(0n); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Instant/prototype/toString/rounding-cross-midnight.js b/test/built-ins/Temporal/Instant/prototype/toString/rounding-cross-midnight.js new file mode 100644 index 00000000000..923671d4898 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/rounding-cross-midnight.js @@ -0,0 +1,13 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: Rounding can cross midnight +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(946_684_799_999_999_999n); // one nanosecond before 2000-01-01T00:00:00 +for (const roundingMode of ["ceil", "halfExpand"]) { + assert.sameValue(instant.toString({ fractionalSecondDigits: 8, roundingMode }), "2000-01-01T00:00:00.00000000Z"); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/rounding-direction.js b/test/built-ins/Temporal/Instant/prototype/toString/rounding-direction.js new file mode 100644 index 00000000000..f5185d9331d --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/rounding-direction.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.Instant(-65_261_246_399_500_000_000n); // -000099-12-15T12:00:00.5Z +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "floor" }), + "-000099-12-15T12:00:00Z", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "trunc" }), + "-000099-12-15T12:00:00Z", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "ceil" }), + "-000099-12-15T12:00:01Z", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "halfExpand" }), + "-000099-12-15T12:00:01Z", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-ceil.js b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-ceil.js new file mode 100644 index 00000000000..f4cd9f0a802 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-ceil.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: ceil value for roundingMode option +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(1_000_000_000_123_987_500n); + +const result1 = instant.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123988Z", + "roundingMode is ceil (with 6 digits from smallestUnit)"); + +const result2 = instant.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123988Z", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); + +const result3 = instant.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "2001-09-09T01:46:40.124Z", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = instant.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "2001-09-09T01:46:40.124Z", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = instant.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "2001-09-09T01:46:41Z", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = instant.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "2001-09-09T01:46:41Z", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); + +const result7 = instant.toString({ smallestUnit: "minute", roundingMode: "ceil" }); +assert.sameValue(result7, "2001-09-09T01:47Z", "roundingMode is ceil (round to minute)"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-floor.js b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-floor.js new file mode 100644 index 00000000000..d50326568b0 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-floor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: floor value for roundingMode option +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(1_000_000_000_123_987_500n); + +const result1 = instant.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123987Z", + "roundingMode is floor (with 6 digits from smallestUnit)"); + +const result2 = instant.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123987Z", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); + +const result3 = instant.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "2001-09-09T01:46:40.123Z", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = instant.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "2001-09-09T01:46:40.123Z", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = instant.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "2001-09-09T01:46:40Z", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = instant.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "2001-09-09T01:46:40Z", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); + +const result7 = instant.toString({ smallestUnit: "minute", roundingMode: "floor" }); +assert.sameValue(result7, "2001-09-09T01:46Z", "roundingMode is floor (round to minute)"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-halfExpand.js b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-halfExpand.js new file mode 100644 index 00000000000..7b8aa7e8fa7 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-halfExpand.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: halfExpand value for roundingMode option +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(1_000_000_000_123_987_500n); + +const result1 = instant.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123988Z", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); + +const result2 = instant.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123988Z", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); + +const result3 = instant.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "2001-09-09T01:46:40.124Z", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = instant.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "2001-09-09T01:46:40.124Z", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = instant.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "2001-09-09T01:46:40Z", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = instant.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "2001-09-09T01:46:40Z", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); + +const result7 = instant.toString({ smallestUnit: "minute", roundingMode: "halfExpand" }); +assert.sameValue(result7, "2001-09-09T01:47Z", "roundingMode is halfExpand (round to minute)"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-trunc.js b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-trunc.js new file mode 100644 index 00000000000..944c479c161 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/roundingmode-trunc.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: trunc value for roundingMode option +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(1_000_000_000_123_987_500n); + +const result1 = instant.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123987Z", + "roundingMode is trunc (with 6 digits from smallestUnit)"); + +const result2 = instant.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123987Z", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = instant.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "2001-09-09T01:46:40.123Z", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = instant.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "2001-09-09T01:46:40.123Z", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = instant.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "2001-09-09T01:46:40Z", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = instant.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "2001-09-09T01:46:40Z", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = instant.toString({ smallestUnit: "minute", roundingMode: "trunc" }); +assert.sameValue(result7, "2001-09-09T01:46Z", "roundingMode is trunc (round to minute)"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-fractionalseconddigits.js b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-fractionalseconddigits.js new file mode 100644 index 00000000000..73d8f9aaf90 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-fractionalseconddigits.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: fractionalSecondDigits option is not used with smallestUnit present +features: [Temporal] +---*/ + +const instant = new Temporal.Instant(56_789_999_999n); +const tests = [ + ["minute", "1970-01-01T00:00Z"], + ["second", "1970-01-01T00:00:56Z"], + ["millisecond", "1970-01-01T00:00:56.789Z"], + ["microsecond", "1970-01-01T00:00:56.789999Z"], + ["nanosecond", "1970-01-01T00:00:56.789999999Z"], +]; + +for (const [smallestUnit, expected] of tests) { + const string = instant.toString({ + smallestUnit, + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } + }); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); +} + +assert.throws(RangeError, () => instant.toString({ + smallestUnit: "hour", + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-invalid-string.js index f6ba6e30cc6..10b0b72baab 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-invalid-string.js @@ -8,4 +8,30 @@ features: [Temporal] ---*/ const instant = new Temporal.Instant(1_000_000_000_123_987_500n); -assert.throws(RangeError, () => instant.toString({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => instant.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js index 191eec97ed4..e1c53c93eb6 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js @@ -9,11 +9,36 @@ features: [Temporal] const instant = new Temporal.Instant(1_000_000_000_123_456_789n); -assert.sameValue(instant.toString({ smallestUnit: "minute" }), "2001-09-09T01:46Z"); -assert.sameValue(instant.toString({ smallestUnit: "second" }), "2001-09-09T01:46:40Z"); -assert.sameValue(instant.toString({ smallestUnit: "millisecond" }), "2001-09-09T01:46:40.123Z"); -assert.sameValue(instant.toString({ smallestUnit: "microsecond" }), "2001-09-09T01:46:40.123456Z"); -assert.sameValue(instant.toString({ smallestUnit: "nanosecond" }), "2001-09-09T01:46:40.123456789Z"); +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + instant, + [ + ["minute", "2001-09-09T01:46Z"], + ["second", "2001-09-09T01:46:40Z"], + ["millisecond", "2001-09-09T01:46:40.123Z"], + ["microsecond", "2001-09-09T01:46:40.123456Z"], + ["nanosecond", "2001-09-09T01:46:40.123456789Z"], + ], + "subseconds toString" +); + +test( + new Temporal.Instant(999_999_960_000_000_000n), + [ + ["minute", "2001-09-09T01:46Z"], + ["second", "2001-09-09T01:46:00Z"], + ["millisecond", "2001-09-09T01:46:00.000Z"], + ["microsecond", "2001-09-09T01:46:00.000000Z"], + ["nanosecond", "2001-09-09T01:46:00.000000000Z"], + ], + "whole minutes toString" +); const notValid = [ "era", @@ -25,5 +50,6 @@ const notValid = [ ]; notValid.forEach((smallestUnit) => { - assert.throws(RangeError, () => instant.toString({ smallestUnit }), smallestUnit); + assert.throws(RangeError, () => instant.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); }); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/year-format.js b/test/built-ins/Temporal/Instant/prototype/toString/year-format.js new file mode 100644 index 00000000000..195115a0c3f --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/toString/year-format.js @@ -0,0 +1,53 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +function epochNsInYear(year) { + // Return an epoch nanoseconds value near the middle of the given year + const avgNsPerYear = 31_556_952_000_000_000n; + return (year - 1970n) * avgNsPerYear + (avgNsPerYear / 2n); +} + +let instance = new Temporal.Instant(epochNsInYear(-100000n)); +assert.sameValue(instance.toString(), "-100000-07-01T21:30:36Z", "large negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-10000n)); +assert.sameValue(instance.toString(), "-010000-07-01T21:30:36Z", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-9999n)); +assert.sameValue(instance.toString(), "-009999-07-02T03:19:48Z", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-1000n)); +assert.sameValue(instance.toString(), "-001000-07-02T09:30:36Z", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-999n)); +assert.sameValue(instance.toString(), "-000999-07-02T15:19:48Z", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(-1n)); +assert.sameValue(instance.toString(), "-000001-07-02T15:41:24Z", "year -1 formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(0n)); +assert.sameValue(instance.toString(), "0000-07-01T21:30:36Z", "year 0 formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(1n)); +assert.sameValue(instance.toString(), "0001-07-02T03:19:48Z", "year 1 formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(999n)); +assert.sameValue(instance.toString(), "0999-07-02T03:41:24Z", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(1000n)); +assert.sameValue(instance.toString(), "1000-07-02T09:30:36Z", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(9999n)); +assert.sameValue(instance.toString(), "9999-07-02T15:41:24Z", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.Instant(epochNsInYear(10000n)); +assert.sameValue(instance.toString(), "+010000-07-01T21:30:36Z", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.Instant(epochNsInYear(100000n)); +assert.sameValue(instance.toString(), "+100000-07-01T21:30:36Z", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/Instant/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/until/largestunit-invalid-string.js index 9d288cd6d6d..0837ea1dbb1 100644 --- a/test/built-ins/Temporal/Instant/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.Instant(1_000_000_000_000_000_000n); const later = new Temporal.Instant(1_000_090_061_987_654_321n); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/Instant/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..c30976350c2 --- /dev/null +++ b/test/built-ins/Temporal/Instant/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.Instant(0n); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.Instant(3600_000_000_000n), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/Instant/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/until/smallestunit-invalid-string.js index 145ea2b808e..146b390014e 100644 --- a/test/built-ins/Temporal/Instant/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.Instant(1_000_000_000_000_000_000n); const later = new Temporal.Instant(1_000_090_061_987_654_321n); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js new file mode 100644 index 00000000000..8c0480b1d1a --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js @@ -0,0 +1,66 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.compare +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a %%%conversion_target%%% +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const other = new Temporal.PlainDate(2020, 1, 1); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(arg, other), + `"${arg}" should not be a valid ISO string for a PlainDate (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(other, arg), + `"${arg}" should not be a valid ISO string for a PlainDate (second argument)` + ); +} diff --git a/test/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..e874d00f7cc --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.compare +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +Temporal.PlainDate.compare({ year: 2000, month: 5, day: 2, calendar }, { year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); diff --git a/test/built-ins/Temporal/PlainDate/from/argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/from/argument-string-invalid.js index f0dee3ade9c..b59bdf35d49 100644 --- a/test/built-ins/Temporal/PlainDate/from/argument-string-invalid.js +++ b/test/built-ins/Temporal/PlainDate/from/argument-string-invalid.js @@ -1,30 +1,60 @@ -// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// Copyright (C) 2022 Igalia S.L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- esid: sec-temporal.plaindate.from -description: overflow property is extracted with ISO-invalid string argument. -info: | - 1. Perform ? ToTemporalOverflow(_options_). - - 1. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception. -includes: [compareArray.js, temporalHelpers.js] -features: [Temporal] +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] ---*/ -const expected = [ - "get overflow", - "get overflow.toString", - "call overflow.toString", +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", ]; - -let actual = []; -const object = { - get overflow() { - actual.push("get overflow"); - return TemporalHelpers.toPrimitiveObserver(actual, "constrain", "overflow"); - } -}; - -assert.throws(RangeError, () => Temporal.PlainDate.from("2020-13-34", object)); -assert.compareArray(actual, expected); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js new file mode 100644 index 00000000000..f0dee3ade9c --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js @@ -0,0 +1,30 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.from +description: overflow property is extracted with ISO-invalid string argument. +info: | + 1. Perform ? ToTemporalOverflow(_options_). + + 1. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get overflow", + "get overflow.toString", + "call overflow.toString", +]; + +let actual = []; +const object = { + get overflow() { + actual.push("get overflow"); + return TemporalHelpers.toPrimitiveObserver(actual, "constrain", "overflow"); + } +}; + +assert.throws(RangeError, () => Temporal.PlainDate.from("2020-13-34", object)); +assert.compareArray(actual, expected); diff --git a/test/built-ins/Temporal/PlainDate/from/argument-string-overflow.js b/test/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string.js similarity index 100% rename from test/built-ins/Temporal/PlainDate/from/argument-string-overflow.js rename to test/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string.js diff --git a/test/built-ins/Temporal/PlainDate/from/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/from/options-wrong-type.js new file mode 100644 index 00000000000..73408176606 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainDate.from({ year: 1976, month: 11, day: 18 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js index f04f77f745b..27e499961c5 100644 --- a/test/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js @@ -34,8 +34,14 @@ const invalidOverflow = [ "CONSTRAIN", "constra\u0131n", ]; -validItems.forEach((item) => { - invalidOverflow.forEach((overflow) => { - assert.throws(RangeError, () => Temporal.PlainDate.from(item, { overflow })); - }); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const item of validItems) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(item, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/PlainDate/prototype/add/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/add/options-wrong-type.js new file mode 100644 index 00000000000..e33a0a90c01 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/add/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js index 66282d2a6c3..6c7b65fd879 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js @@ -18,6 +18,12 @@ features: [Temporal] const date = new Temporal.PlainDate(2000, 5, 2); const duration = new Temporal.Duration(3, 3, 0, 3); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => date.add(duration, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.add(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js new file mode 100644 index 00000000000..ca71e4016a9 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.equals +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.equals(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainDate/prototype/equals/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/prototype/equals/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..5de98aa4001 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/equals/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.equals +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.equals({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js new file mode 100644 index 00000000000..45e74d668a5 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.since +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.since(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..782f4823b18 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.since +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.since({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.js b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.js index dbeb5699d69..86fdee9d580 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.js @@ -10,10 +10,10 @@ features: [Temporal] const feb20 = Temporal.PlainDate.from("2020-02-01"); const feb21 = Temporal.PlainDate.from("2021-02-01"); -TemporalHelpers.assertDuration(feb21.since(feb20), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no options"); -TemporalHelpers.assertDuration(feb21.since(feb20, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "undefined options"); -TemporalHelpers.assertDuration(feb21.since(feb20, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no largestUnit"); -TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); -TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "days"); -TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "auto"); -TemporalHelpers.assertDuration(feb21.since(feb20, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); +TemporalHelpers.assertDuration(feb21.since(feb20), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no options"); +TemporalHelpers.assertDuration(feb21.since(feb20, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined options"); +TemporalHelpers.assertDuration(feb21.since(feb20, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "days"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "auto"); +TemporalHelpers.assertDuration(feb21.since(feb20, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js index c1d8068ee4e..b3623a502e7 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js @@ -17,10 +17,10 @@ const feb20 = Temporal.PlainDate.from("2020-02-01"); const feb21 = Temporal.PlainDate.from("2021-02-01"); TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "years" }), /* years = */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, years"); TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "months" }), 0, /* months = */ 12, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, months"); -TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, 0, "start of February, weeks"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, "start of February, weeks"); const lastFeb20 = Temporal.PlainDate.from("2020-02-29"); const lastFeb21 = Temporal.PlainDate.from("2021-02-28"); -TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "years" }), 0, /* months = */ 11, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, 0, "end of February, years"); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "years" }), 0, /* months = */ 11, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "end of February, years"); TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "months" }), 0, /* months = */ 11, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "end of February, months"); TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 1, 0, 0, 0, 0, 0, 0, "end of February, weeks"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js index 9b31fbaabcb..3b047aa86aa 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,30 @@ features: [Temporal] const earlier = new Temporal.PlainDate(2000, 5, 2); const later = new Temporal.PlainDate(2001, 6, 3); -const values = ["era", "eraYear", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..09905ce544b --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainDate(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js index b06b57f530a..2bc9968ca67 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,30 @@ features: [Temporal] const earlier = new Temporal.PlainDate(2000, 5, 2); const later = new Temporal.PlainDate(2001, 6, 3); -const values = ["era", "eraYear", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/subtract/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/subtract/options-wrong-type.js new file mode 100644 index 00000000000..66584a29d6a --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/subtract/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js index d3cbd6e8074..9387c6aff46 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js @@ -18,6 +18,12 @@ features: [Temporal] const date = new Temporal.PlainDate(2000, 5, 2); const duration = new Temporal.Duration(3, 3, 0, 3); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => date.subtract(duration, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.subtract(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/toJSON/year-format.js b/test/built-ins/Temporal/PlainDate/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..6f4864b4d62 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/toJSON/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDate(-100000, 12, 3); +assert.sameValue(instance.toJSON(), "-100000-12-03", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-10000, 4, 5); +assert.sameValue(instance.toJSON(), "-010000-04-05", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-9999, 6, 7); +assert.sameValue(instance.toJSON(), "-009999-06-07", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1000, 8, 9); +assert.sameValue(instance.toJSON(), "-001000-08-09", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-999, 10, 9); +assert.sameValue(instance.toJSON(), "-000999-10-09", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1, 8, 7); +assert.sameValue(instance.toJSON(), "-000001-08-07", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDate(0, 6, 5); +assert.sameValue(instance.toJSON(), "0000-06-05", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDate(1, 4, 3); +assert.sameValue(instance.toJSON(), "0001-04-03", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDate(999, 2, 10); +assert.sameValue(instance.toJSON(), "0999-02-10", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(1000, 1, 23); +assert.sameValue(instance.toJSON(), "1000-01-23", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(9999, 4, 5); +assert.sameValue(instance.toJSON(), "9999-04-05", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(10000, 6, 7); +assert.sameValue(instance.toJSON(), "+010000-06-07", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDate(100000, 8, 9); +assert.sameValue(instance.toJSON(), "+100000-08-09", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..681c5f08a64 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..6ef9df6b85f --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.toplainyearmonth +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.toPlainYearMonth(); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDate/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..af7518abb73 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/toString/year-format.js b/test/built-ins/Temporal/PlainDate/prototype/toString/year-format.js new file mode 100644 index 00000000000..9c1d121aab2 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/toString/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDate(-100000, 12, 3); +assert.sameValue(instance.toString(), "-100000-12-03", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-10000, 4, 5); +assert.sameValue(instance.toString(), "-010000-04-05", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-9999, 6, 7); +assert.sameValue(instance.toString(), "-009999-06-07", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1000, 8, 9); +assert.sameValue(instance.toString(), "-001000-08-09", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-999, 10, 9); +assert.sameValue(instance.toString(), "-000999-10-09", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1, 8, 7); +assert.sameValue(instance.toString(), "-000001-08-07", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDate(0, 6, 5); +assert.sameValue(instance.toString(), "0000-06-05", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDate(1, 4, 3); +assert.sameValue(instance.toString(), "0001-04-03", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDate(999, 2, 10); +assert.sameValue(instance.toString(), "0999-02-10", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(1000, 1, 23); +assert.sameValue(instance.toString(), "1000-01-23", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(9999, 4, 5); +assert.sameValue(instance.toString(), "9999-04-05", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(10000, 6, 7); +assert.sameValue(instance.toString(), "+010000-06-07", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDate(100000, 8, 9); +assert.sameValue(instance.toString(), "+100000-08-09", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js b/test/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js new file mode 100644 index 00000000000..4e59ac5e3f3 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.until +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.until(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..e55859f7278 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.until +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.until({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.js b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.js index ea3f6679570..63b7fd397e6 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.js @@ -10,10 +10,10 @@ features: [Temporal] const feb20 = Temporal.PlainDate.from("2020-02-01"); const feb21 = Temporal.PlainDate.from("2021-02-01"); -TemporalHelpers.assertDuration(feb20.until(feb21), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no options"); -TemporalHelpers.assertDuration(feb20.until(feb21, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "undefined options"); -TemporalHelpers.assertDuration(feb20.until(feb21, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no largestUnit"); -TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); -TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "days"); -TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "auto"); -TemporalHelpers.assertDuration(feb20.until(feb21, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); +TemporalHelpers.assertDuration(feb20.until(feb21), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no options"); +TemporalHelpers.assertDuration(feb20.until(feb21, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined options"); +TemporalHelpers.assertDuration(feb20.until(feb21, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "days"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "auto"); +TemporalHelpers.assertDuration(feb20.until(feb21, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js index 30c7ceec20c..30fd70ae2ae 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js @@ -17,7 +17,7 @@ const feb20 = Temporal.PlainDate.from("2020-02-01"); const feb21 = Temporal.PlainDate.from("2021-02-01"); TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "years" }), /* years = */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, years"); TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "months" }), 0, /* months = */ 12, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, months"); -TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, 0, "start of February, weeks"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, "start of February, weeks"); const lastFeb20 = Temporal.PlainDate.from("2020-02-29"); const lastFeb21 = Temporal.PlainDate.from("2021-02-28"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js index b06f5d6ed85..379dd28424d 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,30 @@ features: [Temporal] const earlier = new Temporal.PlainDate(2000, 5, 2); const later = new Temporal.PlainDate(2001, 6, 3); -const values = ["era", "eraYear", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..e93369500ed --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainDate(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js index 3eb01aaee89..8382c5c924c 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,30 @@ features: [Temporal] const earlier = new Temporal.PlainDate(2000, 5, 2); const later = new Temporal.PlainDate(2001, 6, 3); -const values = ["era", "eraYear", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/PlainDate/prototype/with/options-wrong-type.js new file mode 100644 index 00000000000..0fdb1c24e6d --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/with/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDate/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDate/prototype/with/overflow-invalid-string.js index d35f66be86b..acef874825b 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDate/prototype/with/overflow-invalid-string.js @@ -17,6 +17,12 @@ features: [Temporal] ---*/ const date = new Temporal.PlainDate(2000, 5, 2); -["", "CONSTRAIN", "balance", "other string"].forEach((overflow) => - assert.throws(RangeError, () => date.with({ month: 8 }, { overflow })) -); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.with({ month: 8 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/PlainDateTime/compare/basic.js b/test/built-ins/Temporal/PlainDateTime/compare/basic.js index a47e91cd628..17cd7104252 100644 --- a/test/built-ins/Temporal/PlainDateTime/compare/basic.js +++ b/test/built-ins/Temporal/PlainDateTime/compare/basic.js @@ -9,21 +9,14 @@ features: [Temporal] const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); const dt2 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt3 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt4 = new Temporal.PlainDateTime(2019, 10, 29, 15, 23, 30, 123, 456, 789); +const dt5 = new Temporal.PlainDateTime(1976, 11, 18, 10, 46, 38, 271, 986, 102); -assert.sameValue( - Temporal.PlainDateTime.compare(dt1, dt1), - 0, - "equal" -); +assert.sameValue(Temporal.PlainDateTime.compare(dt1, dt1), 0, "equal"); +assert.sameValue(Temporal.PlainDateTime.compare(dt1, dt2), -1, "smaller/larger"); +assert.sameValue(Temporal.PlainDateTime.compare(dt2, dt1), 1, "larger/smaller"); +assert.sameValue(Temporal.PlainDateTime.compare(dt2, dt3), 0, "equal different object"); +assert.sameValue(Temporal.PlainDateTime.compare(dt3, dt4), -1, "same date, earlier time"); +assert.sameValue(Temporal.PlainDateTime.compare(dt3, dt5), 1, "same time, later date"); -assert.sameValue( - Temporal.PlainDateTime.compare(dt1, dt2), - -1, - "smaller/larger" -); - -assert.sameValue( - Temporal.PlainDateTime.compare(dt2, dt1), - 1, - "larger/smaller" -); diff --git a/test/built-ins/Temporal/PlainDateTime/compare/calendar-ignored.js b/test/built-ins/Temporal/PlainDateTime/compare/calendar-ignored.js new file mode 100644 index 00000000000..9f197ae0a62 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/compare/calendar-ignored.js @@ -0,0 +1,19 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.compare +description: Calendar is not taken into account for the comparison. +features: [Temporal] +---*/ + +const calendar1 = { toString() { throw new Test262Error("should not call calendar1.toString") } }; +const calendar2 = { toString() { throw new Test262Error("should not call calendar2.toString") } }; +const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar1); +const dt2 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar1); +const dt3 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar1); +const dt4 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar2); + +assert.sameValue(Temporal.PlainDateTime.compare(dt1, dt2), -1, "smaller"); +assert.sameValue(Temporal.PlainDateTime.compare(dt2, dt3), 0, "equal with same calendar"); +assert.sameValue(Temporal.PlainDateTime.compare(dt2, dt4), 0, "equal with different calendar"); diff --git a/test/built-ins/Temporal/PlainDateTime/from/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/from/options-wrong-type.js new file mode 100644 index 00000000000..df34d81b64c --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainDateTime.from({ year: 1976, month: 11, day: 18 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/from/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/from/overflow-invalid-string.js index 41673499f72..1786ed59049 100644 --- a/test/built-ins/Temporal/PlainDateTime/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/from/overflow-invalid-string.js @@ -31,6 +31,14 @@ const validValues = [ { year: 2000, month: 5, day: 2, hour: 12 }, "2000-05-02T12:00", ]; -validValues.forEach((value) => { - assert.throws(RangeError, () => Temporal.PlainDateTime.from(value, { overflow: "other string" })); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const value of validValues) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainDateTime.from(value, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/add/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/add/options-wrong-type.js new file mode 100644 index 00000000000..68c33eb4970 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/add/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js index 40124a8f32d..6ce6ecc29de 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js @@ -21,11 +21,12 @@ features: [Temporal] const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); const duration = new Temporal.Duration(3, 3, 0, 3, 3); -const badOverflows = ['', 'CONSTRAIN', 'balance', "other string"]; -badOverflows.forEach((overflow) => { + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { assert.throws( RangeError, () => datetime.add({ months: 1 }, { overflow }), `invalid overflow ("${overflow}")` ); -}); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js index c83cffeef4e..72133b1e514 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js @@ -9,6 +9,12 @@ features: [Temporal] const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); const dt2 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt3 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt4 = new Temporal.PlainDateTime(2019, 10, 29, 15, 23, 30, 123, 456, 789); +const dt5 = new Temporal.PlainDateTime(1976, 11, 18, 10, 46, 38, 271, 986, 102); assert.sameValue(dt1.equals(dt1), true, "equal"); assert.sameValue(dt1.equals(dt2), false, "unequal"); +assert.sameValue(dt2.equals(dt3), true, "equal with different objects"); +assert.sameValue(dt2.equals(dt4), false, "same date, different time"); +assert.sameValue(dt2.equals(dt5), false, "same time, different date"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js b/test/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js new file mode 100644 index 00000000000..de8dfabf30e --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js @@ -0,0 +1,36 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Calendar is taken into account if the ISO data is equal +includes: [compareArray.js,temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const calendar1 = TemporalHelpers.toPrimitiveObserver(actual, "A", "calendar1"); +const calendar2 = TemporalHelpers.toPrimitiveObserver(actual, "A", "calendar2"); +const calendar3 = TemporalHelpers.toPrimitiveObserver(actual, "B", "calendar3"); +const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar1); +const dt1b = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar1); +const dt2 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar2); +const dt3 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar3); + +assert.sameValue(dt1.equals(dt1b), true, "same calendar object"); +assert.compareArray(actual, []); + +assert.sameValue(dt1.equals(dt2), true, "same calendar string"); +assert.compareArray(actual, ["get calendar1.toString", "call calendar1.toString", "get calendar2.toString", "call calendar2.toString"]); + +actual.splice(0, actual.length); // empty it for the next check +assert.sameValue(dt1.equals(dt3), false, "different calendar string"); +assert.compareArray(actual, ["get calendar1.toString", "call calendar1.toString", "get calendar3.toString", "call calendar3.toString"]); + +const calendar4 = { toString() { throw new Test262Error("should not call calendar4.toString") } }; +const calendar5 = { toString() { throw new Test262Error("should not call calendar5.toString") } }; +const dt4 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar4); +const dt5 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar4); +const dt6 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar5); +assert.sameValue(dt4.equals(dt5), false, "not equal same calendar"); +assert.sameValue(dt4.equals(dt6), false, "not equal different calendar"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/balance.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/balance.js new file mode 100644 index 00000000000..37a7947b6e3 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/balance.js @@ -0,0 +1,19 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Rounding balances to the next smallest unit +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 23, 59, 59, 999, 999, 999); + +["day", "hour", "minute", "second", "millisecond", "microsecond"].forEach((smallestUnit) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit }), + 1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0, + `balances to next ${smallestUnit}` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.js new file mode 100644 index 00000000000..eaf7bd764a6 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + undefined, + null, + true, + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.js new file mode 100644 index 00000000000..5e0e1eaeca4 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.js @@ -0,0 +1,31 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(-99, 12, 15, 12, 0, 0, 500); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "floor" }), + -99, 12, "M12", 15, 12, 0, 0, 0, 0, 0, + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode floor)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "trunc" }), + -99, 12, "M12", 15, 12, 0, 0, 0, 0, 0, + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "ceil" }), + -99, 12, "M12", 15, 12, 0, 1, 0, 0, 0, + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "halfExpand" }), + -99, 12, "M12", 15, 12, 0, 1, 0, 0, 0, + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.js new file mode 100644 index 00000000000..304046e331d --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.js @@ -0,0 +1,53 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Rounding increment should properly divide the relevant time unit +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +[1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit: "hour", roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid hour increments divide into 24 (rounding increment = ${roundingIncrement})`); +}); + +["minute", "second"].forEach((smallestUnit) => { + [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit, roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid ${smallestUnit} increments divide into 60 (rounding increment = ${roundingIncrement})` + ); + }); +}); + +["millisecond", "microsecond", "nanosecond"].forEach((smallestUnit) => { + [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit, roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid ${smallestUnit} increments divide into 1000 (rounding increment = ${roundingIncrement})`); + }); +}); + +const nextIncrements = { + "hour": 24, + "minute": 60, + "second": 60, + "millisecond": 1000, + "microsecond": 1000, + "nanosecond": 1000 +}; + +Object.entries(nextIncrements).forEach(([unit, next]) => { + assert.throws( + RangeError, + () => dt.round({ smallestUnit: unit, roundingIncrement: next }), + `throws on increments that are equal to the next highest (unit = ${unit}, increment = ${next})` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.js new file mode 100644 index 00000000000..82ab14b519c --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.js @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Throw exception if the rounding unit does not properly divide the relevant time unit +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); +const units = ["day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]; +units.forEach((unit) => { + assert.throws( + RangeError, + () => dt.round({ smallestUnit: unit, roundingIncrement: 29 }), + `throws on increments that do not divide evenly into the next highest (unit = ${unit})` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.js new file mode 100644 index 00000000000..71470b4bb9c --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.js @@ -0,0 +1,17 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: One day is a valid rounding increment +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "day", roundingIncrement: 1 }), + 1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0, + "1 day is a valid increment" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.js new file mode 100644 index 00000000000..d434095df9a --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Basic checks for rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "hour", roundingIncrement: 4 }), + 1976, 11, "M11", 18, 16, 0, 0, 0, 0, 0, + "rounds to an increment of hours" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "minute", roundingIncrement: 15 }), + 1976, 11, "M11", 18, 14, 30, 0, 0, 0, 0, + "rounds to an increment of minutes" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "second", roundingIncrement: 30 }), + 1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0, + "rounds to an increment of seconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "millisecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 120, 0, 0, + "rounds to an increment of milliseconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "microsecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 123, 460, 0, + "rounds to an increment of microseconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "nanosecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 123, 456, 790, + "rounds to an increment of nanoseconds" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil-basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil-basic.js new file mode 100644 index 00000000000..3e290c93178 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil-basic.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Basic checks for ceiling rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const incrementOneCeil = { + "day": [1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 15, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 24, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 31, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 124, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 457, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +Object.entries(incrementOneCeil).forEach(([smallestUnit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit, roundingMode: "ceil" }), + ...expected, + `rounds up to ${smallestUnit} (ceil)`, + undefined + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor-basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor-basic.js new file mode 100644 index 00000000000..8379b6100f8 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor-basic.js @@ -0,0 +1,29 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Basic checks for the floor rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const incrementOneFloor = { + "day": [1976, 11, "M11", 18, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 14, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 23, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +Object.entries(incrementOneFloor).forEach(([smallestUnit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit, roundingMode: "floor" }), + ...expected, + `rounds down to ${smallestUnit} (floor)` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-basic.js new file mode 100644 index 00000000000..5cb4275c3aa --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-basic.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Basic checks for half-expand rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const incrementOneNearest = { + "day": [1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 14, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 24, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 457, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +Object.entries(incrementOneNearest).forEach(([smallestUnit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit, roundingMode: "halfExpand" }), + ...expected, + `rounds to nearest ${smallestUnit} (half-expand)`, + undefined + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.js new file mode 100644 index 00000000000..47274d17459 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.js @@ -0,0 +1,31 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Half-expand is the default rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const units = { + "day": [1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 14, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 24, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 457, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +const expected = [1976, 11, "M11", 18, 0, 0, 0, 0, 0, 0]; + +Object.entries(units).forEach(([unit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: unit }), + ...expected, + `halfExpand is the default (smallest unit = ${unit}, rounding mode absent)` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc-basic.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc-basic.js new file mode 100644 index 00000000000..c8f0a278488 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc-basic.js @@ -0,0 +1,29 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Basic checks for truncation rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const incrementOneFloor = { + "day": [1976, 11, "M11", 18, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 14, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 23, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +Object.entries(incrementOneFloor).forEach(([smallestUnit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit, roundingMode: "trunc" }), + ...expected, + `truncates to ${smallestUnit}` + ); +}); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.js index e4d8f8503c1..f37ebe513cc 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.js @@ -8,4 +8,26 @@ features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); -assert.throws(RangeError, () => datetime.round({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.js new file mode 100644 index 00000000000..7f57d1d220a --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Throw if smallest unit is missing from argument +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + RangeError, + () => dt.round({ roundingIncrement: 1, roundingMode: "ceil" }), + "throws without required smallestUnit parameter" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.js new file mode 100644 index 00000000000..8ca7977a4e9 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Throw if argument is an empty plain object +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + RangeError, + () => dt.round({}), + "throws on empty object" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.js new file mode 100644 index 00000000000..d75fe284628 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Throw if no arguments at all are given +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => dt.round(), + "throws without any parameters" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-undefined.js new file mode 100644 index 00000000000..7b49ded8ddc --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/round/throws-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: Throw if sole argument is undefined +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => dt.round(undefined), + "throws without undefined as sole parameter" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-invalid-string.js index 1e8f9c80548..547667d70d3 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..ef026cc97c3 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainDateTime(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-invalid-string.js index a031b3f0fff..6fc80aa6a06 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js new file mode 100644 index 00000000000..38172d541d8 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js index 1e1f1761c81..c3e4b694f44 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js @@ -20,4 +20,11 @@ features: [Temporal] const date = new Temporal.PlainDateTime(2000, 5, 2, 12); const duration = new Temporal.Duration(3, 3, 0, 3, 3); -assert.throws(RangeError, () => date.subtract(duration, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.subtract(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toJSON/year-format.js b/test/built-ins/Temporal/PlainDateTime/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..261e9e6ec07 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toJSON/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDateTime(-100000, 12, 3, 4, 56, 7, 890); +assert.sameValue(instance.toJSON(), "-100000-12-03T04:56:07.89", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-10000, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toJSON(), "-010000-04-05T06:07:08.91", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-9999, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toJSON(), "-009999-06-07T08:09:10.987", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toJSON(), "-001000-08-09T10:09:08.765", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-999, 10, 9, 8, 7, 6, 543); +assert.sameValue(instance.toJSON(), "-000999-10-09T08:07:06.543", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1, 8, 7, 6, 54, 32, 100); +assert.sameValue(instance.toJSON(), "-000001-08-07T06:54:32.1", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(0, 6, 5, 4, 32, 10, 123); +assert.sameValue(instance.toJSON(), "0000-06-05T04:32:10.123", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1, 4, 3, 21, 0, 12, 345); +assert.sameValue(instance.toJSON(), "0001-04-03T21:00:12.345", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(999, 2, 10, 12, 34, 56, 789); +assert.sameValue(instance.toJSON(), "0999-02-10T12:34:56.789", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1000, 1, 23, 4, 56, 7, 890); +assert.sameValue(instance.toJSON(), "1000-01-23T04:56:07.89", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(9999, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toJSON(), "9999-04-05T06:07:08.91", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(10000, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toJSON(), "+010000-06-07T08:09:10.987", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(100000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toJSON(), "+100000-08-09T10:09:08.765", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..ee8746eb4b0 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..0a8deb44c9e --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplainyearmonth +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.toPlainYearMonth(); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.js new file mode 100644 index 00000000000..2567d042758 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: auto value for fractionalSecondDigits option +features: [Temporal] +---*/ + +const zeroSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); +const wholeSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30); +const subSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400); + +const tests = [ + [zeroSeconds, "1976-11-18T15:23:00"], + [wholeSeconds, "1976-11-18T15:23:30"], + [subSeconds, "1976-11-18T15:23:30.1234"], +]; + +for (const [datetime, expected] of tests) { + assert.sameValue(datetime.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(datetime.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js index 150d868658a..9fa496c2955 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -10,10 +10,13 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaindatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: "other string" })); +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js index 7de58c30b34..281d78f1abd 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -10,7 +10,7 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaindatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.js new file mode 100644 index 00000000000..843ef74f788 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Number for fractionalSecondDigits option +features: [Temporal] +---*/ + +const zeroSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); +const wholeSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30); +const subSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400); + +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "1976-11-18T15:23:30", + "truncates 4 decimal places to 0"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:00.00", + "pads zero seconds to 2 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:30.00", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:30.12", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "1976-11-18T15:23:30.123", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "1976-11-18T15:23:30.123400", + "pads 4 decimal places to 6"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:00.0000000", + "pads zero seconds to 7 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:30.0000000", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:30.1234000", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "1976-11-18T15:23:30.123400000", + "pads 4 decimal places to 9"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js index 948d707eb35..2ccbafaeec0 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -10,11 +10,17 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaindatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 })); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 })); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js index 12a0f77b873..d5ebb9c7e68 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js @@ -8,17 +8,31 @@ info: | sec-getoption step 3: 3. If _value_ is *undefined*, return _fallback_. sec-getstringornumberoption step 2: - 2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_). + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaindatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ -const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); +const zeroSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); +const wholeSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30); +const subSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400); -const explicit = datetime.toString({ fractionalSecondDigits: undefined }); -assert.sameValue(explicit, "2000-05-02T12:34:56.98765", "default fractionalSecondDigits is auto"); +const tests = [ + [zeroSeconds, "1976-11-18T15:23:00"], + [wholeSeconds, "1976-11-18T15:23:30"], + [subSeconds, "1976-11-18T15:23:30.1234"], +]; -// See options-undefined.js for {} +for (const [datetime, expected] of tests) { + const explicit = datetime.toString({ fractionalSecondDigits: undefined }); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); + + const implicit = datetime.toString({}); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); + + const lambda = datetime.toString(() => {}); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js index 9177b82196a..5ecaf7a6d1f 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -22,4 +22,26 @@ features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); -TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(datetime); + +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => datetime.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = datetime.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "2000-05-02T12:34:56.98765", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..b535b7e07c9 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.js new file mode 100644 index 00000000000..fe29b3b9c51 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.js @@ -0,0 +1,13 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Rounding can cross midnight +features: [Temporal] +---*/ + +const plainDateTime = new Temporal.PlainDateTime(1999, 12, 31, 23, 59, 59, 999, 999, 999); // one nanosecond before 2000-01-01T00:00:00 +for (const roundingMode of ["ceil", "halfExpand"]) { + assert.sameValue(plainDateTime.toString({ fractionalSecondDigits: 8, roundingMode }), "2000-01-01T00:00:00.00000000"); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.js new file mode 100644 index 00000000000..a4d7dec32d7 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(-99, 12, 15, 12, 0, 0, 500); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "floor" }), + "-000099-12-15T12:00:00", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "trunc" }), + "-000099-12-15T12:00:00", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "ceil" }), + "-000099-12-15T12:00:01", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "halfExpand" }), + "-000099-12-15T12:00:01", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.js new file mode 100644 index 00000000000..762b3a5cd33 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: ceil value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is ceil (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "2000-05-02T12:34:57", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "2000-05-02T12:34:57", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "ceil" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is ceil (round to minute)"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.js new file mode 100644 index 00000000000..4899d4cfa26 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: floor value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is floor (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "2000-05-02T12:34:56.123", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "2000-05-02T12:34:56.123", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "floor" }); +assert.sameValue(result7, "2000-05-02T12:34", "roundingMode is floor (round to minute)"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.js new file mode 100644 index 00000000000..9dcad461121 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: halfExpand value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfExpand" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfExpand (round to minute)"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.js new file mode 100644 index 00000000000..fa3e86319fc --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: trunc value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is trunc (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "2000-05-02T12:34:56.123", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "2000-05-02T12:34:56.123", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "trunc" }); +assert.sameValue(result7, "2000-05-02T12:34", "roundingMode is trunc (round to minute)"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.js new file mode 100644 index 00000000000..9918d045fc7 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: fractionalSecondDigits option is not used with smallestUnit present +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 12, 34, 56, 789, 999, 999); +const tests = [ + ["minute", "1976-11-18T12:34"], + ["second", "1976-11-18T12:34:56"], + ["millisecond", "1976-11-18T12:34:56.789"], + ["microsecond", "1976-11-18T12:34:56.789999"], + ["nanosecond", "1976-11-18T12:34:56.789999999"], +]; + +for (const [smallestUnit, expected] of tests) { + const string = datetime.toString({ + smallestUnit, + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } + }); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); +} + +assert.throws(RangeError, () => datetime.toString({ + smallestUnit: "hour", + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js index 1d1a6aaeca2..10e19530c1a 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js @@ -8,4 +8,30 @@ features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); -assert.throws(RangeError, () => datetime.toString({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js index 34928a9c6d9..6aff7a613b2 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js @@ -7,15 +7,41 @@ description: Valid units for the smallestUnit option features: [Temporal] ---*/ -const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 789, 999, 999); +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 456, 789); -assert.sameValue(datetime.toString({ smallestUnit: "minute" }), "2000-05-02T12:34"); -assert.sameValue(datetime.toString({ smallestUnit: "second" }), "2000-05-02T12:34:56"); -assert.sameValue(datetime.toString({ smallestUnit: "millisecond" }), "2000-05-02T12:34:56.789"); -assert.sameValue(datetime.toString({ smallestUnit: "microsecond" }), "2000-05-02T12:34:56.789999"); -assert.sameValue(datetime.toString({ smallestUnit: "nanosecond" }), "2000-05-02T12:34:56.789999999"); +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + datetime, + [ + ["minute", "2000-05-02T12:34"], + ["second", "2000-05-02T12:34:56"], + ["millisecond", "2000-05-02T12:34:56.123"], + ["microsecond", "2000-05-02T12:34:56.123456"], + ["nanosecond", "2000-05-02T12:34:56.123456789"], + ], + "subseconds toString" +); + +test( + new Temporal.PlainDateTime(2000, 5, 2, 12, 34), + [ + ["minute", "2000-05-02T12:34"], + ["second", "2000-05-02T12:34:00"], + ["millisecond", "2000-05-02T12:34:00.000"], + ["microsecond", "2000-05-02T12:34:00.000000"], + ["nanosecond", "2000-05-02T12:34:00.000000000"], + ], + "whole minutes toString" +); const notValid = [ + "era", "year", "month", "week", @@ -24,5 +50,6 @@ const notValid = [ ]; notValid.forEach((smallestUnit) => { - assert.throws(RangeError, () => datetime.toString({ smallestUnit }), smallestUnit); + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); }); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/year-format.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/year-format.js new file mode 100644 index 00000000000..d94ed41240f --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDateTime(-100000, 12, 3, 4, 56, 7, 890); +assert.sameValue(instance.toString(), "-100000-12-03T04:56:07.89", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-10000, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toString(), "-010000-04-05T06:07:08.91", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-9999, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toString(), "-009999-06-07T08:09:10.987", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toString(), "-001000-08-09T10:09:08.765", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-999, 10, 9, 8, 7, 6, 543); +assert.sameValue(instance.toString(), "-000999-10-09T08:07:06.543", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1, 8, 7, 6, 54, 32, 100); +assert.sameValue(instance.toString(), "-000001-08-07T06:54:32.1", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(0, 6, 5, 4, 32, 10, 123); +assert.sameValue(instance.toString(), "0000-06-05T04:32:10.123", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1, 4, 3, 21, 0, 12, 345); +assert.sameValue(instance.toString(), "0001-04-03T21:00:12.345", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(999, 2, 10, 12, 34, 56, 789); +assert.sameValue(instance.toString(), "0999-02-10T12:34:56.789", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1000, 1, 23, 4, 56, 7, 890); +assert.sameValue(instance.toString(), "1000-01-23T04:56:07.89", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(9999, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toString(), "9999-04-05T06:07:08.91", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(10000, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toString(), "+010000-06-07T08:09:10.987", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(100000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toString(), "+100000-08-09T10:09:08.765", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-wrong-type.js new file mode 100644 index 00000000000..c2a63768399 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tozoneddatetime +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toZonedDateTime("UTC", value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js index a3cf0f6aff3..aa7ca9a4c34 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..6b248d2e110 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainDateTime(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-invalid-string.js index 781434f7af6..d12bb40e32c 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.js new file mode 100644 index 00000000000..e13f520ea33 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.js @@ -0,0 +1,66 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Largest unit is respected +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "years" }), + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (years)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "months" }), + 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (months)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "weeks" }), + 0, 0, 52, 2, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (weeks)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "hours" }), + 0, 0, 0, 0, 8784, 0, 0, 0, 0, 0, + "can return lower or higher units (hours)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "minutes" }), + 0, 0, 0, 0, 0, 527040, 0, 0, 0, 0, + "can return lower or higher units (minutes)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "seconds" }), + 0, 0, 0, 0, 0, 0, 31622400, 0, 0, 0, + "can return lower or higher units (seconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "milliseconds" }), + 0, 0, 0, 0, 0, 0, 0, 31622400000, 0, 0, + "can return lower or higher units (milliseconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "microseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 31622400000000, 0, + "can return lower or higher units (microseconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "nanoseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 31622400000000000, + "can return lower or higher units (nanoseconds)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/argument-not-object.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/argument-not-object.js new file mode 100644 index 00000000000..65c474da538 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/argument-not-object.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: Non-object arguments throw. +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const args = [ + undefined, + null, + true, + "2020-01-12T10:20:30", + Symbol(), + 2020, + 2020n, +]; +for (const argument of args) { + assert.throws(TypeError, () => instance.with(argument), `Does not support ${typeof argument}`); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-options.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-options.js new file mode 100644 index 00000000000..935c1333d12 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-options.js @@ -0,0 +1,27 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: The options argument is passed through to Calendar#dateFromFields as-is. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const options = {}; +let calledDateFromFields = 0; +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateFromFields(fields, optionsArg) { + ++calledDateFromFields; + assert.sameValue(optionsArg, options, "should pass options object through"); + return super.dateFromFields(fields, optionsArg); + } +}; +const calendar = new Calendar(); +const plaindatetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const result = plaindatetime.with({ year: 2005 }, options); +TemporalHelpers.assertPlainDateTime(result, 2005, 5, "M05", 2, 12, 34, 56, 987, 654, 321); +assert.sameValue(calledDateFromFields, 1, "should have called overridden dateFromFields once"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.js new file mode 100644 index 00000000000..ae6887e31a1 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if a Temporal object with a calendar is supplied +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +const values = [ + Temporal.PlainDate.from("2022-04-12"), + Temporal.PlainDateTime.from("2022-04-12T15:19:45"), + Temporal.PlainMonthDay.from("04-12"), + Temporal.PlainTime.from("15:19:45"), + Temporal.PlainYearMonth.from("2022-04"), + Temporal.ZonedDateTime.from("2022-04-12T15:19:45[UTC]"), +]; + +for (const value of values) { + Object.defineProperty(value, "calendar", { + get() { throw new Test262Error("should not get calendar property") } + }); + Object.defineProperty(value, "timeZone", { + get() { throw new Test262Error("should not get timeZone property") } + }); + assert.throws( + TypeError, + () => datetime.with(value), + "throws with temporal object" + ); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/options-wrong-type.js new file mode 100644 index 00000000000..5c29d95e5e6 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js index be6e0797b83..ce2bc34b9c6 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js @@ -42,6 +42,12 @@ const expected = [ "get year", "get year.valueOf", "call year.valueOf", + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", ]; const actual = []; const fields = { @@ -70,7 +76,13 @@ const argument = new Proxy(fields, { return key in target; }, }); -const result = instance.with(argument); +const options = { + get overflow() { + actual.push("get options.overflow"); + return TemporalHelpers.toPrimitiveObserver(actual, "constrain", "options.overflow"); + } +}; +const result = instance.with(argument, options); TemporalHelpers.assertPlainDateTime(result, 1, 1, "M01", 1, 1, 1, 1, 1, 1, 1); assert.sameValue(result.calendar.id, "iso8601", "calendar result"); assert.compareArray(actual, expected, "order of operations"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/with/overflow-invalid-string.js index c23b9e9e970..4d3b05b0eac 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/with/overflow-invalid-string.js @@ -18,10 +18,12 @@ features: [Temporal] ---*/ const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); -const badOverflows = ["", "CONSTRAIN", "balance", "other string"]; -badOverflows.forEach((overflow) => { + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { assert.throws( RangeError, () => datetime.with({ minute: 45 }, { overflow }), - `invalid overflow string (${overflow})`); -}); + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insuffcient-data.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insufficient-data.js similarity index 100% rename from test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insuffcient-data.js rename to test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insufficient-data.js diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js new file mode 100644 index 00000000000..118282b48de --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js @@ -0,0 +1,38 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved with ISO PDT +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal = { + id: 'thisisnotiso', + era() { return "the era"; }, + eraYear() { return 1909; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; } +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0); +assert.sameValue(pdt.calendar.toString(), "iso8601", "PlainDateTime with ISO calendar"); +const pd = new Temporal.PlainDate(2010, 11, 12, cal); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is changed if receiver has ISO calendar (1)", + "the era", + 1909 +); + +assert.sameValue( + shifted.calendar, + cal, + "calendar is changed if receiver has ISO calendar (2)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js new file mode 100644 index 00000000000..28499059815 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js @@ -0,0 +1,40 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved when both calendars have the same id +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal1 = { + toString() { return "this is a string"; }, +}; +const cal2 = { + id: 'thisisnotiso', + era() { return "the era"; }, + eraYear() { return 1909; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; } +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal1); +const pd = new Temporal.PlainDate(2010, 11, 12, cal2); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is changed with same id (1)", + "the era", + 1909 +); + +assert.sameValue( + shifted.calendar, + cal2, + "calendar is changed with same id (2)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js new file mode 100644 index 00000000000..f963a3b61d2 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js @@ -0,0 +1,42 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved when both calendars are the same object +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +let calls = 0; +const cal = { + id: 'thisisnotiso', + era() { return "the era"; }, + eraYear() { return 1909; }, + toString() { + ++calls; + return "this is a string"; + }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; } +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); +const pd = new Temporal.PlainDate(2010, 11, 12, cal); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is unchanged with same calendars (1)", + "the era", + 1909 +); + +assert.sameValue( + shifted.calendar, + cal, + "calendar is unchanged with same calendars (2)" +); +assert.sameValue(calls, 0, "should not have called cal.toString()"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js new file mode 100644 index 00000000000..ad9f56f7bb4 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js @@ -0,0 +1,38 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: Original PDT calendar is preserved with ISO PlainDate +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal = { + id: 'thisisnotiso', + era() { return "the era"; }, + eraYear() { return 1909; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; } +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); +const pd = new Temporal.PlainDate(2010, 11, 12); +assert.sameValue(pd.calendar.toString(), "iso8601", "PlainDate with ISO calendar"); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is unchanged if input has ISO calendar (1)", + "the era", + 1909 +); + +assert.sameValue( + shifted.calendar, + cal, + "calendar is unchanged if input has ISO calendar (2)" +); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-invalid.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-invalid.js new file mode 100644 index 00000000000..a4f4d9350f0 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js index 84f0ac12ef4..d86925d1b80 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js @@ -3,7 +3,7 @@ /*--- esid: sec-temporal.plaindatetime.prototype.withplaindate -description: New calendar is preserved if original PDT has ISO calendar +description: Original PDT calendar is preserved with ISO string features: [Temporal] includes: [temporalHelpers.js] ---*/ diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..b67561e4829 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.withPlainDate({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainMonthDay/calendar-always.js b/test/built-ins/Temporal/PlainMonthDay/calendar-always.js new file mode 100644 index 00000000000..8b9d87ff0a0 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/calendar-always.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday +description: If calendar name is to be emitted, include additional reference info +features: [Temporal] +---*/ + +const pmd = new Temporal.PlainMonthDay(10, 31, "iso8601", 2019); + +assert.sameValue( + pmd.toString({ calendarName: 'always' }), + "2019-10-31[u-ca=iso8601]", + "emit year-month-day if calendarName = 'always' (four-argument constructor)" +); + +const anotherPMD = Temporal.PlainMonthDay.from("2019-10-31"); // 2019 will get dropped + +assert.sameValue( + anotherPMD.toString({ calendarName: 'always' }), + "1972-10-31[u-ca=iso8601]", + "emit fallback year if calendarName = 'always' (static from)" +); diff --git a/test/built-ins/Temporal/PlainMonthDay/from/calendar-monthdayfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainMonthDay/from/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..aa302eb1aba --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/from/calendar-monthdayfromfields-called-with-options-undefined.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.from +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +features: [Temporal] +---*/ + +const realMonthDayFromFields = Temporal.Calendar.prototype.monthDayFromFields; +let monthDayFromFieldsCallCount = 0; +Temporal.Calendar.prototype.monthDayFromFields = function (fields, options) { + monthDayFromFieldsCallCount++; + assert.sameValue(options, undefined, "monthDayFromFields shouldn't be called with options"); + return realMonthDayFromFields.call(this, fields, options); +} + +Temporal.PlainMonthDay.from("2000-05-02"); +assert.sameValue(monthDayFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.monthDayFromFields = realMonthDayFromFields; diff --git a/test/built-ins/Temporal/PlainMonthDay/from/options-wrong-type.js b/test/built-ins/Temporal/PlainMonthDay/from/options-wrong-type.js new file mode 100644 index 00000000000..c4c559bc6a8 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainMonthDay.from({ monthCode: "M12", day: 15 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainMonthDay/from/overflow-invalid-string.js b/test/built-ins/Temporal/PlainMonthDay/from/overflow-invalid-string.js index c2427006fdc..48ccf843643 100644 --- a/test/built-ins/Temporal/PlainMonthDay/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainMonthDay/from/overflow-invalid-string.js @@ -27,6 +27,14 @@ const validValues = [ { monthCode: "M05", day: 2 }, "05-02", ]; -validValues.forEach((value) => { - assert.throws(RangeError, () => Temporal.PlainMonthDay.from(value, { overflow: "other string" })); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const value of validValues) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainMonthDay.from(value, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/equals/calendar-monthdayfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainMonthDay/prototype/equals/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..649812219f9 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/equals/calendar-monthdayfromfields-called-with-options-undefined.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.prototype.equals +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainMonthDay(5, 2, calendar); +instance.equals({ monthCode: "M05", day: 3, calendar }); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); + +// Test again, but overriding the global Temporal.Calendar.prototype method so +// we can observe the call to monthDayFromFields() on the ISO8601 calendar +// that occurs when we parse the string + +const realMonthDayFromFields = Temporal.Calendar.prototype.monthDayFromFields; +let monthDayFromFieldsCallCount = 0; +Temporal.Calendar.prototype.monthDayFromFields = function (fields, options) { + monthDayFromFieldsCallCount++; + assert.sameValue(options, undefined, "monthDayFromFields shouldn't be called with options"); + return realMonthDayFromFields.call(this, fields, options); +} + +instance.equals("2000-05-03"); +assert.sameValue(monthDayFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.monthDayFromFields = realMonthDayFromFields; diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/toJSON/year-format.js b/test/built-ins/Temporal/PlainMonthDay/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..90b633fb299 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/toJSON/year-format.js @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +// For PlainMonthDay, the ISO reference year is only present in the string if +// the calendar is not ISO 8601 +class NotISO extends Temporal.Calendar { + constructor() { super("iso8601"); } + toString() { return "not-iso"; } +} +const calendar = new NotISO(); + +let instance = new Temporal.PlainMonthDay(12, 3, calendar, -100000); +assert.sameValue(instance.toJSON(), "-100000-12-03[u-ca=not-iso]", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(4, 5, calendar, -10000); +assert.sameValue(instance.toJSON(), "-010000-04-05[u-ca=not-iso]", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(6, 7, calendar, -9999); +assert.sameValue(instance.toJSON(), "-009999-06-07[u-ca=not-iso]", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 9, calendar, -1000); +assert.sameValue(instance.toJSON(), "-001000-08-09[u-ca=not-iso]", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(10, 9, calendar, -999); +assert.sameValue(instance.toJSON(), "-000999-10-09[u-ca=not-iso]", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 7, calendar, -1); +assert.sameValue(instance.toJSON(), "-000001-08-07[u-ca=not-iso]", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(6, 5, calendar, 0); +assert.sameValue(instance.toJSON(), "0000-06-05[u-ca=not-iso]", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(4, 3, calendar, 1); +assert.sameValue(instance.toJSON(), "0001-04-03[u-ca=not-iso]", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(2, 10, calendar, 999); +assert.sameValue(instance.toJSON(), "0999-02-10[u-ca=not-iso]", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(1, 23, calendar, 1000); +assert.sameValue(instance.toJSON(), "1000-01-23[u-ca=not-iso]", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(4, 5, calendar, 9999); +assert.sameValue(instance.toJSON(), "9999-04-05[u-ca=not-iso]", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(6, 7, calendar, 10000); +assert.sameValue(instance.toJSON(), "+010000-06-07[u-ca=not-iso]", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 9, calendar, 100000); +assert.sameValue(instance.toJSON(), "+100000-08-09[u-ca=not-iso]", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/toString/calendarname-always.js b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/calendarname-always.js index fadff8929f4..4d1d85b6797 100644 --- a/test/built-ins/Temporal/PlainMonthDay/prototype/toString/calendarname-always.js +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/calendarname-always.js @@ -8,9 +8,9 @@ features: [Temporal] ---*/ const tests = [ - [[], "05-02[u-ca=iso8601]"], + [[], "1972-05-02[u-ca=iso8601]"], [[{ toString() { return "custom"; } }], "1972-05-02[u-ca=custom]"], - [[{ toString() { return "iso8601"; } }], "05-02[u-ca=iso8601]"], + [[{ toString() { return "iso8601"; } }], "1972-05-02[u-ca=iso8601]"], [[{ toString() { return "ISO8601"; } }], "1972-05-02[u-ca=ISO8601]"], [[{ toString() { return "\u0131so8601"; } }], "1972-05-02[u-ca=\u0131so8601]"], // dotless i ]; diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..67575fe09f8 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainMonthDay(5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/toString/year-format.js b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/year-format.js new file mode 100644 index 00000000000..3898ff66b65 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/toString/year-format.js @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +// For PlainMonthDay, the ISO reference year is only present in the string if +// the calendar is not ISO 8601 +class NotISO extends Temporal.Calendar { + constructor() { super("iso8601"); } + toString() { return "not-iso"; } +} +const calendar = new NotISO(); + +let instance = new Temporal.PlainMonthDay(12, 3, calendar, -100000); +assert.sameValue(instance.toString(), "-100000-12-03[u-ca=not-iso]", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(4, 5, calendar, -10000); +assert.sameValue(instance.toString(), "-010000-04-05[u-ca=not-iso]", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(6, 7, calendar, -9999); +assert.sameValue(instance.toString(), "-009999-06-07[u-ca=not-iso]", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 9, calendar, -1000); +assert.sameValue(instance.toString(), "-001000-08-09[u-ca=not-iso]", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(10, 9, calendar, -999); +assert.sameValue(instance.toString(), "-000999-10-09[u-ca=not-iso]", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 7, calendar, -1); +assert.sameValue(instance.toString(), "-000001-08-07[u-ca=not-iso]", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(6, 5, calendar, 0); +assert.sameValue(instance.toString(), "0000-06-05[u-ca=not-iso]", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(4, 3, calendar, 1); +assert.sameValue(instance.toString(), "0001-04-03[u-ca=not-iso]", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(2, 10, calendar, 999); +assert.sameValue(instance.toString(), "0999-02-10[u-ca=not-iso]", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(1, 23, calendar, 1000); +assert.sameValue(instance.toString(), "1000-01-23[u-ca=not-iso]", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(4, 5, calendar, 9999); +assert.sameValue(instance.toString(), "9999-04-05[u-ca=not-iso]", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainMonthDay(6, 7, calendar, 10000); +assert.sameValue(instance.toString(), "+010000-06-07[u-ca=not-iso]", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainMonthDay(8, 9, calendar, 100000); +assert.sameValue(instance.toString(), "+100000-08-09[u-ca=not-iso]", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/PlainMonthDay/prototype/with/options-wrong-type.js new file mode 100644 index 00000000000..5dbd34864b0 --- /dev/null +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/with/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainmonthday.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainMonthDay(5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainMonthDay/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/PlainMonthDay/prototype/with/overflow-invalid-string.js index 5ed47e97538..0036dfe6380 100644 --- a/test/built-ins/Temporal/PlainMonthDay/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainMonthDay/prototype/with/overflow-invalid-string.js @@ -17,6 +17,12 @@ features: [Temporal] ---*/ const monthday = new Temporal.PlainMonthDay(5, 2); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => monthday.with({ day: 8 }, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => monthday.with({ day: 8 }, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainTime/from/argument-string-invalid.js b/test/built-ins/Temporal/PlainTime/from/observable-get-overflow-argument-string-invalid.js similarity index 100% rename from test/built-ins/Temporal/PlainTime/from/argument-string-invalid.js rename to test/built-ins/Temporal/PlainTime/from/observable-get-overflow-argument-string-invalid.js diff --git a/test/built-ins/Temporal/PlainTime/from/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/from/options-wrong-type.js new file mode 100644 index 00000000000..587674dd128 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainTime.from({ hour: 12, minute: 34 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/from/overflow-invalid-string.js b/test/built-ins/Temporal/PlainTime/from/overflow-invalid-string.js index 856d071453e..dcefde8a682 100644 --- a/test/built-ins/Temporal/PlainTime/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/from/overflow-invalid-string.js @@ -19,8 +19,14 @@ const validValues = [ { hour: 12 }, "12:00", ]; -validValues.forEach((value) => { - ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"].forEach((overflow) => { - assert.throws(RangeError, () => Temporal.PlainTime.from(value, { overflow })); - }); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const value of validValues) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainTime.from(value, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/PlainTime/prototype/round/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/round/options-wrong-type.js new file mode 100644 index 00000000000..2edf4591a14 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/round/options-wrong-type.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.round +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + undefined, + null, + true, + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainTime(); +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-invalid-string.js index 1da2034e113..917a5a409d2 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-invalid-string.js @@ -8,7 +8,28 @@ features: [Temporal] ---*/ const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); -const values = ["era", "year", "month", "week", "day", "years", "months", "weeks", "days", "nonsense", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => time.round({ smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => time.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/since/largestunit-invalid-string.js index f74105aba51..0faa16156a0 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.PlainTime(12, 34, 56, 0, 0, 0); const later = new Temporal.PlainTime(13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..f48b7c373bc --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainTime(); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainTime(12, 34, 56), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/since/smallestunit-invalid-string.js index de440191cf2..b375626bf59 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.PlainTime(12, 34, 56, 0, 0, 0); const later = new Temporal.PlainTime(13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/argument-string-invalid.js b/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/argument-string-invalid.js new file mode 100644 index 00000000000..768f1dba079 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.toplaindatetime +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..5a594f23a42 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/toPlainDateTime/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.toplaindatetime +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainTime(12, 34, 56, 987, 654, 321, calendar); +instance.toPlainDateTime({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-auto.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-auto.js index 2bff43e90a7..2c90ffaa47a 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-auto.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-auto.js @@ -7,13 +7,17 @@ description: auto value for fractionalSecondDigits option features: [Temporal] ---*/ +const zeroSeconds = new Temporal.PlainTime(15, 23); +const wholeSeconds = new Temporal.PlainTime(15, 23, 30); +const subSeconds = new Temporal.PlainTime(15, 23, 30, 123, 400); + const tests = [ - ["15:23", "15:23:00"], - ["15:23:30", "15:23:30"], - ["15:23:30.1234", "15:23:30.1234"], + [zeroSeconds, "15:23:00"], + [wholeSeconds, "15:23:30"], + [subSeconds, "15:23:30.1234"], ]; -for (const [input, expected] of tests) { - const plainTime = Temporal.PlainTime.from(input); - assert.sameValue(plainTime.toString({ fractionalSecondDigits: "auto" }), expected); +for (const [time, expected] of tests) { + assert.sameValue(time.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(time.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js index 3d4ab17c430..1be21d324c7 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -10,12 +10,13 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaintime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0); -for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos"]) { - assert.throws(RangeError, () => time.toString({ fractionalSecondDigits })); +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => time.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js index 9b7c5250e0d..3ca8fed5aa0 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -10,7 +10,7 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaintime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-number.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-number.js index 5973c534001..0ea1eb838ea 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-number.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-number.js @@ -7,16 +7,27 @@ description: Number for fractionalSecondDigits option features: [Temporal] ---*/ -const t1 = Temporal.PlainTime.from("15:23"); -const t2 = Temporal.PlainTime.from("15:23:30"); -const t3 = Temporal.PlainTime.from("15:23:30.1234"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 0 }), "15:23:30"); -assert.sameValue(t1.toString({ fractionalSecondDigits: 2 }), "15:23:00.00"); -assert.sameValue(t2.toString({ fractionalSecondDigits: 2 }), "15:23:30.00"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 2 }), "15:23:30.12"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 3 }), "15:23:30.123"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 6 }), "15:23:30.123400"); -assert.sameValue(t1.toString({ fractionalSecondDigits: 7 }), "15:23:00.0000000"); -assert.sameValue(t2.toString({ fractionalSecondDigits: 7 }), "15:23:30.0000000"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 7 }), "15:23:30.1234000"); -assert.sameValue(t3.toString({ fractionalSecondDigits: 9 }), "15:23:30.123400000"); +const zeroSeconds = new Temporal.PlainTime(15, 23); +const wholeSeconds = new Temporal.PlainTime(15, 23, 30); +const subSeconds = new Temporal.PlainTime(15, 23, 30, 123, 400); + +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "15:23:30", + "truncates 4 decimal places to 0"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 2 }), "15:23:00.00", + "pads zero seconds to 2 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "15:23:30.00", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "15:23:30.12", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "15:23:30.123", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "15:23:30.123400", + "pads 4 decimal places to 6"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 7 }), "15:23:00.0000000", + "pads zero seconds to 7 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "15:23:30.0000000", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "15:23:30.1234000", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "15:23:30.123400000", + "pads 4 decimal places to 9"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js index 5959dd94591..1d6e899312f 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -10,13 +10,17 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaintime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0); -assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -Infinity })); -assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -1 })); -assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 10 })); -assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: Infinity })); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js index 1d9d2dff038..6c33c55f7f4 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js @@ -8,29 +8,31 @@ info: | sec-getoption step 3: 3. If _value_ is *undefined*, return _fallback_. sec-getstringornumberoption step 2: - 2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_). + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.plaintime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ +const zeroSeconds = new Temporal.PlainTime(15, 23); +const wholeSeconds = new Temporal.PlainTime(15, 23, 30); +const subSeconds = new Temporal.PlainTime(15, 23, 30, 123, 400); + const tests = [ - ["15:23", "15:23:00"], - ["15:23:30", "15:23:30"], - ["15:23:30.1234", "15:23:30.1234"], + [zeroSeconds, "15:23:00"], + [wholeSeconds, "15:23:30"], + [subSeconds, "15:23:30.1234"], ]; -for (const [input, expected] of tests) { - const time = Temporal.PlainTime.from(input); - +for (const [time, expected] of tests) { const explicit = time.toString({ fractionalSecondDigits: undefined }); - assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto"); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); const implicit = time.toString({}); - assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto"); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); const lambda = time.toString(() => {}); - assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto"); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js index 54440155aa3..79fcd282938 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -22,4 +22,26 @@ features: [Temporal] ---*/ const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0); -TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(time); + +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => time.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = time.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "12:34:56.98765", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..d77abfa038d --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainTime(); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/rounding-cross-midnight.js b/test/built-ins/Temporal/PlainTime/prototype/toString/rounding-cross-midnight.js index 4c67d223aac..d580f6f5e23 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/rounding-cross-midnight.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/rounding-cross-midnight.js @@ -7,7 +7,7 @@ description: Rounding can cross midnight features: [Temporal] ---*/ -const plainTime = Temporal.PlainTime.from("23:59:59.999999999"); +const plainTime = new Temporal.PlainTime(23, 59, 59, 999, 999, 999); // one nanosecond before 00:00:00 for (const roundingMode of ["ceil", "halfExpand"]) { assert.sameValue(plainTime.toString({ fractionalSecondDigits: 8, roundingMode }), "00:00:00.00000000"); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-ceil.js b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-ceil.js index 4f6552b87be..97006c66ff6 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-ceil.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-ceil.js @@ -10,10 +10,28 @@ features: [Temporal] const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); const result1 = time.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); -assert.sameValue(result1, "12:34:56.123988", "roundingMode is ceil"); +assert.sameValue(result1, "12:34:56.123988", + "roundingMode is ceil (with 6 digits from smallestUnit)"); -const result2 = time.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); -assert.sameValue(result2, "12:34:56.124", "roundingMode is ceil"); +const result2 = time.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "12:34:56.123988", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); -const result3 = time.toString({ smallestUnit: "second", roundingMode: "ceil" }); -assert.sameValue(result3, "12:34:57", "roundingMode is ceil"); +const result3 = time.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "12:34:56.124", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = time.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "12:34:56.124", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = time.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "12:34:57", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = time.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "12:34:57", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); + +const result7 = time.toString({ smallestUnit: "minute", roundingMode: "ceil" }); +assert.sameValue(result7, "12:35", "roundingMode is ceil (round to minute)"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-floor.js b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-floor.js index 63b30d3cc5b..528d8cd0c84 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-floor.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-floor.js @@ -10,10 +10,28 @@ features: [Temporal] const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); const result1 = time.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); -assert.sameValue(result1, "12:34:56.123987", "roundingMode is floor"); +assert.sameValue(result1, "12:34:56.123987", + "roundingMode is floor (with 6 digits from smallestUnit)"); -const result2 = time.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); -assert.sameValue(result2, "12:34:56.123", "roundingMode is floor"); +const result2 = time.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "12:34:56.123987", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); -const result3 = time.toString({ smallestUnit: "second", roundingMode: "floor" }); -assert.sameValue(result3, "12:34:56", "roundingMode is floor"); +const result3 = time.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "12:34:56.123", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = time.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "12:34:56.123", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = time.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "12:34:56", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = time.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "12:34:56", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); + +const result7 = time.toString({ smallestUnit: "minute", roundingMode: "floor" }); +assert.sameValue(result7, "12:34", "roundingMode is floor (round to minute)"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-halfExpand.js b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-halfExpand.js index cd7b8e4673a..35a65a86665 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-halfExpand.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-halfExpand.js @@ -10,10 +10,28 @@ features: [Temporal] const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); const result1 = time.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); -assert.sameValue(result1, "12:34:56.123988", "roundingMode is halfExpand"); +assert.sameValue(result1, "12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); -const result2 = time.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); -assert.sameValue(result2, "12:34:56.124", "roundingMode is halfExpand"); +const result2 = time.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); -const result3 = time.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); -assert.sameValue(result3, "12:34:56", "roundingMode is halfExpand"); +const result3 = time.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "12:34:56.124", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = time.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "12:34:56.124", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = time.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "12:34:56", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = time.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "12:34:56", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); + +const result7 = time.toString({ smallestUnit: "minute", roundingMode: "halfExpand" }); +assert.sameValue(result7, "12:35", "roundingMode is halfExpand (round to minute)"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-trunc.js b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-trunc.js index e25101caf42..d3496b266bd 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-trunc.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/roundingmode-trunc.js @@ -10,10 +10,28 @@ features: [Temporal] const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); const result1 = time.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); -assert.sameValue(result1, "12:34:56.123987", "roundingMode is trunc"); +assert.sameValue(result1, "12:34:56.123987", + "roundingMode is trunc (with 6 digits from smallestUnit)"); -const result2 = time.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); -assert.sameValue(result2, "12:34:56.123", "roundingMode is trunc"); +const result2 = time.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "12:34:56.123987", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); -const result3 = time.toString({ smallestUnit: "second", roundingMode: "trunc" }); -assert.sameValue(result3, "12:34:56", "roundingMode is trunc"); +const result3 = time.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "12:34:56.123", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = time.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "12:34:56.123", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = time.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "12:34:56", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = time.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "12:34:56", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = time.toString({ smallestUnit: "minute", roundingMode: "trunc" }); +assert.sameValue(result7, "12:34", "roundingMode is trunc (round to minute)"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-fractionalseconddigits.js b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-fractionalseconddigits.js index 06ab3baac63..318041efa06 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-fractionalseconddigits.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-fractionalseconddigits.js @@ -21,11 +21,10 @@ for (const [smallestUnit, expected] of tests) { smallestUnit, get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } }); - assert.sameValue(string, expected, smallestUnit); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); } assert.throws(RangeError, () => time.toString({ smallestUnit: "hour", get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } -})); - +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-invalid-string.js index d5ea0a7b3e7..d093928a489 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-invalid-string.js @@ -8,6 +8,30 @@ features: [Temporal] ---*/ const time = new Temporal.PlainTime(12, 34, 56, 123, 987, 500); -for (const smallestUnit of ["era", "year", "month", "day", "hour", "nonsense", "other string", "m\u0131nute", "SECOND"]) { - assert.throws(RangeError, () => time.toString({ smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => time.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js index e2b4c71dbd2..bb942179e2c 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js @@ -7,21 +7,41 @@ description: Valid units for the smallestUnit option features: [Temporal] ---*/ -const time = new Temporal.PlainTime(12, 34, 56, 789, 999, 999); -assert.sameValue(time.toString({ smallestUnit: "minute" }), "12:34"); -assert.sameValue(time.toString({ smallestUnit: "second" }), "12:34:56"); -assert.sameValue(time.toString({ smallestUnit: "millisecond" }), "12:34:56.789"); -assert.sameValue(time.toString({ smallestUnit: "microsecond" }), "12:34:56.789999"); -assert.sameValue(time.toString({ smallestUnit: "nanosecond" }), "12:34:56.789999999"); +const time = new Temporal.PlainTime(12, 34, 56, 123, 456, 789); -const time2 = new Temporal.PlainTime(12, 34); -assert.sameValue(time2.toString({ smallestUnit: "minute" }), "12:34"); -assert.sameValue(time2.toString({ smallestUnit: "second" }), "12:34:00"); -assert.sameValue(time2.toString({ smallestUnit: "millisecond" }), "12:34:00.000"); -assert.sameValue(time2.toString({ smallestUnit: "microsecond" }), "12:34:00.000000"); -assert.sameValue(time2.toString({ smallestUnit: "nanosecond" }), "12:34:00.000000000"); +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + time, + [ + ["minute", "12:34"], + ["second", "12:34:56"], + ["millisecond", "12:34:56.123"], + ["microsecond", "12:34:56.123456"], + ["nanosecond", "12:34:56.123456789"], + ], + "subseconds toString" +); + +test( + new Temporal.PlainTime(12, 34), + [ + ["minute", "12:34"], + ["second", "12:34:00"], + ["millisecond", "12:34:00.000"], + ["microsecond", "12:34:00.000000"], + ["nanosecond", "12:34:00.000000000"], + ], + "whole minutes toString" +); const notValid = [ + "era", "year", "month", "week", @@ -30,5 +50,6 @@ const notValid = [ ]; notValid.forEach((smallestUnit) => { - assert.throws(RangeError, () => time.toString({ smallestUnit }), smallestUnit); + assert.throws(RangeError, () => time.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); }); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/argument-string-invalid.js b/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/argument-string-invalid.js new file mode 100644 index 00000000000..03b196269e8 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.tozoneddatetime +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainDate: arg }), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..e6b9fc3e122 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/toZonedDateTime/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.tozoneddatetime +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainTime(12, 34, 56, 987, 654, 321, calendar); +instance.toZonedDateTime({ plainDate: { year: 2000, month: 5, day: 3, calendar }, timeZone: new Temporal.TimeZone("UTC") }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/PlainTime/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/until/largestunit-invalid-string.js index 7fcf10a557b..ff95f0e7832 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.PlainTime(12, 34, 56, 0, 0, 0); const later = new Temporal.PlainTime(13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..4f30cb995d2 --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainTime(); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainTime(12, 34, 56), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/until/smallestunit-invalid-string.js index 7225494a217..62ca4957d27 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,28 @@ features: [Temporal] const earlier = new Temporal.PlainTime(12, 34, 56, 0, 0, 0); const later = new Temporal.PlainTime(13, 35, 57, 987, 654, 321); -const values = ["era", "eraYear", "years", "months", "weeks", "days", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/with/options-wrong-type.js new file mode 100644 index 00000000000..d45bbc8986d --- /dev/null +++ b/test/built-ins/Temporal/PlainTime/prototype/with/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaintime.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainTime(); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ minute: 45 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainTime/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/with/overflow-invalid-string.js index 796cec5fcf3..dc50e7795bc 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/with/overflow-invalid-string.js @@ -16,6 +16,12 @@ features: [Temporal] const time = new Temporal.PlainTime(12); const values = ["", "CONSTRAIN", "balance", "other string"]; -for (const overflow of values) { - assert.throws(RangeError, () => time.with({ minute: 45 }, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => time.with({ minute: 45 }, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainYearMonth/calendar-always.js b/test/built-ins/Temporal/PlainYearMonth/calendar-always.js new file mode 100644 index 00000000000..0aad58df09f --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/calendar-always.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth +description: If calendar name is to be emitted, include additional reference info +features: [Temporal] +---*/ + +const pym = new Temporal.PlainYearMonth(2019, 10, "iso8601", 31); + +assert.sameValue( + pym.toString({ calendarName: 'always' }), + "2019-10-31[u-ca=iso8601]", + "emit year-month-day if calendarName = 'always' (four-argument constructor)" +); + +const anotherPYM = Temporal.PlainYearMonth.from("2019-10-31"); // 31 will get dropped + +assert.sameValue( + anotherPYM.toString({ calendarName: 'always' }), + "2019-10-01[u-ca=iso8601]", + "emit fallback day if calendarName = 'always' (static from)" +); diff --git a/test/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..999e5afa760 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,32 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.compare +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +Temporal.PlainYearMonth.compare({ year: 2000, month: 5, calendar }, { year: 2000, month: 6, calendar }); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 2); + +// Test again, but overriding the global Temporal.Calendar.prototype method so +// we can observe the call to yearMonthFromFields() on the ISO8601 calendar +// that occurs when we parse the string + +const realYearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; +let yearMonthFromFieldsCallCount = 0; +Temporal.Calendar.prototype.yearMonthFromFields = function (fields, options) { + yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return realYearMonthFromFields.call(this, fields, options); +} + +Temporal.PlainYearMonth.compare("2000-05-01", "2000-06-01"); +assert.sameValue(yearMonthFromFieldsCallCount, 2); + +Temporal.Calendar.prototype.yearMonthFromFields = realYearMonthFromFields; diff --git a/test/built-ins/Temporal/PlainYearMonth/from/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/from/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..f3f33f1ba0f --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/from/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.from +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +features: [Temporal] +---*/ + +const realYearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; +let yearMonthFromFieldsCallCount = 0; +Temporal.Calendar.prototype.yearMonthFromFields = function (fields, options) { + yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return realYearMonthFromFields.call(this, fields, options); +} + +Temporal.PlainYearMonth.from("2000-05-01"); +assert.sameValue(yearMonthFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.yearMonthFromFields = realYearMonthFromFields; diff --git a/test/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js new file mode 100644 index 00000000000..eb85b8180b3 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainYearMonth.from({ year: 2021, monthCode: "M01" }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js index d30774eece5..11335f2481a 100644 --- a/test/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js @@ -27,8 +27,14 @@ const validValues = [ { year: 2000, month: 5 }, "2000-05", ]; -validValues.forEach((value) => { - ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"].forEach((overflow) => { - assert.throws(RangeError, () => Temporal.PlainYearMonth.from(value, { overflow })); - }); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const value of validValues) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(value, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js b/test/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js new file mode 100644 index 00000000000..de0bee72b0f --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js @@ -0,0 +1,147 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.add +description: > + Calls calendar's dateFromFields method to obtain a start date for the + operation, based on the sign of the duration +info: | + 8. Let _fields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»). + 9. Let _sign_ be ! DurationSign(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _balanceResult_.[[Days]], 0, 0, 0, 0, 0, 0). + 10. If _sign_ < 0, then + a. Let _dayFromCalendar_ be ? CalendarDaysInMonth(_calendar_, _yearMonth_). + b. Let _day_ be ? ToPositiveInteger(_dayFromCalendar_). + 11. Else, + a. Let _day_ be 1. + 12. Perform ! CreateDataPropertyOrThrow(_fields_, *"day"*, _day_). + 13. Let _date_ be ? DateFromFields(_calendar_, _fields_, *undefined*). +includes: [deepEqual.js, temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + this.dateFromFieldsCalls = []; + } + year(date) { + // years in this calendar start and end on the same day as ISO 8601 years + return date.getISOFields().isoYear; + } + month(date) { + // this calendar has 10 months of 36 days each, plus an 11th month of 5 or 6 + const { isoYear, isoMonth, isoDay } = date.getISOFields(); + const isoDate = new Temporal.PlainDate(isoYear, isoMonth, isoDay); + return Math.floor((isoDate.dayOfYear - 1) / 36) + 1; + } + monthCode(date) { + return "M" + this.month(date).toString().padStart(2, "0"); + } + day(date) { + return (date.dayOfYear - 1) % 36 + 1; + } + daysInMonth(date) { + if (this.month(date) < 11) return 36; + return this.daysInYear(date) - 360; + } + _dateFromFieldsImpl({ year, month, monthCode, day }) { + if (year === undefined) throw new TypeError("year required"); + if (month === undefined && monthCode === undefined) throw new TypeError("one of month or monthCode required"); + if (month !== undefined && month < 1) throw new RangeError("month < 1"); + if (day === undefined) throw new TypeError("day required"); + + if (monthCode !== undefined) { + const numberPart = +(monthCode.slice(1)); + if ("M" + `${numberPart}`.padStart(2, "0") !== monthCode) throw new RangeError("invalid monthCode"); + if (month === undefined) { + month = numberPart; + } else if (month !== numberPart) { + throw new RangeError("month and monthCode must match"); + } + } + + const isoDayOfYear = (month - 1) * 36 + day; + return new Temporal.PlainDate(year, 1, 1).add({ days: isoDayOfYear - 1 }).withCalendar(this); + } + dateFromFields(...args) { + this.dateFromFieldsCalls.push(args); + return this._dateFromFieldsImpl(...args); + } + yearMonthFromFields(fields, options) { + const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, day: 1 }, options).getISOFields(); + return new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay); + } + monthDayFromFields(fields, options) { + const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, year: 2000 }, options).getISOFields(); + return new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear); + } + dateAdd(date, duration, options) { + if (duration.months) throw new Error("adding months not implemented in this test"); + return super.dateAdd(date, duration, options); + } + toString() { + return "thirty-six"; + } +} + +const calendar = new CustomCalendar(); +const month2 = Temporal.PlainYearMonth.from({ year: 2022, month: 2, calendar }); +const lessThanOneMonth = new Temporal.Duration(0, 0, 0, 35); +const oneMonth = new Temporal.Duration(0, 0, 0, 36); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.add(lessThanOneMonth), + 2022, 2, "M02", + "adding positive less than one month's worth of days yields the same month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 1 }, + "first day of month 2 passed to dateFromFields when adding positive duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.add(oneMonth), + 2022, 3, "M03", + "adding positive one month's worth of days yields the following month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 1 }, + "first day of month 2 passed to dateFromFields when adding positive duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.add(lessThanOneMonth.negated()), + 2022, 2, "M02", + "adding negative less than one month's worth of days yields the same month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 36 }, + "last day of month 2 passed to dateFromFields when adding negative duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.add(oneMonth.negated()), + 2022, 1, "M01", + "adding negative one month's worth of days yields the previous month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 36 }, + "last day of month 2 passed to dateFromFields when adding negative duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js new file mode 100644 index 00000000000..95d62d106b2 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js index 4913de46a29..1633f1b6544 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js @@ -20,6 +20,12 @@ features: [Temporal] const yearmonth = new Temporal.PlainYearMonth(2000, 5); const duration = new Temporal.Duration(1, 1); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => yearmonth.add(duration, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => yearmonth.add(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..490c35f4939 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.equals +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +let instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.equals({ year: 2000, month: 6, calendar }); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); + +// Test again, but overriding the global Temporal.Calendar.prototype method so +// we can observe the call to yearMonthFromFields() on the ISO8601 calendar +// that occurs when we parse the string + +const realYearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; +let yearMonthFromFieldsCallCount = 0; +Temporal.Calendar.prototype.yearMonthFromFields = function (fields, options) { + yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return realYearMonthFromFields.call(this, fields, options); +} + +calendar = new Temporal.Calendar("iso8601"); +instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.equals("2000-06-01"); +assert.sameValue(yearMonthFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.yearMonthFromFields = realYearMonthFromFields; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..d7978361ad5 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.since +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.since({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..db48db0cfaa --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.since +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +let instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.since({ year: 2000, month: 6, calendar }); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); + +// Test again, but overriding the global Temporal.Calendar.prototype method so +// we can observe the call to yearMonthFromFields() on the ISO8601 calendar +// that occurs when we parse the string + +const realYearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; +let yearMonthFromFieldsCallCount = 0; +Temporal.Calendar.prototype.yearMonthFromFields = function (fields, options) { + yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return realYearMonthFromFields.call(this, fields, options); +} + +calendar = new Temporal.Calendar("iso8601"); +instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.since("2000-06-01"); +assert.sameValue(yearMonthFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.yearMonthFromFields = realYearMonthFromFields; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js index 09b7687f263..00a668d252d 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,34 @@ features: [Temporal] const earlier = new Temporal.PlainYearMonth(2000, 5); const later = new Temporal.PlainYearMonth(2001, 6); -const values = ["era", "eraYear", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..9441a8e4dba --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainYearMonth(1976, 11), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js index 21b0c4b6983..f8e1f541a06 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,34 @@ features: [Temporal] const earlier = new Temporal.PlainYearMonth(2000, 5); const later = new Temporal.PlainYearMonth(2001, 6); -const values = ["era", "eraYear", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js new file mode 100644 index 00000000000..7e717222a8d --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js @@ -0,0 +1,147 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.subtract +description: > + Calls calendar's dateFromFields method to obtain a start date for the + operation, based on the sign of the duration +info: | + 9. Let _fields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»). + 10. Let _sign_ be ! DurationSign(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _balanceResult_.[[Days]], 0, 0, 0, 0, 0, 0). + 11. If _sign_ < 0, then + a. Let _dayFromCalendar_ be ? CalendarDaysInMonth(_calendar_, _yearMonth_). + b. Let _day_ be ? ToPositiveInteger(_dayFromCalendar_). + 12. Else, + a. Let _day_ be 1. + 13. Perform ! CreateDataPropertyOrThrow(_fields_, *"day"*, _day_). + 14. Let _date_ be ? DateFromFields(_calendar_, _fields_, *undefined*). +includes: [deepEqual.js, temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + this.dateFromFieldsCalls = []; + } + year(date) { + // years in this calendar start and end on the same day as ISO 8601 years + return date.getISOFields().isoYear; + } + month(date) { + // this calendar has 10 months of 36 days each, plus an 11th month of 5 or 6 + const { isoYear, isoMonth, isoDay } = date.getISOFields(); + const isoDate = new Temporal.PlainDate(isoYear, isoMonth, isoDay); + return Math.floor((isoDate.dayOfYear - 1) / 36) + 1; + } + monthCode(date) { + return "M" + this.month(date).toString().padStart(2, "0"); + } + day(date) { + return (date.dayOfYear - 1) % 36 + 1; + } + daysInMonth(date) { + if (this.month(date) < 11) return 36; + return this.daysInYear(date) - 360; + } + _dateFromFieldsImpl({ year, month, monthCode, day }) { + if (year === undefined) throw new TypeError("year required"); + if (month === undefined && monthCode === undefined) throw new TypeError("one of month or monthCode required"); + if (month !== undefined && month < 1) throw new RangeError("month < 1"); + if (day === undefined) throw new TypeError("day required"); + + if (monthCode !== undefined) { + const numberPart = +(monthCode.slice(1)); + if ("M" + `${numberPart}`.padStart(2, "0") !== monthCode) throw new RangeError("invalid monthCode"); + if (month === undefined) { + month = numberPart; + } else if (month !== numberPart) { + throw new RangeError("month and monthCode must match"); + } + } + + const isoDayOfYear = (month - 1) * 36 + day; + return new Temporal.PlainDate(year, 1, 1).add({ days: isoDayOfYear - 1 }).withCalendar(this); + } + dateFromFields(...args) { + this.dateFromFieldsCalls.push(args); + return this._dateFromFieldsImpl(...args); + } + yearMonthFromFields(fields, options) { + const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, day: 1 }, options).getISOFields(); + return new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay); + } + monthDayFromFields(fields, options) { + const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, year: 2000 }, options).getISOFields(); + return new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear); + } + dateAdd(date, duration, options) { + if (duration.months) throw new Error("adding months not implemented in this test"); + return super.dateAdd(date, duration, options); + } + toString() { + return "thirty-six"; + } +} + +const calendar = new CustomCalendar(); +const month2 = Temporal.PlainYearMonth.from({ year: 2022, month: 2, calendar }); +const lessThanOneMonth = new Temporal.Duration(0, 0, 0, 35); +const oneMonth = new Temporal.Duration(0, 0, 0, 36); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.subtract(lessThanOneMonth), + 2022, 2, "M02", + "subtracting positive less than one month's worth of days yields the same month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 36 }, + "last day of month 2 passed to dateFromFields when subtracting positive duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.subtract(oneMonth), + 2022, 1, "M01", + "subtracting positive one month's worth of days yields the previous month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 36 }, + "last day of month 2 passed to dateFromFields when subtracting positive duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.subtract(lessThanOneMonth.negated()), + 2022, 2, "M02", + "subtracting negative less than one month's worth of days yields the same month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 1 }, + "first day of month 2 passed to dateFromFields when subtracting negative duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.subtract(oneMonth.negated()), + 2022, 3, "M03", + "subtracting negative one month's worth of days yields the following month" +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, month: 2, monthCode: "M02", day: 1 }, + "first day of month 2 passed to dateFromFields when subtracting negative duration" +); +assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed"); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js new file mode 100644 index 00000000000..d64177826d6 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js index 8c2efb855a7..46286d5a6a2 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js @@ -20,6 +20,12 @@ features: [Temporal] const yearmonth = new Temporal.PlainYearMonth(2000, 5); const duration = new Temporal.Duration(1, 1); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => yearmonth.subtract(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js b/test/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..706d3624a0f --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainYearMonth(-100000, 12); +assert.sameValue(instance.toJSON(), "-100000-12", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-10000, 4); +assert.sameValue(instance.toJSON(), "-010000-04", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-9999, 6); +assert.sameValue(instance.toJSON(), "-009999-06", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-1000, 8); +assert.sameValue(instance.toJSON(), "-001000-08", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-999, 10); +assert.sameValue(instance.toJSON(), "-000999-10", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-1, 8); +assert.sameValue(instance.toJSON(), "-000001-08", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(0, 6); +assert.sameValue(instance.toJSON(), "0000-06", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(1, 4); +assert.sameValue(instance.toJSON(), "0001-04", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(999, 2); +assert.sameValue(instance.toJSON(), "0999-02", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(1000, 1); +assert.sameValue(instance.toJSON(), "1000-01", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(9999, 4); +assert.sameValue(instance.toJSON(), "9999-04", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(10000, 6); +assert.sameValue(instance.toJSON(), "+010000-06", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(100000, 8); +assert.sameValue(instance.toJSON(), "+100000-08", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js index d6fa52e1064..be8cc7e93f8 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js @@ -14,7 +14,7 @@ const yearmonth1 = new Temporal.PlainYearMonth(2000, 5); const yearmonth2 = new Temporal.PlainYearMonth(2000, 5, calendar); [ - [yearmonth1, "2000-05[u-ca=iso8601]"], + [yearmonth1, "2000-05-01[u-ca=iso8601]"], // fallback day 1 used [yearmonth2, "2000-05-01[u-ca=custom]"], ].forEach(([yearmonth, expected]) => { const result = yearmonth.toString({ calendarName: "always" }); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..1e759554d51 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js new file mode 100644 index 00000000000..6c1b9474638 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js @@ -0,0 +1,47 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainYearMonth(-100000, 12); +assert.sameValue(instance.toString(), "-100000-12", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-10000, 4); +assert.sameValue(instance.toString(), "-010000-04", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-9999, 6); +assert.sameValue(instance.toString(), "-009999-06", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-1000, 8); +assert.sameValue(instance.toString(), "-001000-08", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-999, 10); +assert.sameValue(instance.toString(), "-000999-10", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(-1, 8); +assert.sameValue(instance.toString(), "-000001-08", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(0, 6); +assert.sameValue(instance.toString(), "0000-06", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(1, 4); +assert.sameValue(instance.toString(), "0001-04", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(999, 2); +assert.sameValue(instance.toString(), "0999-02", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(1000, 1); +assert.sameValue(instance.toString(), "1000-01", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(9999, 4); +assert.sameValue(instance.toString(), "9999-04", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainYearMonth(10000, 6); +assert.sameValue(instance.toString(), "+010000-06", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainYearMonth(100000, 8); +assert.sameValue(instance.toString(), "+100000-08", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..89bdacd0cd3 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.until +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.until({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..d9b946e2795 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.until +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +let instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.until({ year: 2000, month: 6, calendar }); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); + +// Test again, but overriding the global Temporal.Calendar.prototype method so +// we can observe the call to yearMonthFromFields() on the ISO8601 calendar +// that occurs when we parse the string + +const realYearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields; +let yearMonthFromFieldsCallCount = 0; +Temporal.Calendar.prototype.yearMonthFromFields = function (fields, options) { + yearMonthFromFieldsCallCount++; + assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options"); + return realYearMonthFromFields.call(this, fields, options); +} + +calendar = new Temporal.Calendar("iso8601"); +instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.until("2000-06-01"); +assert.sameValue(yearMonthFromFieldsCallCount, 1); + +Temporal.Calendar.prototype.yearMonthFromFields = realYearMonthFromFields; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js index bb243a89914..e3055ec8c49 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,34 @@ features: [Temporal] const earlier = new Temporal.PlainYearMonth(2000, 5); const later = new Temporal.PlainYearMonth(2001, 6); -const values = ["era", "eraYear", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..ff3266edccc --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainYearMonth(1976, 11), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js index 9e494305079..07095eaf3f4 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,34 @@ features: [Temporal] const earlier = new Temporal.PlainYearMonth(2000, 5); const later = new Temporal.PlainYearMonth(2001, 6); -const values = ["era", "eraYear", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js index bc8f0a542ec..8b6b6e1af38 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js @@ -7,7 +7,7 @@ description: TypeError thrown when options argument is a primitive features: [BigInt, Symbol, Temporal] ---*/ -const values = [ +const badOptions = [ null, true, "2021-01", @@ -16,7 +16,8 @@ const values = [ 2n, ]; -const ym = Temporal.PlainYearMonth.from("2019-10"); -values.forEach((value) => { - assert.throws(TypeError, () => ym.with({ year: 2020 }, value), `TypeError on wrong argument type ${typeof value}`); -}); +const instance = new Temporal.PlainYearMonth(2019, 10); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ year: 2020 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js index 587c66754c8..4684d597f3e 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js @@ -17,6 +17,12 @@ features: [Temporal] ---*/ const yearmonth = new Temporal.PlainYearMonth(2000, 5); -for (const overflow of ["", "CONSTRAIN", "balance", "other string", "constra\u0131n"]) { - assert.throws(RangeError, () => yearmonth.with({ month: 8 }, { overflow })); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => yearmonth.with({ month: 8 }, { overflow }), + `invalid overflow ("${overflow}")` + ); } diff --git a/test/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-wrong-type.js b/test/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-wrong-type.js new file mode 100644 index 00000000000..eaa0b1239d0 --- /dev/null +++ b/test/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getinstantfor +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.getInstantFor(new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/from/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/from/options-wrong-type.js new file mode 100644 index 00000000000..91fb3bab63e --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/from/options-wrong-type.js @@ -0,0 +1,22 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: "UTC" }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/from/overflow-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/from/overflow-invalid-string.js index 5913d3e7f96..e8406c57e37 100644 --- a/test/built-ins/Temporal/ZonedDateTime/from/overflow-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/from/overflow-invalid-string.js @@ -32,6 +32,14 @@ const validValues = [ { year: 2000, month: 5, day: 2, hour: 12, timeZone: "UTC" }, "2001-09-09T01:46:40.987654321+00:00[UTC]", ]; -validValues.forEach((value) => { - assert.throws(RangeError, () => Temporal.ZonedDateTime.from(value, { overflow: "other string" })); -}); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const value of validValues) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.ZonedDateTime.from(value, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/add/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/add/options-wrong-type.js new file mode 100644 index 00000000000..b107f23ee02 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/add/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ years: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/add/overflow-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/add/overflow-invalid-string.js index 4c88b568784..ede72ad4a96 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/add/overflow-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/add/overflow-invalid-string.js @@ -20,4 +20,11 @@ features: [Temporal] const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC"); const duration = new Temporal.Duration(0, 0, 0, 1); -assert.throws(RangeError, () => datetime.add(duration, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => datetime.add(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/round/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/round/options-wrong-type.js new file mode 100644 index 00000000000..e54dcd45e6c --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/round/options-wrong-type.js @@ -0,0 +1,24 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.round +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + undefined, + null, + true, + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/round/rounding-direction.js b/test/built-ins/Temporal/ZonedDateTime/prototype/round/rounding-direction.js new file mode 100644 index 00000000000..676841ed26d --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/round/rounding-direction.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.round +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.ZonedDateTime(-65_261_246_399_500_000_000n, "UTC"); // -000099-12-15T12:00:00.5Z +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "floor" }).epochNanoseconds, + -65_261_246_400_000_000_000n, // -000099-12-15T12:00:00Z + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode floor)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "trunc" }).epochNanoseconds, + -65_261_246_400_000_000_000n, // -000099-12-15T12:00:00Z + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "ceil" }).epochNanoseconds, + -65_261_246_399_000_000_000n, // -000099-12-15T12:00:01Z + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.round({ smallestUnit: "second", roundingMode: "halfExpand" }).epochNanoseconds, + -65_261_246_399_000_000_000n, // -000099-12-15T12:00:01Z + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/round/smallestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/round/smallestunit-invalid-string.js index bee6892ba97..cf8831a9756 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/round/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/round/smallestunit-invalid-string.js @@ -8,4 +8,26 @@ features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); -assert.throws(RangeError, () => datetime.round({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateadd-called-with-options-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateadd-called-with-options-undefined.js new file mode 100644 index 00000000000..9e6556718c8 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateadd-called-with-options-undefined.js @@ -0,0 +1,68 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.since +description: > + BuiltinTimeZoneGetInstantFor calls Calendar.dateAdd with undefined as the + options value +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddUndefinedOptions(); +const timeZone = TemporalHelpers.oneShiftTimeZone(new Temporal.Instant(0n), 3600e9); +const earlier = new Temporal.ZonedDateTime(0n, timeZone, calendar); + +// Basic difference with largestUnit larger than days. +// The calls come from these paths: +// ZonedDateTime.since() -> DifferenceZonedDateTime -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() + +const later1 = new Temporal.ZonedDateTime(1_213_200_000_000_000n, timeZone, calendar); +later1.since(earlier, { largestUnit: "weeks" }); +assert.sameValue(calendar.dateAddCallCount, 2, "basic difference with largestUnit >days"); + +// Basic difference with largestUnit equal to days, to cover the second path in +// AddZonedDateTime. +// The calls come from these paths: +// ZonedDateTime.since() -> DifferenceZonedDateTime -> NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) + +calendar.dateAddCallCount = 0; + +later1.since(earlier, { largestUnit: "days" }); +assert.sameValue(calendar.dateAddCallCount, 2, "basic difference with largestUnit days"); + +// Difference with rounding, with smallestUnit a calendar unit. +// The calls come from these paths: +// ZonedDateTime.since() -> +// DifferenceZonedDateTime -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// MoveRelativeDate -> calendar.dateAdd() + +calendar.dateAddCallCount = 0; + +later1.since(earlier, { smallestUnit: "weeks" }); +assert.sameValue(calendar.dateAddCallCount, 5, "rounding difference with calendar smallestUnit"); + +// Difference with rounding, with smallestUnit a non-calendar unit, and having +// the resulting time difference be longer than a calendar day, covering the +// paths that go through AdjustRoundedDurationDays. (The path through +// AdjustRoundedDurationDays -> AddDuration that's covered in the corresponding +// test in until() only happens in one direction.) +// The calls come from these paths: +// ZonedDateTime.since() -> +// DifferenceZonedDateTime -> NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (3x) +// AdjustRoundedDurationDays -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (3x) + +calendar.dateAddCallCount = 0; + +const later2 = new Temporal.ZonedDateTime(86_399_999_999_999n, timeZone, calendar); +later2.since(earlier, { largestUnit: "days", smallestUnit: "hours", roundingMode: "ceil" }); +assert.sameValue(calendar.dateAddCallCount, 6, "rounding difference with non-calendar smallestUnit and time difference longer than a calendar day"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-invalid-string.js index 61dd7f3ad39..9e96e8a4965 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); const later = new Temporal.ZonedDateTime(1_000_090_061_987_654_321n, "UTC"); -const values = ["era", "eraYear", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/options-wrong-type.js new file mode 100644 index 00000000000..f2f30920733 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.ZonedDateTime(3600_000_000_000n, "UTC"), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-invalid-string.js index 5735fba65e7..a116e240745 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); const later = new Temporal.ZonedDateTime(1_000_090_061_987_654_321n, "UTC"); -const values = ["era", "eraYear", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => later.since(earlier, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/options-wrong-type.js new file mode 100644 index 00000000000..d06125ab40a --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ years: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/overflow-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/overflow-invalid-string.js index 8c144ef70d0..7a7d4fd1206 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/overflow-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/subtract/overflow-invalid-string.js @@ -20,4 +20,11 @@ features: [Temporal] const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC"); const duration = new Temporal.Duration(0, 0, 0, 1); -assert.throws(RangeError, () => datetime.subtract(duration, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => datetime.subtract(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toJSON/year-format.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toJSON/year-format.js new file mode 100644 index 00000000000..d532f99c4a6 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toJSON/year-format.js @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +function epochNsInYear(year) { + // Return an epoch nanoseconds value near the middle of the given year + const avgNsPerYear = 31_556_952_000_000_000n; + return (year - 1970n) * avgNsPerYear + (avgNsPerYear / 2n); +} + +const utc = new Temporal.TimeZone("UTC"); + +let instance = new Temporal.ZonedDateTime(epochNsInYear(-100000n), utc); +assert.sameValue(instance.toJSON(), "-100000-07-01T21:30:36+00:00[UTC]", "large negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-10000n), utc); +assert.sameValue(instance.toJSON(), "-010000-07-01T21:30:36+00:00[UTC]", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-9999n), utc); +assert.sameValue(instance.toJSON(), "-009999-07-02T03:19:48+00:00[UTC]", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-1000n), utc); +assert.sameValue(instance.toJSON(), "-001000-07-02T09:30:36+00:00[UTC]", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-999n), utc); +assert.sameValue(instance.toJSON(), "-000999-07-02T15:19:48+00:00[UTC]", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-1n), utc); +assert.sameValue(instance.toJSON(), "-000001-07-02T15:41:24+00:00[UTC]", "year -1 formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(0n), utc); +assert.sameValue(instance.toJSON(), "0000-07-01T21:30:36+00:00[UTC]", "year 0 formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(1n), utc); +assert.sameValue(instance.toJSON(), "0001-07-02T03:19:48+00:00[UTC]", "year 1 formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(999n), utc); +assert.sameValue(instance.toJSON(), "0999-07-02T03:41:24+00:00[UTC]", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(1000n), utc); +assert.sameValue(instance.toJSON(), "1000-07-02T09:30:36+00:00[UTC]", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(9999n), utc); +assert.sameValue(instance.toJSON(), "9999-07-02T15:41:24+00:00[UTC]", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(10000n), utc); +assert.sameValue(instance.toJSON(), "+010000-07-01T21:30:36+00:00[UTC]", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(100000n), utc); +assert.sameValue(instance.toJSON(), "+100000-07-01T21:30:36+00:00[UTC]", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..e1925185c5d --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..8f75ba30b57 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.toplainyearmonth +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); +instance.toPlainYearMonth(); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-auto.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-auto.js new file mode 100644 index 00000000000..bffb9289511 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-auto.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: auto value for fractionalSecondDigits option +features: [BigInt, Temporal] +---*/ + +const zeroSeconds = new Temporal.ZonedDateTime(0n, "UTC"); +const wholeSeconds = new Temporal.ZonedDateTime(30_000_000_000n, "UTC"); +const subSeconds = new Temporal.ZonedDateTime(30_123_400_000n, "UTC"); + +const tests = [ + [zeroSeconds, "1970-01-01T00:00:00+00:00[UTC]"], + [wholeSeconds, "1970-01-01T00:00:30+00:00[UTC]"], + [subSeconds, "1970-01-01T00:00:30.1234+00:00[UTC]"], +]; + +for (const [datetime, expected] of tests) { + assert.sameValue(datetime.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(datetime.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js index ea172ceb80e..c933354b9d4 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -9,11 +9,14 @@ info: | 4. If _stringValues_ is not *undefined* and _stringValues_ does not contain an element equal to _value_, throw a *RangeError* exception. sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). - sec-temporal.instant.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + sec-temporal.zoneddatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC"); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: "other string" })); +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js index 93685aedece..a9ccce61d8d 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -10,7 +10,7 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.zoneddatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-number.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-number.js new file mode 100644 index 00000000000..0063031f203 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-number.js @@ -0,0 +1,33 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: Number for fractionalSecondDigits option +features: [BigInt, Temporal] +---*/ + +const zeroSeconds = new Temporal.ZonedDateTime(0n, "UTC"); +const wholeSeconds = new Temporal.ZonedDateTime(30_000_000_000n, "UTC"); +const subSeconds = new Temporal.ZonedDateTime(30_123_400_000n, "UTC"); + +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "1970-01-01T00:00:30+00:00[UTC]", + "truncates 4 decimal places to 0"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:00.00+00:00[UTC]", + "pads zero seconds to 2 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:30.00+00:00[UTC]", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "1970-01-01T00:00:30.12+00:00[UTC]", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "1970-01-01T00:00:30.123+00:00[UTC]", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "1970-01-01T00:00:30.123400+00:00[UTC]", + "pads 4 decimal places to 6"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:00.0000000+00:00[UTC]", + "pads zero seconds to 7 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:30.0000000+00:00[UTC]", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "1970-01-01T00:00:30.1234000+00:00[UTC]", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "1970-01-01T00:00:30.123400000+00:00[UTC]", + "pads 4 decimal places to 9"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js index 36ae8d14293..487600a4158 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -10,11 +10,17 @@ info: | sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.zoneddatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC"); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 })); -assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 })); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js index a4e0a10b5f0..734f436c4c3 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js @@ -8,17 +8,31 @@ info: | sec-getoption step 3: 3. If _value_ is *undefined*, return _fallback_. sec-getstringornumberoption step 2: - 2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_). + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). sec-temporal-tosecondsstringprecision step 9: 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). sec-temporal.zoneddatetime.prototype.tostring step 4: - 4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_). + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). features: [Temporal] ---*/ -const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC"); +const zeroSeconds = new Temporal.ZonedDateTime(0n, "UTC"); +const wholeSeconds = new Temporal.ZonedDateTime(30_000_000_000n, "UTC"); +const subSeconds = new Temporal.ZonedDateTime(30_123_400_000n, "UTC"); -const explicit = datetime.toString({ fractionalSecondDigits: undefined }); -assert.sameValue(explicit, "2001-09-09T01:46:40.98765+00:00[UTC]", "default fractionalSecondDigits is auto"); +const tests = [ + [zeroSeconds, "1970-01-01T00:00:00+00:00[UTC]"], + [wholeSeconds, "1970-01-01T00:00:30+00:00[UTC]"], + [subSeconds, "1970-01-01T00:00:30.1234+00:00[UTC]"], +]; -// See options-undefined.js for {} +for (const [datetime, expected] of tests) { + const explicit = datetime.toString({ fractionalSecondDigits: undefined }); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); + + const implicit = datetime.toString({}); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); + + const lambda = datetime.toString(() => {}); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js index b147dbac3e2..9a12691ad6d 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -22,4 +22,26 @@ features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC"); -TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(datetime); + +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => datetime.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = datetime.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "2001-09-09T01:46:40.98765+00:00[UTC]", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/options-wrong-type.js new file mode 100644 index 00000000000..4b579b44d01 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-cross-midnight.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-cross-midnight.js new file mode 100644 index 00000000000..a55db0f240e --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-cross-midnight.js @@ -0,0 +1,13 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: Rounding can cross midnight +features: [Temporal] +---*/ + +const zonedDateTime = new Temporal.ZonedDateTime(946_684_799_999_999_999n, "UTC"); // one nanosecond before 2000-01-01T00:00:00 +for (const roundingMode of ["ceil", "halfExpand"]) { + assert.sameValue(zonedDateTime.toString({ fractionalSecondDigits: 8, roundingMode }), "2000-01-01T00:00:00.00000000+00:00[UTC]"); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-direction.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-direction.js new file mode 100644 index 00000000000..b376e075bb8 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/rounding-direction.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.ZonedDateTime(-65_261_246_399_500_000_000n, "UTC"); // -000099-12-15T12:00:00.5Z +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "floor" }), + "-000099-12-15T12:00:00+00:00[UTC]", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "trunc" }), + "-000099-12-15T12:00:00+00:00[UTC]", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "ceil" }), + "-000099-12-15T12:00:01+00:00[UTC]", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "halfExpand" }), + "-000099-12-15T12:00:01+00:00[UTC]", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-ceil.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-ceil.js new file mode 100644 index 00000000000..cd9c1af1edc --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-ceil.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: ceil value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123988+00:00[UTC]", + "roundingMode is ceil (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123988+00:00[UTC]", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "2001-09-09T01:46:40.124+00:00[UTC]", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "2001-09-09T01:46:40.124+00:00[UTC]", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "2001-09-09T01:46:41+00:00[UTC]", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "2001-09-09T01:46:41+00:00[UTC]", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "ceil" }); +assert.sameValue(result7, "2001-09-09T01:47+00:00[UTC]", "roundingMode is ceil (round to minute)"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-floor.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-floor.js new file mode 100644 index 00000000000..fec4286c461 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-floor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: floor value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123987+00:00[UTC]", + "roundingMode is floor (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123987+00:00[UTC]", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "2001-09-09T01:46:40.123+00:00[UTC]", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "2001-09-09T01:46:40.123+00:00[UTC]", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "floor" }); +assert.sameValue(result7, "2001-09-09T01:46+00:00[UTC]", "roundingMode is floor (round to minute)"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-halfExpand.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-halfExpand.js new file mode 100644 index 00000000000..a4a989cb6ed --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-halfExpand.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: halfExpand value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123988+00:00[UTC]", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123988+00:00[UTC]", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "2001-09-09T01:46:40.124+00:00[UTC]", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "2001-09-09T01:46:40.124+00:00[UTC]", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfExpand" }); +assert.sameValue(result7, "2001-09-09T01:47+00:00[UTC]", "roundingMode is halfExpand (round to minute)"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-trunc.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-trunc.js new file mode 100644 index 00000000000..8fc3ca0dca9 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/roundingmode-trunc.js @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: trunc value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); +assert.sameValue(result1, "2001-09-09T01:46:40.123987+00:00[UTC]", + "roundingMode is trunc (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "2001-09-09T01:46:40.123987+00:00[UTC]", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "2001-09-09T01:46:40.123+00:00[UTC]", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "2001-09-09T01:46:40.123+00:00[UTC]", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "2001-09-09T01:46:40+00:00[UTC]", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "trunc" }); +assert.sameValue(result7, "2001-09-09T01:46+00:00[UTC]", "roundingMode is trunc (round to minute)"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-fractionalseconddigits.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-fractionalseconddigits.js new file mode 100644 index 00000000000..7845c10bfb2 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-fractionalseconddigits.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: fractionalSecondDigits option is not used with smallestUnit present +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(56_789_999_999n, "UTC"); +const tests = [ + ["minute", "1970-01-01T00:00+00:00[UTC]"], + ["second", "1970-01-01T00:00:56+00:00[UTC]"], + ["millisecond", "1970-01-01T00:00:56.789+00:00[UTC]"], + ["microsecond", "1970-01-01T00:00:56.789999+00:00[UTC]"], + ["nanosecond", "1970-01-01T00:00:56.789999999+00:00[UTC]"], +]; + +for (const [smallestUnit, expected] of tests) { + const string = datetime.toString({ + smallestUnit, + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } + }); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); +} + +assert.throws(RangeError, () => datetime.toString({ + smallestUnit: "hour", + get fractionalSecondDigits() { throw new Test262Error("should not get fractionalSecondDigits") } +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-invalid-string.js index d3940464811..1ba9732789b 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-invalid-string.js @@ -8,4 +8,30 @@ features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_987_500n, "UTC"); -assert.throws(RangeError, () => datetime.toString({ smallestUnit: "other string" })); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js index 12c10368b64..6ea787955a9 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js @@ -9,13 +9,39 @@ features: [Temporal] const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_456_789n, "UTC"); -assert.sameValue(datetime.toString({ smallestUnit: "minute" }), "2001-09-09T01:46+00:00[UTC]"); -assert.sameValue(datetime.toString({ smallestUnit: "second" }), "2001-09-09T01:46:40+00:00[UTC]"); -assert.sameValue(datetime.toString({ smallestUnit: "millisecond" }), "2001-09-09T01:46:40.123+00:00[UTC]"); -assert.sameValue(datetime.toString({ smallestUnit: "microsecond" }), "2001-09-09T01:46:40.123456+00:00[UTC]"); -assert.sameValue(datetime.toString({ smallestUnit: "nanosecond" }), "2001-09-09T01:46:40.123456789+00:00[UTC]"); +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + datetime, + [ + ["minute", "2001-09-09T01:46+00:00[UTC]"], + ["second", "2001-09-09T01:46:40+00:00[UTC]"], + ["millisecond", "2001-09-09T01:46:40.123+00:00[UTC]"], + ["microsecond", "2001-09-09T01:46:40.123456+00:00[UTC]"], + ["nanosecond", "2001-09-09T01:46:40.123456789+00:00[UTC]"], + ], + "subseconds toString" +); + +test( + new Temporal.ZonedDateTime(999_999_960_000_000_000n, "UTC"), + [ + ["minute", "2001-09-09T01:46+00:00[UTC]"], + ["second", "2001-09-09T01:46:00+00:00[UTC]"], + ["millisecond", "2001-09-09T01:46:00.000+00:00[UTC]"], + ["microsecond", "2001-09-09T01:46:00.000000+00:00[UTC]"], + ["nanosecond", "2001-09-09T01:46:00.000000000+00:00[UTC]"], + ], + "whole minutes toString" +); const notValid = [ + "era", "year", "month", "week", @@ -24,5 +50,6 @@ const notValid = [ ]; notValid.forEach((smallestUnit) => { - assert.throws(RangeError, () => datetime.toString({ smallestUnit }), smallestUnit); + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); }); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/year-format.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/year-format.js new file mode 100644 index 00000000000..1532bf1fecd --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/year-format.js @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +function epochNsInYear(year) { + // Return an epoch nanoseconds value near the middle of the given year + const avgNsPerYear = 31_556_952_000_000_000n; + return (year - 1970n) * avgNsPerYear + (avgNsPerYear / 2n); +} + +const utc = new Temporal.TimeZone("UTC"); + +let instance = new Temporal.ZonedDateTime(epochNsInYear(-100000n), utc); +assert.sameValue(instance.toString(), "-100000-07-01T21:30:36+00:00[UTC]", "large negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-10000n), utc); +assert.sameValue(instance.toString(), "-010000-07-01T21:30:36+00:00[UTC]", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-9999n), utc); +assert.sameValue(instance.toString(), "-009999-07-02T03:19:48+00:00[UTC]", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-1000n), utc); +assert.sameValue(instance.toString(), "-001000-07-02T09:30:36+00:00[UTC]", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-999n), utc); +assert.sameValue(instance.toString(), "-000999-07-02T15:19:48+00:00[UTC]", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(-1n), utc); +assert.sameValue(instance.toString(), "-000001-07-02T15:41:24+00:00[UTC]", "year -1 formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(0n), utc); +assert.sameValue(instance.toString(), "0000-07-01T21:30:36+00:00[UTC]", "year 0 formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(1n), utc); +assert.sameValue(instance.toString(), "0001-07-02T03:19:48+00:00[UTC]", "year 1 formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(999n), utc); +assert.sameValue(instance.toString(), "0999-07-02T03:41:24+00:00[UTC]", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(1000n), utc); +assert.sameValue(instance.toString(), "1000-07-02T09:30:36+00:00[UTC]", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(9999n), utc); +assert.sameValue(instance.toString(), "9999-07-02T15:41:24+00:00[UTC]", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(10000n), utc); +assert.sameValue(instance.toString(), "+010000-07-01T21:30:36+00:00[UTC]", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.ZonedDateTime(epochNsInYear(100000n), utc); +assert.sameValue(instance.toString(), "+100000-07-01T21:30:36+00:00[UTC]", "large positive year formatted as 6-digit"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateadd-called-with-options-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateadd-called-with-options-undefined.js new file mode 100644 index 00000000000..13bdd33972e --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateadd-called-with-options-undefined.js @@ -0,0 +1,69 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.until +description: > + BuiltinTimeZoneGetInstantFor calls Calendar.dateAdd with undefined as the + options value +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddUndefinedOptions(); +const timeZone = TemporalHelpers.oneShiftTimeZone(new Temporal.Instant(0n), 3600e9); +const earlier = new Temporal.ZonedDateTime(0n, timeZone, calendar); + +// Basic difference with largestUnit larger than days. +// The calls come from these paths: +// ZonedDateTime.until() -> DifferenceZonedDateTime -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() + +const later1 = new Temporal.ZonedDateTime(1_213_200_000_000_000n, timeZone, calendar); +earlier.until(later1, { largestUnit: "weeks" }); +assert.sameValue(calendar.dateAddCallCount, 2, "basic difference with largestUnit >days"); + +// Basic difference with largestUnit equal to days, to cover the second path in +// AddZonedDateTime. +// The calls come from these paths: +// ZonedDateTime.until() -> DifferenceZonedDateTime -> NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) + +calendar.dateAddCallCount = 0; + +earlier.until(later1, { largestUnit: "days" }); +assert.sameValue(calendar.dateAddCallCount, 2, "basic difference with largestUnit days"); + +// Difference with rounding, with smallestUnit a calendar unit. +// The calls come from these paths: +// ZonedDateTime.until() -> +// DifferenceZonedDateTime -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// RoundDuration -> +// MoveRelativeZonedDateTime -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// MoveRelativeDate -> calendar.dateAdd() + +calendar.dateAddCallCount = 0; + +earlier.until(later1, { smallestUnit: "weeks" }); +assert.sameValue(calendar.dateAddCallCount, 5, "rounding difference with calendar smallestUnit"); + +// Difference with rounding, with smallestUnit a non-calendar unit, and having +// the resulting time difference be longer than a calendar day, covering the +// paths that go through AdjustRoundedDurationDays. +// The calls come from these paths: +// ZonedDateTime.until() -> +// DifferenceZonedDateTime -> NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// AdjustRoundedDurationDays -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// AddDuration -> +// AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() +// DifferenceZonedDateTime -> NanosecondsToDays -> AddZonedDateTime -> BuiltinTimeZoneGetInstantFor -> calendar.dateAdd() (2x) + +calendar.dateAddCallCount = 0; + +const later2 = new Temporal.ZonedDateTime(86_399_999_999_999n, timeZone, calendar); +earlier.until(later2, { largestUnit: "days", smallestUnit: "hours", roundingMode: "ceil" }); +assert.sameValue(calendar.dateAddCallCount, 5, "rounding difference with non-calendar smallestUnit and time difference longer than a calendar day"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-invalid-string.js index a59c2f2e43c..2be916f1778 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); const later = new Temporal.ZonedDateTime(1_000_090_061_987_654_321n, "UTC"); -const values = ["era", "eraYear", "other string"]; -for (const largestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { largestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); } diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/options-wrong-type.js new file mode 100644 index 00000000000..55b128637ea --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.ZonedDateTime(3600_000_000_000n, "UTC"), value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-invalid-string.js index 42f55bc8503..4f09f10f688 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-invalid-string.js @@ -9,7 +9,20 @@ features: [Temporal] const earlier = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); const later = new Temporal.ZonedDateTime(1_000_090_061_987_654_321n, "UTC"); -const values = ["era", "eraYear", "other string"]; -for (const smallestUnit of values) { - assert.throws(RangeError, () => earlier.until(later, { smallestUnit })); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); } diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/with/options-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/with/options-wrong-type.js new file mode 100644 index 00000000000..5f4d25d9305 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/with/options-wrong-type.js @@ -0,0 +1,23 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.ZonedDateTime(0n, "UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/with/overflow-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/with/overflow-invalid-string.js index 96d5ab3799d..843437f59fd 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/with/overflow-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/with/overflow-invalid-string.js @@ -18,4 +18,11 @@ features: [Temporal] ---*/ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC"); -assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: "other string" })); +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => datetime.with({ minute: 45 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/argument-string-invalid.js b/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/argument-string-invalid.js new file mode 100644 index 00000000000..003bf13f1b8 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.withplaindate +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..f19cc9fac12 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.withplaindate +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); +instance.withPlainDate({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/built-ins/TypedArray/prototype/set/BigInt/array-arg-targetbuffer-detached-on-get-src-value-throws.js b/test/built-ins/TypedArray/prototype/set/BigInt/array-arg-targetbuffer-detached-on-get-src-value-throws.js deleted file mode 100644 index 568e8b9b08a..00000000000 --- a/test/built-ins/TypedArray/prototype/set/BigInt/array-arg-targetbuffer-detached-on-get-src-value-throws.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-%typedarray%.prototype.set-array-offset -description: > - Throws an error if buffer is detached before setting a value -info: | - 22.2.3.23.1 %TypedArray%.prototype.set (array [ , offset ] ) - - 1. Assert: array is any ECMAScript language value other than an Object with a - [[TypedArrayName]] internal slot. If it is such an Object, the definition in - 22.2.3.23.2 applies. - ... - 21. Repeat, while targetByteIndex < limit - a. Let Pk be ! ToString(k). - b. Let kNumber be ? ToNumber(? Get(src, Pk)). - c. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception. - d. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, - kNumber). - ... -includes: [testBigIntTypedArray.js, detachArrayBuffer.js] -features: [BigInt, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA([1n, 2n, 3n]); - var obj = { - length: 3, - "0": 42n - }; - Object.defineProperty(obj, 1, { - get: function() { - $DETACHBUFFER(sample.buffer); - } - }); - Object.defineProperty(obj, 2, { - get: function() { - throw new Test262Error("Should not get other values"); - } - }); - - assert.throws(TypeError, function() { - sample.set(obj); - }); -}); diff --git a/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js b/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js new file mode 100644 index 00000000000..1d514622089 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js @@ -0,0 +1,36 @@ +// Copyright (C) 2022 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-%typedarray%.prototype.set-array-offset +description: > + Does not throw if target TA is detached mid-iteration +includes: [testTypedArray.js, detachArrayBuffer.js] +features: [TypedArray] +---*/ + +testWithTypedArrayConstructors(function(TA) { + var sample = new TA([1, 2, 3]); + var obj = { + length: 3, + "0": 42 + }; + Object.defineProperty(obj, 1, { + get: function() { + $DETACHBUFFER(sample.buffer); + } + }); + let get2Called = false; + Object.defineProperty(obj, 2, { + get: function() { + get2Called = true; + return 2; + } + }); + + sample.set(obj); + + assert.sameValue(true, get2Called); + assert.sameValue(0, sample.byteLength); + assert.sameValue(0, sample.byteOffset); + assert.sameValue(0, sample.length); +}); diff --git a/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js b/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js deleted file mode 100644 index eed7db0831a..00000000000 --- a/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-%typedarray%.prototype.set-array-offset -description: > - Throws an error if buffer is detached before setting a value -info: | - 22.2.3.23.1 %TypedArray%.prototype.set (array [ , offset ] ) - - 1. Assert: array is any ECMAScript language value other than an Object with a - [[TypedArrayName]] internal slot. If it is such an Object, the definition in - 22.2.3.23.2 applies. - ... - 21. Repeat, while targetByteIndex < limit - a. Let Pk be ! ToString(k). - b. Let kNumber be ? ToNumber(? Get(src, Pk)). - c. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception. - d. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, - kNumber). - ... -includes: [testTypedArray.js, detachArrayBuffer.js] -features: [TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA([1, 2, 3]); - var obj = { - length: 3, - "0": 42 - }; - Object.defineProperty(obj, 1, { - get: function() { - $DETACHBUFFER(sample.buffer); - } - }); - Object.defineProperty(obj, 2, { - get: function() { - throw new Test262Error("Should not get other values"); - } - }); - - assert.throws(TypeError, function() { - sample.set(obj); - }); -}); diff --git a/test/built-ins/TypedArray/prototype/sort/BigInt/detached-buffer-comparefn.js b/test/built-ins/TypedArray/prototype/sort/BigInt/detached-buffer-comparefn.js deleted file mode 100644 index caa7f80a28a..00000000000 --- a/test/built-ins/TypedArray/prototype/sort/BigInt/detached-buffer-comparefn.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-%typedarray%.prototype.sort -description: Throws a TypeError if comparefn detaches the object buffer -info: | - 22.2.3.26 %TypedArray%.prototype.sort ( comparefn ) - - When the TypedArray SortCompare abstract operation is called with two - arguments x and y, the following steps are taken: - - ... - 2. If the argument comparefn is not undefined, then - a. Let v be ? Call(comparefn, undefined, « x, y »). - b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - ... - ... -includes: [testBigIntTypedArray.js, detachArrayBuffer.js] -features: [BigInt, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(4); - var calls = 0; - var comparefn = function() { - if (calls > 0) { - throw new Test262Error(); - } - calls++; - $DETACHBUFFER(sample.buffer); - }; - - assert.throws(TypeError, function() { - sample.sort(comparefn); - }); - - assert.sameValue(calls, 1); -}); diff --git a/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn-coerce.js b/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn-coerce.js deleted file mode 100644 index 6e2be4cafda..00000000000 --- a/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn-coerce.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2020 Google. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-%typedarray%.prototype.sort -description: > - SECURITY Throws a TypeError if coercion of the comparefn return value - detaches the object buffer -info: | - 22.2.3.26 %TypedArray%.prototype.sort ( comparefn ) - - When the TypedArray SortCompare abstract operation is called with two - arguments x and y, the following steps are taken: - - ... - 2. If the argument comparefn is not undefined, then - a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)). - b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - ... - ... -includes: [testTypedArray.js, detachArrayBuffer.js] -features: [TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(4); - var calls = 0; - var convertfn = function(){ - $DETACHBUFFER(sample.buffer); - return 1; - } - var comparefn = function() { - if (calls > 0) { - throw new Test262Error(); - } - calls++; - return {valueOf : convertfn} - }; - - assert.throws(TypeError, function() { - sample.sort(comparefn); - }, "Coercion that detaches buffer should throw TypeError"); - - assert.sameValue(calls, 1); -}); diff --git a/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn.js b/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn.js deleted file mode 100644 index 6ff08beb603..00000000000 --- a/test/built-ins/TypedArray/prototype/sort/detached-buffer-comparefn.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-%typedarray%.prototype.sort -description: Throws a TypeError if comparefn detaches the object buffer -info: | - 22.2.3.26 %TypedArray%.prototype.sort ( comparefn ) - - When the TypedArray SortCompare abstract operation is called with two - arguments x and y, the following steps are taken: - - ... - 2. If the argument comparefn is not undefined, then - a. Let v be ? Call(comparefn, undefined, « x, y »). - b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - ... - ... -includes: [testTypedArray.js, detachArrayBuffer.js] -features: [TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(4); - var calls = 0; - var comparefn = function() { - if (calls > 0) { - throw new Test262Error(); - } - calls++; - $DETACHBUFFER(sample.buffer); - }; - - assert.throws(TypeError, function() { - sample.sort(comparefn); - }); - - assert.sameValue(calls, 1); -}); diff --git a/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js b/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js index 627ed55ecdf..36d8457e980 100644 --- a/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js +++ b/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js @@ -21,16 +21,12 @@ testWithTypedArrayConstructors(function(TA) { var ab = ta.buffer; var called = false; - assert.throws(TypeError, function() { - ta.sort(function(a, b) { - // IsDetachedBuffer is checked right after calling comparefn. - // So, detach the ArrayBuffer to cause sort to throw, to make sure we're actually calling ToNumber immediately (as spec'd) - // (a possible bug is to wait until the result is inspected to call ToNumber, rather than immediately) - $DETACHBUFFER(ab); - return { - [Symbol.toPrimitive]() { called = true; } - }; - }); + ta.sort(function(a, b) { + // Detaching the buffer does not cause sort to throw. + $DETACHBUFFER(ab); + return { + [Symbol.toPrimitive]() { called = true; } + }; }); assert.sameValue(true, called); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-different-type.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-different-type.js deleted file mode 100644 index 4b914e6d2ef..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-different-type.js +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2017 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-typedarray-typedarray -description: > - When a TypedArray is created from another TypedArray with a different element-type - and SpeciesConstructor detaches the source buffer, AllocateArrayBuffer is still - executed. -info: | - 22.2.4.3 TypedArray ( typedArray ) - - ... - 16. If IsSharedArrayBuffer(srcData) is false, then - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - 18. If SameValue(elementType, srcType) is true, then - ... - 19. Else, - a. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", - « [[ArrayBufferData]], [[ArrayBufferByteLength]] »). - ... -includes: [testBigIntTypedArray.js, detachArrayBuffer.js] -features: [BigInt, TypedArray, Symbol.species] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var speciesCallCount = 0; - var bufferConstructor = Object.defineProperty({}, Symbol.species, { - get: function() { - speciesCallCount += 1; - $DETACHBUFFER(ta.buffer); - return speciesConstructor; - } - }); - - var prototypeCallCount = 0; - var speciesConstructor = Object.defineProperty(function(){}.bind(), "prototype", { - get: function() { - prototypeCallCount += 1; - return null; - } - }); - - var ta = new TA(0); - ta.buffer.constructor = bufferConstructor; - - assert.throws(TypeError, function() { - var targetType = TA !== BigInt64Array ? BigInt64Array : BigUint64Array; - new targetType(ta); - }, "TypeError thrown for detached source buffer"); - - assert.sameValue(speciesCallCount, 1, "@@species getter called once"); - assert.sameValue(prototypeCallCount, 1, "prototype getter called once"); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-same-type.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-same-type.js deleted file mode 100644 index c4f45c49c7c..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/detached-when-species-retrieved-same-type.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2017 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-typedarray-typedarray -description: > - When a TypedArray is created from another TypedArray with the same element-type - and SpeciesConstructor detaches the source buffer, AllocateArrayBuffer is still - executed. -info: | - 22.2.4.3 TypedArray ( typedArray ) - - ... - 16. If IsSharedArrayBuffer(srcData) is false, then - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - 18. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength, cloneConstructor ) - - ... - 3. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, srcLength). - 4. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", - « [[ArrayBufferData]], [[ArrayBufferByteLength]] »). - ... -includes: [testBigIntTypedArray.js, detachArrayBuffer.js] -features: [BigInt, TypedArray, Symbol.species] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var speciesCallCount = 0; - var bufferConstructor = Object.defineProperty({}, Symbol.species, { - get: function() { - speciesCallCount += 1; - $DETACHBUFFER(ta.buffer); - return speciesConstructor; - } - }); - - var prototypeCallCount = 0; - var speciesConstructor = Object.defineProperty(function(){}.bind(), "prototype", { - get: function() { - prototypeCallCount += 1; - return null; - } - }); - - var ta = new TA(0); - ta.buffer.constructor = bufferConstructor; - - assert.throws(TypeError, function() { - new TA(ta); - }, "TypeError thrown for detached source buffer"); - - assert.sameValue(speciesCallCount, 1, "@@species getter called once"); - assert.sameValue(prototypeCallCount, 1, "prototype getter called once"); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-access-throws.js deleted file mode 100644 index 3882f1c78e8..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-access-throws.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from getting typedArray argument's buffer.constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var OtherCtor = TA === BigInt64Array ? BigUint64Array : BigInt64Array; - var sample = new OtherCtor(); - - Object.defineProperty(sample.buffer, "constructor", { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js deleted file mode 100644 index 5a5d7ee0ab7..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Derive the ArrayBuffer prototype from the realm of the species constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 9.1.14 GetPrototypeFromConstructor - - ... - 3. Let proto be ? Get(constructor, "prototype"). - 4. If Type(proto) is not Object, then - a. Let realm be ? GetFunctionRealm(constructor). - b. Let proto be realm's intrinsic object named intrinsicDefaultProto. - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, cross-realm, Symbol.species, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); -var other = $262.createRealm().global; -var C = new other.Function(); -C.prototype = null; - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = C; - - var typedArray = new TA(sample); - assert.sameValue( - Object.getPrototypeOf(typedArray.buffer), other.ArrayBuffer.prototype - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species.js deleted file mode 100644 index 1ff1e5db533..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on undefined buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - var ctor = {}; - var called = 0; - var custom = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() { - called++; - }; - - ctor[Symbol.species].prototype = custom; - - var typedArray = new TA(sample); - assert.sameValue(Object.getPrototypeOf(typedArray.buffer), custom); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js deleted file mode 100644 index 44b76c2b95e..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from typedArray argument's buffer.constructor's value -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... - 4. If Type(C) is not Object, throw a TypeError exception. - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - - sample.buffer.constructor = 1; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = true; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = ""; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = null; - assert.throws(TypeError, function() { - new TA(sample); - }); - - var s = Symbol("1"); - sample.buffer.constructor = s; - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js deleted file mode 100644 index 8b3933eedb5..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from getting typedArray argument's buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - var ctor = {}; - - sample.buffer.constructor = ctor; - Object.defineProperty(ctor, Symbol.species, { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js deleted file mode 100644 index 09a8068e9f2..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - 8. Throw a TypeError exception. -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); - -var ctor = function() { - throw new Test262Error(); -}; -var m = { m() {} }.m; -ctor[Symbol.species] = m; - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - - sample.buffer.constructor = ctor; - - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js deleted file mode 100644 index 705b8a7319c..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - ... - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, - "%ArrayBufferPrototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] » ) - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -var sample1 = new BigInt64Array(); -var sample2 = new BigUint64Array(); - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = TA === BigInt64Array ? sample2 : sample1; - var ctor = {}; - var called = 0; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() {called++;}.bind(null); - Object.defineProperty(ctor[Symbol.species], "prototype", { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-access-throws.js deleted file mode 100644 index 51fa9a8358f..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-access-throws.js +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from getting typedArray argument's buffer.constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - Object.defineProperty(sample.buffer, "constructor", { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js deleted file mode 100644 index 90de9642805..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Derive the ArrayBuffer prototype from the realm of the species constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... - - 9.1.14 GetPrototypeFromConstructor - - ... - 3. Let proto be ? Get(constructor, "prototype"). - 4. If Type(proto) is not Object, then - a. Let realm be ? GetFunctionRealm(constructor). - b. Let proto be realm's intrinsic object named intrinsicDefaultProto. - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, cross-realm, Symbol.species, TypedArray] ----*/ - -var other = $262.createRealm().global; -var C = new other.Function(); -C.prototype = null; - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = C; - - var typedArray = new TA(sample); - assert.sameValue( - Object.getPrototypeOf(typedArray.buffer), other.ArrayBuffer.prototype - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom.js deleted file mode 100644 index 743b03e3f4b..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom.js +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on undefined buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - var called = 0; - var custom = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() { - called++; - }; - - ctor[Symbol.species].prototype = custom; - - var typedArray = new TA(sample); - assert.sameValue(Object.getPrototypeOf(typedArray.buffer), custom); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js deleted file mode 100644 index 32cbc01bc3f..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - 8. Throw a TypeError exception. -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - var m = { m() {} }; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = m; - - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js deleted file mode 100644 index 042d4213db8..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - ... - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, - "%ArrayBufferPrototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] » ) - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function(){}.bind(null); - Object.defineProperty(ctor[Symbol.species], "prototype", { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-throws.js deleted file mode 100644 index 0aa7517b802..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-throws.js +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from getting typedArray argument's buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol.species, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - Object.defineProperty(ctor, Symbol.species, { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js b/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js deleted file mode 100644 index a3ca9a041b3..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from typedArray argument's buffer.constructor's value -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... - 4. If Type(C) is not Object, throw a TypeError exception. - ... -includes: [testBigIntTypedArray.js] -features: [BigInt, Symbol, TypedArray] ----*/ - -testWithBigIntTypedArrayConstructors(function(TA) { - var sample = new TA(); - - sample.buffer.constructor = 1; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = true; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = ''; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = null; - assert.throws(TypeError, function() { - new TA(sample); - }); - - var s = Symbol('1'); - sample.buffer.constructor = s; - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/no-species.js b/test/built-ins/TypedArrayConstructors/ctors/no-species.js new file mode 100644 index 00000000000..9fdced7e986 --- /dev/null +++ b/test/built-ins/TypedArrayConstructors/ctors/no-species.js @@ -0,0 +1,30 @@ +// Copyright (C) 2022 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Creating TypedArray from other TypedArrays doesn't look up Symbol.species. +features: [Symbol.species] +---*/ + +let throwOnGrossBufferConstruction = false; + +class GrossBuffer extends ArrayBuffer { + constructor() { + super(...arguments); + if (throwOnGrossBufferConstruction) { + throw new Test262Error("unreachable"); + } + } + static get [Symbol.species]() { + throw new Test262Error("unreachable"); + } +} + +let grossBuf = new GrossBuffer(1024); +throwOnGrossBufferConstruction = true; +let grossTA = new Uint8Array(grossBuf); +let mysteryTA = new Int8Array(grossTA); + +assert.sameValue(mysteryTA.buffer.__proto__, ArrayBuffer.prototype); +assert.sameValue(mysteryTA.buffer.constructor, ArrayBuffer); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js deleted file mode 100644 index 8ee2fba54bc..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2017 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-typedarray-typedarray -description: > - When a TypedArray is created from another TypedArray with a different element-type - and SpeciesConstructor detaches the source buffer, AllocateArrayBuffer is still - executed. -info: | - 22.2.4.3 TypedArray ( typedArray ) - - ... - 16. If IsSharedArrayBuffer(srcData) is false, then - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - 18. If SameValue(elementType, srcType) is true, then - ... - 19. Else, - a. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", - « [[ArrayBufferData]], [[ArrayBufferByteLength]] »). - ... -includes: [testTypedArray.js, detachArrayBuffer.js] -features: [TypedArray, Symbol.species] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var speciesCallCount = 0; - var bufferConstructor = Object.defineProperty({}, Symbol.species, { - get: function() { - speciesCallCount += 1; - $DETACHBUFFER(ta.buffer); - return speciesConstructor; - } - }); - - var prototypeCallCount = 0; - var speciesConstructor = Object.defineProperty(function(){}.bind(), "prototype", { - get: function() { - prototypeCallCount += 1; - return null; - } - }); - - var ta = new TA(0); - ta.buffer.constructor = bufferConstructor; - - assert.throws(TypeError, function() { - var targetType = TA !== Int32Array ? Int32Array : Uint32Array; - new targetType(ta); - }, "TypeError thrown for detached source buffer"); - - assert.sameValue(speciesCallCount, 1, "@@species getter called once"); - assert.sameValue(prototypeCallCount, 1, "prototype getter called once"); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js deleted file mode 100644 index 978f42af64b..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2017 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-typedarray-typedarray -description: > - When a TypedArray is created from another TypedArray with the same element-type - and SpeciesConstructor detaches the source buffer, AllocateArrayBuffer is still - executed. -info: | - 22.2.4.3 TypedArray ( typedArray ) - - ... - 16. If IsSharedArrayBuffer(srcData) is false, then - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - 18. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength, cloneConstructor ) - - ... - 3. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, srcLength). - 4. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", - « [[ArrayBufferData]], [[ArrayBufferByteLength]] »). - ... -includes: [testTypedArray.js, detachArrayBuffer.js] -features: [TypedArray, Symbol.species] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var speciesCallCount = 0; - var bufferConstructor = Object.defineProperty({}, Symbol.species, { - get: function() { - speciesCallCount += 1; - $DETACHBUFFER(ta.buffer); - return speciesConstructor; - } - }); - - var prototypeCallCount = 0; - var speciesConstructor = Object.defineProperty(function(){}.bind(), "prototype", { - get: function() { - prototypeCallCount += 1; - return null; - } - }); - - var ta = new TA(0); - ta.buffer.constructor = bufferConstructor; - - assert.throws(TypeError, function() { - new TA(ta); - }, "TypeError thrown for detached source buffer"); - - assert.sameValue(speciesCallCount, 1, "@@species getter called once"); - assert.sameValue(prototypeCallCount, 1, "prototype getter called once"); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-access-throws.js deleted file mode 100644 index b8976d696de..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-access-throws.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from getting typedArray argument's buffer.constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... -includes: [testTypedArray.js] -features: [TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var OtherCtor = TA === Int8Array ? Int16Array : Int8Array; - var sample = new OtherCtor(); - - Object.defineProperty(sample.buffer, "constructor", { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js deleted file mode 100644 index 03860d1a7be..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Derive the ArrayBuffer prototype from the realm of the species constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 9.1.14 GetPrototypeFromConstructor - - ... - 3. Let proto be ? Get(constructor, "prototype"). - 4. If Type(proto) is not Object, then - a. Let realm be ? GetFunctionRealm(constructor). - b. Let proto be realm's intrinsic object named intrinsicDefaultProto. - ... -includes: [testTypedArray.js] -features: [cross-realm, Symbol.species, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); -var other = $262.createRealm().global; -var C = new other.Function(); -C.prototype = null; - - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = C; - - var typedArray = new TA(sample); - assert.sameValue( - Object.getPrototypeOf(typedArray.buffer), other.ArrayBuffer.prototype - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js deleted file mode 100644 index a510d7806da..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on undefined buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - var ctor = {}; - var called = 0; - var custom = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() { - called++; - }; - - ctor[Symbol.species].prototype = custom; - - var typedArray = new TA(sample); - assert.sameValue(Object.getPrototypeOf(typedArray.buffer), custom); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js deleted file mode 100644 index cfb79f1a948..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from typedArray argument's buffer.constructor's value -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... - 4. If Type(C) is not Object, throw a TypeError exception. - ... -includes: [testTypedArray.js] -features: [Symbol, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - - sample.buffer.constructor = 1; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = true; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = ""; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = null; - assert.throws(TypeError, function() { - new TA(sample); - }); - - var s = Symbol("1"); - sample.buffer.constructor = s; - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js deleted file mode 100644 index 4b0b19aca73..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from getting typedArray argument's buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - var ctor = {}; - - sample.buffer.constructor = ctor; - Object.defineProperty(ctor, Symbol.species, { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js deleted file mode 100644 index c485cae138f..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - 8. Throw a TypeError exception. -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); - -var ctor = function() { - throw new Test262Error(); -}; -var m = { m() {} }.m; -ctor[Symbol.species] = m; - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - - sample.buffer.constructor = ctor; - - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-null.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-null.js deleted file mode 100644 index 96ba9009d66..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-null.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on null buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var OtherCtor = TA === Int8Array ? Int16Array : Int8Array; - var sample = new OtherCtor(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = null; - var typedArray = new TA(sample); - - assert.sameValue( - Object.getPrototypeOf(typedArray.buffer), - ArrayBuffer.prototype, - "buffer ctor is not called when species is null" - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js deleted file mode 100644 index 135634646b4..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - b. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - ... - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, - "%ArrayBufferPrototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] » ) - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -var sample1 = new Int8Array(); -var sample2 = new Int16Array(); - -testWithTypedArrayConstructors(function(TA) { - var sample = TA === Int8Array ? sample2 : sample1; - var ctor = {}; - var called = 0; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() {called++;}.bind(null); - Object.defineProperty(ctor[Symbol.species], "prototype", { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-undefined.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-undefined.js deleted file mode 100644 index 32e78a37dcd..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-undefined.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on undefined buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 18. Else, - a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var OtherCtor = TA === Int8Array ? Int16Array : Int8Array; - var sample = new OtherCtor(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = undefined; - var a = new TA(sample); - assert.sameValue( - Object.getPrototypeOf(a.buffer), - ArrayBuffer.prototype, - "buffer ctor is not called when species is undefined" - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-different-type.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-different-type.js deleted file mode 100644 index 0aba12fc80f..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-different-type.js +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2021 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Error when a TypedArray is created from another TypedArray with a different - element-type and SpeciesConstructor causes the "source" array to go - out-of-bounds. -includes: [testTypedArray.js, compareArray.js] -features: [TypedArray, Symbol.species, resizable-arraybuffer] ----*/ - -// If the host chooses to throw as allowed by the specification, the observed -// behavior will be identical to the case where `ArrayBuffer.prototype.resize` -// has not been implemented. The following assertion prevents this test from -// passing in runtimes which have not implemented the method. -assert.sameValue(typeof ArrayBuffer.prototype.resize, 'function'); - -testWithTypedArrayConstructors(function(TA) { - var BPE = TA.BYTES_PER_ELEMENT; - var TargetCtor = TA !== Int32Array ? Int32Array : Uint32Array; - var ab = new ArrayBuffer(BPE * 4, {maxByteLength: BPE * 5}); - var speciesConstructor = Object.defineProperty(function(){}.bind(), 'prototype', { - get: function() { - return null; - } - }); - var onGetSpecies; - ab.constructor = Object.defineProperty({}, Symbol.species, { - get: function() { - onGetSpecies(); - return speciesConstructor; - } - }); - var source = new TA(ab, BPE); - var expected = [10, 20, 30]; - - source[0] = 10; - source[1] = 20; - source[2] = 30; - - onGetSpecies = function() { - try { - ab.resize(BPE * 5); - expected = [10, 20, 30, 0]; - } catch (_) {} - }; - - assert(compareArray(new TargetCtor(source), expected), 'following grow'); - - onGetSpecies = function() { - try { - ab.resize(BPE * 3); - expected = [10, 20]; - } catch (_) {} - }; - - assert(compareArray(new TargetCtor(source), expected), 'following shrink (within bounds)'); - - onGetSpecies = function() { - try { - ab.resize(BPE); - expected = []; - } catch (_) {} - }; - - assert(compareArray(new TargetCtor(source), expected), 'following shrink (on boundary)'); - - // `assert.throws` cannot be used in this case because the expected error - // is derived only after the constructor is invoked. - var expectedError; - var actualError; - onGetSpecies = function() { - try { - ab.resize(0); - expectedError = TypeError; - } catch (_) { - expectedError = Test262Error; - } - }; - try { - new TargetCtor(source); - throw new Test262Error('the operation completed successfully'); - } catch (caught) { - actualError = caught; - } - - assert.sameValue(actualError.constructor, expectedError); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-same-type.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-same-type.js deleted file mode 100644 index c633ba06962..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-same-type.js +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2021 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Error when a TypedArray is created from another TypedArray with the same - element-type and SpeciesConstructor causes the "source" array to go - out-of-bounds. -includes: [testTypedArray.js, compareArray.js] -features: [TypedArray, Symbol.species, resizable-arraybuffer] ----*/ - -// If the host chooses to throw as allowed by the specification, the observed -// behavior will be identical to the case where `ArrayBuffer.prototype.resize` -// has not been implemented. The following assertion prevents this test from -// passing in runtimes which have not implemented the method. -assert.sameValue(typeof ArrayBuffer.prototype.resize, 'function'); - -testWithTypedArrayConstructors(function(TA) { - var BPE = TA.BYTES_PER_ELEMENT; - var ab = new ArrayBuffer(BPE * 4, {maxByteLength: BPE * 5}); - var speciesConstructor = Object.defineProperty(function(){}.bind(), 'prototype', { - get: function() { - return null; - } - }); - var onGetSpecies; - ab.constructor = Object.defineProperty({}, Symbol.species, { - get: function() { - onGetSpecies(); - return speciesConstructor; - } - }); - var source = new TA(ab, BPE); - var expected = [10, 20, 30]; - - source[0] = 10; - source[1] = 20; - source[2] = 30; - - onGetSpecies = function() { - try { - ab.resize(BPE * 5); - expected = [10, 20, 30, 0]; - } catch (_) {} - }; - - assert.sameValue((new TA(source)).join(','), expected.join(',')); - assert(compareArray(new TA(source), expected), 'following grow'); - - onGetSpecies = function() { - try { - ab.resize(BPE * 3); - expected = [10, 20]; - } catch (_) {} - }; - - assert(compareArray(new TA(source), expected), 'following shrink (within bounds)'); - - onGetSpecies = function() { - try { - ab.resize(BPE); - expected = []; - } catch (_) {} - }; - - assert(compareArray(new TA(source), expected), 'following shrink (on boundary)'); - - // `assert.throws` cannot be used in this case because the expected error - // is derived only after the constructor is invoked. - var expectedError; - var actualError; - onGetSpecies = function() { - try { - ab.resize(0); - expectedError = TypeError; - } catch (_) { - expectedError = Test262Error; - } - }; - try { - new TA(source); - throw new Test262Error('the operation completed successfully'); - } catch (caught) { - actualError = caught; - } - - assert.sameValue(actualError.constructor, expectedError); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-access-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-access-throws.js deleted file mode 100644 index f8e75d20916..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-access-throws.js +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from getting typedArray argument's buffer.constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... -includes: [testTypedArray.js] -features: [TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - Object.defineProperty(sample.buffer, "constructor", { - get: function() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js deleted file mode 100644 index 43743b956e7..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Derive the ArrayBuffer prototype from the realm of the species constructor -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... - - 9.1.14 GetPrototypeFromConstructor - - ... - 3. Let proto be ? Get(constructor, "prototype"). - 4. If Type(proto) is not Object, then - a. Let realm be ? GetFunctionRealm(constructor). - b. Let proto be realm's intrinsic object named intrinsicDefaultProto. - ... -includes: [testTypedArray.js] -features: [cross-realm, Symbol.species, TypedArray] ----*/ - -var other = $262.createRealm().global; -var C = new other.Function(); -C.prototype = null; - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = C; - - var typedArray = new TA(sample); - assert.sameValue( - Object.getPrototypeOf(typedArray.buffer), other.ArrayBuffer.prototype - ); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js deleted file mode 100644 index 7ed3aca0da1..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Use default ArrayBuffer constructor on undefined buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - var called = 0; - var custom = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function() { - called++; - }; - - ctor[Symbol.species].prototype = custom; - - var typedArray = new TA(sample); - assert.sameValue(Object.getPrototypeOf(typedArray.buffer), custom); - assert.sameValue(called, 0); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js deleted file mode 100644 index 2072aa96dd1..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - 8. Throw a TypeError exception. -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - var m = { m() {} }; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = m; - - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js deleted file mode 100644 index b171826cfb1..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from buffer.constructor.@@species.prototype -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - 8. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, cloneLength). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - 6. If S is either undefined or null, return defaultConstructor. - 7. If IsConstructor(S) is true, return S. - ... - - 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength ) - - ... - 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, - "%ArrayBufferPrototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] » ) - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - - ctor[Symbol.species] = function(){}.bind(null); - Object.defineProperty(ctor[Symbol.species], "prototype", { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-throws.js deleted file mode 100644 index ec2aaf3c1f5..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-throws.js +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt from getting typedArray argument's buffer.constructor.@@species -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 5. Let S be ? Get(C, @@species). - ... -includes: [testTypedArray.js] -features: [Symbol.species, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - var ctor = {}; - - sample.buffer.constructor = ctor; - Object.defineProperty(ctor, Symbol.species, { - get() { - throw new Test262Error(); - } - }); - - assert.throws(Test262Error, function() { - new TA(sample); - }); -}); diff --git a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js b/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js deleted file mode 100644 index ef97097495c..00000000000 --- a/test/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2016 the V8 project authors. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-typedarray-typedarray -description: > - Return abrupt completion from typedArray argument's buffer.constructor's value -info: | - 22.2.4.3 TypedArray ( typedArray ) - - This description applies only if the TypedArray function is called with at - least one argument and the Type of the first argument is Object and that - object has a [[TypedArrayName]] internal slot. - - ... - 17. If SameValue(elementType, srcType) is true, then - a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset). - ... - - 24.1.1.4 CloneArrayBuffer ( srcBuffer, srcByteOffset [ , cloneConstructor ] ) - - ... - 2. If cloneConstructor is not present, then - a. Let cloneConstructor be ? SpeciesConstructor(srcBuffer, %ArrayBuffer%). - ... - - 7.3.20 SpeciesConstructor ( O, defaultConstructor ) - - ... - 2. Let C be ? Get(O, "constructor"). - ... - 4. If Type(C) is not Object, throw a TypeError exception. - ... -includes: [testTypedArray.js] -features: [Symbol, TypedArray] ----*/ - -testWithTypedArrayConstructors(function(TA) { - var sample = new TA(); - - sample.buffer.constructor = 1; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = true; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = ''; - assert.throws(TypeError, function() { - new TA(sample); - }); - - sample.buffer.constructor = null; - assert.throws(TypeError, function() { - new TA(sample); - }); - - var s = Symbol('1'); - sample.buffer.constructor = s; - assert.throws(TypeError, function() { - new TA(sample); - }); -}); diff --git a/test/harness/temporalHelpers-one-shift-time-zone.js b/test/harness/temporalHelpers-one-shift-time-zone.js new file mode 100644 index 00000000000..db4e4102d0a --- /dev/null +++ b/test/harness/temporalHelpers-one-shift-time-zone.js @@ -0,0 +1,80 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Verify the time zone arithmetic used in TemporalHelpers.oneShiftTimeZone() + against known cases in the implementation's time zone database +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +function checkTimeZoneArithmetic(shiftInstant, shiftNs, realTimeZoneName, shiftWallTime) { + // No need to test this on hosts that don't provide an Intl object. It's + // sufficient that the logic is tested on at least one host. + if (typeof globalThis.Intl === "undefined") + return; + + const tz = TemporalHelpers.oneShiftTimeZone(shiftInstant, shiftNs); + const realTz = new Temporal.TimeZone(realTimeZoneName); + + assert.sameValue( + tz.getOffsetNanosecondsFor(shiftInstant), + realTz.getOffsetNanosecondsFor(shiftInstant), + 'offset at shift instant' + ); + const minus1 = shiftInstant.subtract({ hours: 1 }); + assert.sameValue( + tz.getOffsetNanosecondsFor(minus1), + realTz.getOffsetNanosecondsFor(minus1), + 'offset at 1 hour before shift' + ); + const plus1 = shiftInstant.add({ hours: 1 }); + assert.sameValue( + tz.getOffsetNanosecondsFor(plus1), + realTz.getOffsetNanosecondsFor(plus1), + 'offset at 1 hour after shift' + ); + + assert.compareArray( + tz.getPossibleInstantsFor(shiftWallTime).map((i) => i.epochNanoseconds), + realTz.getPossibleInstantsFor(shiftWallTime).map((i) => i.epochNanoseconds), + 'possible instants for wall time' + ); + const before1 = shiftWallTime.subtract({ hours: 1 }); + assert.compareArray( + tz.getPossibleInstantsFor(before1).map((i) => i.epochNanoseconds), + realTz.getPossibleInstantsFor(before1).map((i) => i.epochNanoseconds), + 'possible instants for 1 hour before wall time' + ); + const after1 = shiftWallTime.add({ hours: 1 }); + assert.compareArray( + tz.getPossibleInstantsFor(after1).map((i) => i.epochNanoseconds), + realTz.getPossibleInstantsFor(after1).map((i) => i.epochNanoseconds), + 'possible instants for 1 hour after wall time' + ); +} + +// Check a positive DST shift from +00:00 to +01:00 +checkTimeZoneArithmetic( + new Temporal.Instant(1616893200000000000n), + 3600e9, + 'Europe/London', + new Temporal.PlainDateTime(2021, 3, 28, 1) +); + +// Check a negative DST shift from +00:00 to -01:00 +checkTimeZoneArithmetic( + new Temporal.Instant(1635642000000000000n), + -3600e9, + 'Atlantic/Azores', + new Temporal.PlainDateTime(2021, 10, 31, 1) +); + +// Check the no-shift case +checkTimeZoneArithmetic( + new Temporal.Instant(0n), + 0, + 'UTC', + new Temporal.PlainDateTime(1970, 1, 1) +); diff --git a/test/intl402/NumberFormat/constructor-roundingIncrement-invalid.js b/test/intl402/NumberFormat/constructor-roundingIncrement-invalid.js index 1274a0daac7..e92266498e4 100644 --- a/test/intl402/NumberFormat/constructor-roundingIncrement-invalid.js +++ b/test/intl402/NumberFormat/constructor-roundingIncrement-invalid.js @@ -1,4 +1,5 @@ // Copyright 2021 the V8 project authors. All rights reserved. +// Copyright (C) 2022 Igalia, S.L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- esid: sec-initializenumberformat @@ -26,14 +27,18 @@ assert.throws(RangeError, function() { new Intl.NumberFormat([], {roundingIncrement: 5001}); }, '5001'); -assert.throws(RangeError, function() { +assert.throws(TypeError, function() { new Intl.NumberFormat([], {roundingIncrement: 2, roundingPriority: 'morePrecision'}); }, '2, roundingType is "morePrecision"'); -assert.throws(RangeError, function() { +assert.throws(TypeError, function() { new Intl.NumberFormat([], {roundingIncrement: 2, roundingPriority: 'lessPrecision'}); }, '2, roundingType is "lessPrecision"'); -assert.throws(RangeError, function() { +assert.throws(TypeError, function() { new Intl.NumberFormat([], {roundingIncrement: 2, minimumSignificantDigits: 1}); }, '2, roundingType is "significantDigits"'); + +assert.throws(RangeError, function() { + new Intl.NumberFormat([], {roundingIncrement: 2, maximumFractionDigits:3 , minimumFractionDigits:2 }); +}, '"maximumFractionDigits" is not equal to "minimumFractionDigits"'); diff --git a/test/intl402/Temporal/Calendar/prototype/era/argument-string-invalid.js b/test/intl402/Temporal/Calendar/prototype/era/argument-string-invalid.js new file mode 100644 index 00000000000..b7a6b5c0bc1 --- /dev/null +++ b/test/intl402/Temporal/Calendar/prototype/era/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.era +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.era(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/intl402/Temporal/Calendar/prototype/era/calendar-datefromfields-called-with-options-undefined.js b/test/intl402/Temporal/Calendar/prototype/era/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..eb1e61d9b19 --- /dev/null +++ b/test/intl402/Temporal/Calendar/prototype/era/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.era +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.era({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/intl402/Temporal/Calendar/prototype/eraYear/argument-string-invalid.js b/test/intl402/Temporal/Calendar/prototype/eraYear/argument-string-invalid.js new file mode 100644 index 00000000000..6b3f65b9ea4 --- /dev/null +++ b/test/intl402/Temporal/Calendar/prototype/eraYear/argument-string-invalid.js @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.erayear +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.Calendar("iso8601"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.eraYear(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} diff --git a/test/intl402/Temporal/Calendar/prototype/eraYear/calendar-datefromfields-called-with-options-undefined.js b/test/intl402/Temporal/Calendar/prototype/eraYear/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 00000000000..a2c9fa6645e --- /dev/null +++ b/test/intl402/Temporal/Calendar/prototype/eraYear/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,15 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.calendar.prototype.erayear +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +calendar.eraYear({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); diff --git a/test/intl402/Temporal/Instant/prototype/toString/timezone-offset.js b/test/intl402/Temporal/Instant/prototype/toString/timezone-offset.js new file mode 100644 index 00000000000..ee2bd1e5fba --- /dev/null +++ b/test/intl402/Temporal/Instant/prototype/toString/timezone-offset.js @@ -0,0 +1,19 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.instant.prototype.tostring +description: The time zone offset part of the string serialization (Intl time zones) +features: [BigInt, Temporal] +---*/ + +const instant = new Temporal.Instant(0n); + +function test(timeZoneIdentifier, expected, description) { + const timeZone = new Temporal.TimeZone(timeZoneIdentifier); + assert.sameValue(instant.toString({ timeZone }), expected, description); +} + +test("Europe/Berlin", "1970-01-01T01:00:00+01:00", "positive offset"); +test("America/New_York", "1969-12-31T19:00:00-05:00", "negative offset"); +test("Africa/Monrovia", "1969-12-31T23:15:30-00:45", "sub-minute offset"); diff --git a/test/intl402/Temporal/TimeZone/etc-timezone.js b/test/intl402/Temporal/TimeZone/etc-timezone.js new file mode 100644 index 00000000000..b3995e5f4ca --- /dev/null +++ b/test/intl402/Temporal/TimeZone/etc-timezone.js @@ -0,0 +1,79 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone +description: Some Etc/GMT{+/-}{0}N timezones are valid, but not all +features: [Temporal] +---*/ + +// "Etc/GMT-0" through "Etc/GMT-14" are OK + +assert.sameValue( + (new Temporal.TimeZone("Etc/GMT-0")).toString(), + "UTC", // if the offset is -0, we say "UTC" rather than "GMT" + "Etc/GMT-0 is a valid timezone" +); + +[1,2,3,4,5,6,7,8,9,10,11,12,13,14].forEach((n) => { + let tz = "Etc/GMT-" + n; + let instance = new Temporal.TimeZone(tz); + assert.sameValue( + instance.toString(), + tz, + tz + " is a valid timezone" + ); +}); + +let gmtMinus24TZ = "Etc/GMT-24"; +assert.throws( + RangeError, + () => { new Temporal.TimeZone(gmtMinus24TZ); }, + gmtMinus24TZ + " is an invalid timezone" +); + +// "Etc/GMT-0N" is not OK (1 ≤ N ≤ 9) +[1,2,3,4,5,6,7,8,9].forEach((n) => { + let tz = "Etc/GMT-0" + n; + assert.throws( + RangeError, + () => { new Temporal.TimeZone(tz); }, + tz + " is an invalid timezone" + ); +}); + +// "Etc/GMT+0N" is not OK (0 ≤ N ≤ 9) +[0,1,2,3,4,5,6,7,8,9].forEach((n) => { + let tz = "Etc/GMT+0" + n; + assert.throws( + RangeError, + () => { new Temporal.TimeZone(tz); }, + tz + " is an invalid timezone" + ); +}); + +// Etc/GMT+0" through "Etc/GMT+12" are OK + +// zero is handled in its own way (say "UTC" rather than "GMT"): +assert.sameValue( + (new Temporal.TimeZone("Etc/GMT+0")).toString(), + "UTC", // if the offset is +0, we say "UTC" rather than "GMT" + "Etc/GMT+0 is a valid timezone" +); + +[1,2,3,4,5,6,7,8,9,10,11,12].forEach((n) => { + let tz = "Etc/GMT+" + n; + let instance = new Temporal.TimeZone(tz); + assert.sameValue( + instance.toString(), + tz, + tz + " is a valid timezone" + ); +}); + +let gmtPlus24TZ = "Etc/GMT+24"; +assert.throws( + RangeError, + () => { new Temporal.TimeZone(gmtPlus24TZ); }, + gmtPlus24TZ + " is an invalid timezone" +); diff --git a/test/language/expressions/unary-plus/S11.4.6_A3_T3.js b/test/language/expressions/unary-plus/S11.4.6_A3_T3.js index 79bf732a2f2..9a3a2f6b49f 100644 --- a/test/language/expressions/unary-plus/S11.4.6_A3_T3.js +++ b/test/language/expressions/unary-plus/S11.4.6_A3_T3.js @@ -13,11 +13,21 @@ if (+"1" !== 1) { } //CHECK#2 -if (isNaN(+"x") !== true) { - throw new Test262Error('#2: +"x" === Not-a-Number. Actual: ' + (+"x")); +if (+new Number("-1") !== -1) { + throw new Test262Error('#2: +new String("-1") === -1. Actual: ' + (+new String("-1"))); } //CHECK#3 -if (+new Number("-1") !== -1) { - throw new Test262Error('#3: +new String("-1") === -1. Actual: ' + (+new String("-1"))); +if (isNaN(+"x") !== true) { + throw new Test262Error('#3: +"x" === Not-a-Number. Actual: ' + (+"x")); +} + +//CHECK#4 +if (isNaN(+"INFINITY") !== true) { + throw new Test262Error('#4: +"INFINITY" === Not-a-Number. Actual: ' + (+"INFINITY")); +} + +//CHECK#5 +if (isNaN(+"infinity") !== true) { + throw new Test262Error('#5: +"infinity" === Not-a-Number. Actual: ' + (+"infinity")); } diff --git a/test/language/statements/for-in/S12.6.4_A7_T2.js b/test/language/statements/for-in/S12.6.4_A7_T2.js index 4ae8a3946ec..b7043d78b4a 100644 --- a/test/language/statements/for-in/S12.6.4_A7_T2.js +++ b/test/language/statements/for-in/S12.6.4_A7_T2.js @@ -13,7 +13,10 @@ description: > var __obj, __accum; -__obj={aa:1,ba:2,ca:3}; +__obj = Object.create(null); +__obj.aa = 1; +__obj.ba = 2; +__obj.ca = 3; __accum=""; @@ -25,23 +28,10 @@ for (var __key in __obj){ } - -////////////////////////////////////////////////////////////////////////////// -//CHECK#1 -if (!((__accum.indexOf("aa1")!==-1)&&(__accum.indexOf("ca3")!==-1))) { - throw new Test262Error('#1: (__accum.indexOf("aa1")!==-1)&&(__accum.indexOf("ca3")!==-1)'); -} -// -////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// -//CHECK#2 -if (__accum.indexOf("ba2")!==-1) { - throw new Test262Error('#2: __accum.indexOf("ba2") === -1. Actual: __accum.indexOf("ba2") ==='+ __accum.indexOf("ba2") ); -} -// -////////////////////////////////////////////////////////////////////////////// - +assert( + __accum === "aa1ca3" || __accum === "ca3aa1", + "Unexpected value: '" + __accum + "'" +); // erasator is the hash map terminator function erasator_T_1000(hash_map, charactr){