diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/built-ins/Temporal/PlainYearMonth | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/PlainYearMonth')
624 files changed, 17970 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/basic.js new file mode 100644 index 0000000000..89df253b7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/basic.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: PlainYearMonth constructor works +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = new Temporal.PlainYearMonth(1976, 11); +assert.sameValue(typeof ym, "object"); +TemporalHelpers.assertPlainYearMonth(ym, 1976, 11, "M11"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/builtin.js new file mode 100644 index 0000000000..ec3397b9a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/builtin.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Tests that Temporal.PlainYearMonth meets the requirements for built-in objects +info: | + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth), + Function.prototype, "prototype"); + +assert.sameValue(typeof Temporal.PlainYearMonth.prototype, + "object", "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-always.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-always.js new file mode 100644 index 0000000000..bfc3f7c978 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-always.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-case-insensitive.js new file mode 100644 index 0000000000..d3465f7957 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-case-insensitive.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Calendar names are case-insensitive +features: [Temporal] +---*/ + +const arg = "iSo8601"; + +const result = new Temporal.PlainYearMonth(2000, 5, arg, 1); +assert.sameValue(result.calendarId, "iso8601", "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-invalid.js new file mode 100644 index 0000000000..b5c69e0d04 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-invalid.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth throws a RangeError if the calendar argument is invalid +esid: sec-temporal.plainyearmonth +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf"]; +const actual = []; +const args = [ + TemporalHelpers.toPrimitiveObserver(actual, 1970, "year"), + TemporalHelpers.toPrimitiveObserver(actual, 1, "month"), + "local", + TemporalHelpers.toPrimitiveObserver(actual, 1, "day") +]; +assert.throws(RangeError, () => new Temporal.PlainYearMonth(...args)); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-number.js new file mode 100644 index 0000000000..dc11586ee5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-number.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is not allowed to be a calendar +features: [Temporal] +---*/ + +const numbers = [ + 1, + -19761118, + 19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => new Temporal.PlainYearMonth(2000, 5, arg, 1), + "A number is not a valid ISO string for Calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-string.js new file mode 100644 index 0000000000..3d8417dd83 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.constructor +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const arg = "iso8601"; + +const result = new Temporal.PlainYearMonth(2000, 5, arg, 1); +assert.sameValue(result.getISOFields().calendar, "iso8601", `Calendar created from string "${arg}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-temporal-object.js new file mode 100644 index 0000000000..501c0b44a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-temporal-object.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal-totemporalcalendar step 1.b: + b. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(2000, 5, 2); +const plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const plainMonthDay = new Temporal.PlainMonthDay(5, 2); +const plainYearMonth = new Temporal.PlainYearMonth(2000, 5); +const zonedDateTime = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"); + +[plainDate, plainDateTime, plainMonthDay, plainYearMonth, zonedDateTime].forEach((arg) => { + const actual = []; + const expected = []; + + const calendar = arg.getISOFields().calendar; + + Object.defineProperty(arg, "calendar", { + get() { + actual.push("get calendar"); + return calendar; + }, + }); + + const result = new Temporal.PlainYearMonth(2000, 5, arg, 1); + assert.sameValue(result.getISOFields().calendar, calendar, "Temporal object coerced to calendar"); + + assert.compareArray(actual, expected, "calendar getter not called"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-undefined.js new file mode 100644 index 0000000000..317f57a426 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-undefined.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Calendar argument defaults to the built-in ISO 8601 calendar +features: [Temporal] +---*/ + +const args = [2000, 5]; + +Object.defineProperty(Temporal.Calendar, "from", { + get() { + throw new Test262Error("Should not get Calendar.from"); + }, +}); + +const dateExplicit = new Temporal.PlainYearMonth(...args, undefined); +assert.sameValue(dateExplicit.calendarId, "iso8601"); + +const dateImplicit = new Temporal.PlainYearMonth(...args); +assert.sameValue(dateImplicit.calendarId, "iso8601"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-wrong-type.js new file mode 100644 index 0000000000..1bbf456ce8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/calendar-wrong-type.js @@ -0,0 +1,40 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or object for Calendar +features: [BigInt, Symbol, Temporal] +---*/ + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => new Temporal.PlainYearMonth(2000, 5, arg, 1), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => new Temporal.PlainYearMonth(2000, 5, arg, 1), `${description} is not a valid object and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..1ac34ed0c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-builtin-calendar-no-array-iteration.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method with a property bag argument with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const arg = { year: 2000, month: 5, calendar: "iso8601" }; +Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)); +Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-cast.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-cast.js new file mode 100644 index 0000000000..4f98ccb77c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-cast.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: compare() casts its arguments +features: [Temporal] +---*/ + +const nov94 = Temporal.PlainYearMonth.from("1994-11"); +const jun13 = Temporal.PlainYearMonth.from("2013-06"); + +assert.sameValue(Temporal.PlainYearMonth.compare({ year: 1994, month: 11 }, jun13), -1, "one object"); +assert.sameValue(Temporal.PlainYearMonth.compare("1994-11", jun13), -1, "one string"); +assert.throws(TypeError, () => Temporal.PlainYearMonth.compare({ year: 1994 }, jun13), "one missing property"); + +assert.sameValue(Temporal.PlainYearMonth.compare(nov94, { year: 2013, month: 6 }), -1, "two object"); +assert.sameValue(Temporal.PlainYearMonth.compare(nov94, "2013-06"), -1, "two string"); +assert.throws(TypeError, () => Temporal.PlainYearMonth.compare(nov94, { year: 2013 }), "two missing property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-number.js new file mode 100644 index 0000000000..6381187105 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-number.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is invalid in place of an ISO string for Temporal.PlainYearMonth +features: [Temporal] +---*/ + +const arg = 201906; + +const numbers = [ + 1, + 201906, + -201906, + 1234567, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `A number (${arg}) is not a valid ISO string for PlainYearMonth (first argument)` + ); + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `A number (${arg}) is not a valid ISO string for PlainYearMonth (first argument)` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..c37f433a64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-case-insensitive.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const calendar = "IsO8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result1 = Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)); +assert.sameValue(result1, 0, "Calendar is case-insensitive (first argument)"); +const result2 = Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg); +assert.sameValue(result2, 0, "Calendar is case-insensitive (second argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..47e6492289 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-leap-second.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for a calendar in a property bag +features: [Temporal] +---*/ + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result1 = Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)); +assert.sameValue( + result1, + 0, + "leap second is a valid ISO string for calendar (first argument)" +); +const result2 = Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg); +assert.sameValue( + result2, + 0, + "leap second is a valid ISO string for calendar (second argument)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..9db6ff73d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-number.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; + +for (const calendar of numbers) { + const arg = { year: 2019, monthCode: "M06", calendar }; + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + "A number is not a valid ISO string for calendar (first argument)" + ); + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + "A number is not a valid ISO string for calendar (second argument)" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..d757e80b1e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-string.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dateFromFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateFromFields"); +Object.defineProperty(Temporal.Calendar.prototype, "dateFromFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateFromFields should not be looked up"); + }, +}); + +const calendar = "iso8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; + +const result1 = Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)); +assert.sameValue(result1, 0, `Calendar created from string "${arg}" (first argument)`); + +const result2 = Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg); +assert.sameValue(result2, 0, `Calendar created from string "${arg}" (second argument)`); + +Object.defineProperty(Temporal.Calendar.prototype, "dateFromFields", dateFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..bed5c45623 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-wrong-type.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when a calendar property from a property bag cannot + be converted to a calendar object or string +features: [BigInt, Symbol, Temporal] +---*/ + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [calendar, description] of primitiveTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws( + typeof calendar === "string" ? RangeError : TypeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `${description} does not convert to a valid ISO string (first argument)` + ); + assert.throws( + typeof calendar === "string" ? RangeError : TypeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `${description} does not convert to a valid ISO string (second argument)` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], + [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields() +]; + +for (const [calendar, description] of typeErrorTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws(TypeError, () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), `${description} is not a valid property bag and does not convert to a string (first argument)`); + assert.throws(TypeError, () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), `${description} is not a valid property bag and does not convert to a string (second argument)`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..6ecb7deff3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-propertybag-calendar-year-zero.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T17:45", + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+01:00", + "-000000-10-31T17:45+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + "reject minus zero as extended year (first argument)" + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + "reject minus zero as extended year (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..8b6f2f790c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-calendar-annotation.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[u-ca=iso8601]", "without time zone"], + ["2019-12-15T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2019-12-15T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2019-12-15T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2019-12-15T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.compare(arg, arg); + + assert.sameValue( + result, + 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..cf8b20edca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-critical-unknown-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `reject unknown annotation with critical flag: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `reject unknown annotation with critical flag: ${arg} (second argument)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..3375a84db3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-date-with-utc-offset.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const validStrings = [ + "2019-12[Africa/Abidjan]", + "2019-12[!Africa/Abidjan]", + "2019-12[u-ca=iso8601]", + "2019-12[Africa/Abidjan][u-ca=iso8601]", + "2019-12-15T00+00:00", + "2019-12-15T00+00:00[UTC]", + "2019-12-15T00+00:00[!UTC]", + "2019-12-15T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = Temporal.PlainYearMonth.compare(arg, arg); + + assert.sameValue( + result, + 0, + `"${arg}" is a valid UTC offset with time for PlainYearMonth` + ); +} + +const invalidStrings = [ + "2022-09[u-ca=hebrew]", + "2022-09Z", + "2022-09+01:00", + "2022-09-15Z", + "2022-09-15Z[UTC]", + "2022-09-15Z[Europe/Vienna]", + "2022-09-15+00:00", + "2022-09-15+00:00[UTC]", + "2022-09-15-02:30", + "2022-09-15-02:30[America/St_Johns]", +]; + +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `"${arg}" UTC offset without time is not valid for PlainYearMonth (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `"${arg}" UTC offset without time is not valid for PlainYearMonth (second argument)` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-invalid.js new file mode 100644 index 0000000000..26c2f8b2c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-invalid.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An invalid ISO string is never supported +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const arg2 = new Temporal.PlainYearMonth(1976, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsInvalid()) { + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(arg, arg2), `"${arg}" is invalid (first argument)`); + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(arg2, arg), `"${arg}" is invalid (second argument)`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..d29e88d68b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-calendar.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `reject more than one calendar annotation if any critical: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `reject more than one calendar annotation if any critical: ${arg} (second argument)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..fecfb4bc40 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-multiple-time-zone.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `reject more than one time zone annotation: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `reject more than one time zone annotation: ${arg} (second argument)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-separators.js new file mode 100644 index 0000000000..8307aacff7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-separators.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Time separator in string argument can vary +features: [Temporal] +---*/ + +const yearMonth = new Temporal.PlainYearMonth(2019, 12); +const tests = [ + ["2019-12-15T15:23", "uppercase T"], + ["2019-12-15t15:23", "lowercase T"], + ["2019-12-15 15:23", "space between date and time"], +]; + +tests.forEach(([arg, description]) => { + assert.sameValue( + Temporal.PlainYearMonth.compare(arg, yearMonth), + 0, + `variant time separators (${description}), first argument` + ); + + assert.sameValue( + Temporal.PlainYearMonth.compare(yearMonth, arg), + 0, + `variant time separators (${description}), second argument` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..e2af75b112 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-time-zone-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[Asia/Kolkata]", "named, with no offset"], + ["2019-12-15T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["2019-12-15T15:23[+00:00]", "numeric, with no offset"], + ["2019-12-15T15:23[!-02:30]", "numeric, with ! and no offset"], + ["2019-12-15T15:23+00:00[UTC]", "named, with offset"], + ["2019-12-15T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["2019-12-15T15:23+00:00[+01:00]", "numeric, with offset"], + ["2019-12-15T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.compare(arg, arg); + + assert.sameValue( + result, + 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..eb501cfc7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-unknown-annotation.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[foo=bar]", "alone"], + ["2019-12-15T15:23[UTC][foo=bar]", "with time zone"], + ["2019-12-15T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2019-12-15T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2019-12-15T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.compare(arg, arg); + + assert.sameValue( + result, + 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..2b3687fc43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string-with-utc-designator.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: RangeError thrown if a string with UTC designator is used as a PlainYearMonth +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const yearMonth = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, yearMonth), + "String with UTC designator should not be valid as a PlainYearMonth (first argument)" + ); + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(yearMonth, arg), + "String with UTC designator should not be valid as a PlainYearMonth (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string.js new file mode 100644 index 0000000000..3cd77be14c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-string.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const validStrings = TemporalHelpers.ISO.plainYearMonthStringsValid().concat(TemporalHelpers.ISO.plainYearMonthStringsValidNegativeYear()); + +for (const arg of validStrings) { + assert.sameValue( + Temporal.PlainYearMonth.compare(arg, arg), + 0, + `"${arg}" is a valid PlainYearMonth string` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-wrong-type.js new file mode 100644 index 0000000000..1f6ae998ed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/argument-wrong-type.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainYearMonth +features: [BigInt, Symbol, Temporal] +---*/ + +const primitiveTests = [ + [undefined, "undefined"], + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), + `${description} does not convert to a valid ISO string (first argument)` + ); + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), + `${description} does not convert to a valid ISO string (second argument)` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth, object"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6)), `${description} is not a valid property bag and does not convert to a string (first argument)`); + assert.throws(TypeError, () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg), `${description} is not a valid property bag and does not convert to a string (second argument)`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/basic.js new file mode 100644 index 0000000000..704b0177e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/basic.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Basic tests for compare() +features: [Temporal] +---*/ + +const nov94 = Temporal.PlainYearMonth.from("1994-11"); +const nov94bis = Temporal.PlainYearMonth.from("1994-11"); +const jun13 = Temporal.PlainYearMonth.from("2013-06"); +assert.sameValue(Temporal.PlainYearMonth.compare(nov94, nov94), 0, "same object"); +assert.sameValue(Temporal.PlainYearMonth.compare(nov94, nov94bis), 0, "different object"); +assert.sameValue(Temporal.PlainYearMonth.compare(nov94, jun13), -1, "before"); +assert.sameValue(Temporal.PlainYearMonth.compare(jun13, nov94), 1, "after"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/builtin.js new file mode 100644 index 0000000000..bef5d9ad97 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/builtin.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: Tests that Temporal.PlainYearMonth.compare meets the requirements for built-in objects +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.compare), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.compare), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.compare), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.compare.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..4591181208 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const arg1 = { year: 2000, month: 5, calendar }; +const arg2 = new Temporal.PlainYearMonth(2019, 6); + +Temporal.PlainYearMonth.compare(arg1, arg2); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar (first argument)"); + +calendar.yearMonthFromFieldsCallCount = 0; + +Temporal.PlainYearMonth.compare(arg2, arg1); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar (second argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-fields-iterable.js new file mode 100644 index 0000000000..a4e08ca12f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-fields-iterable.js @@ -0,0 +1,40 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.compare steps 1–2: + 1. Set _one_ to ? ToTemporalYearMonth(_one_). + 2. Set _two_ to ? ToTemporalYearMonth(_two_). + sec-temporal-totemporalyearmonth step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +Temporal.PlainYearMonth.compare( + { year: 2000, month: 5, calendar: calendar1 }, + { year: 2001, month: 6, calendar: calendar2 }, +); + +assert.sameValue(calendar1.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar1.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar1.iteratorExhausted[0], "iterated through the whole iterable"); +assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-temporal-object.js new file mode 100644 index 0000000000..60b3f7026d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-temporal-object.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plainyearmonth.compare steps 1–2: + 1. Set _one_ to ? ToTemporalYearMonth(_one_). + 2. Set _two_ to ? ToTemporalYearMonth(_two_). + sec-temporal-totemporaldate step 2.b: + b. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_). + sec-temporal-gettemporalcalendarwithisodefault step 2: + 2. Return ? ToTemporalCalendarWithISODefault(_calendar_). + sec-temporal-totemporalcalendarwithisodefault step 2: + 3. Return ? ToTemporalCalendar(_temporalCalendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => { + Temporal.PlainYearMonth.compare( + { year: 2000, month: 5, calendar: temporalObject }, + { year: 2001, month: 6, calendar: temporalObject }, + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..ee9fe4aae1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-calendar.js new file mode 100644 index 0000000000..46bab4df8c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-calendar.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: compare() does not take the calendar into account +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this._id = id; + } + toString() { + return this._id; + } +} + +const ym1 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("a"), 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("b"), 1); +assert.sameValue(Temporal.PlainYearMonth.compare(ym1, ym2), 0); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-reference-day.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-reference-day.js new file mode 100644 index 0000000000..91d93770c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/compare-reference-day.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: compare() takes the reference day into account +features: [Temporal] +---*/ + +const iso = Temporal.Calendar.from("iso8601"); +const ym1 = new Temporal.PlainYearMonth(2000, 1, iso, 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, iso, 2); +assert.sameValue(Temporal.PlainYearMonth.compare(ym1, ym2), -1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..ae2f23fafb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.compare +description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; + +assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6))); +assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/duplicate-calendar-fields.js new file mode 100644 index 0000000000..ae032c2fef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/duplicate-calendar-fields.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.compare +description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + + +for (const extra_fields of [['foo', 'foo'], ['month'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6))); + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/exhaustive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/exhaustive.js new file mode 100644 index 0000000000..38dd3eb88e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/exhaustive.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Tests for compare() with each possible outcome +features: [Temporal] +---*/ + +const cal1 = "iso8601"; +const cal2 = new (class extends Temporal.Calendar { id = "custom"; })("iso8601"); + +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2000, 5, cal1), new Temporal.PlainYearMonth(1987, 5, cal2)), + 1, + "year >" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(1981, 12, cal1), new Temporal.PlainYearMonth(2048, 12, cal2)), + -1, + "year <" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2000, 5, cal1), new Temporal.PlainYearMonth(2000, 3, cal2)), + 1, + "month >" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(1981, 4, cal1), new Temporal.PlainYearMonth(1981, 12, cal2)), + -1, + "month <" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2000, 5, cal1, 30), new Temporal.PlainYearMonth(2000, 5, cal2, 14)), + 1, + "reference day >" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(1981, 4, cal1, 1), new Temporal.PlainYearMonth(1981, 4, cal2, 12)), + -1, + "reference day <" +); +assert.sameValue( + Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2000, 5, cal1), new Temporal.PlainYearMonth(2000, 5, cal2)), + 0, + "=" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..6d55f794e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/infinity-throws-rangeerror.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in a property bag for either argument is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.compare +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const other = new Temporal.PlainYearMonth(2000, 5); +const base = { year: 2000, month: 5 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare({ ...base, [prop]: inf }, other), `${prop} property cannot be ${inf}`); + + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(other, { ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls1 = []; + const obj1 = TemporalHelpers.toPrimitiveObserver(calls1, inf, prop); + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare({ ...base, [prop]: obj1 }, other)); + assert.compareArray(calls1, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + + const calls2 = []; + const obj2 = TemporalHelpers.toPrimitiveObserver(calls2, inf, prop); + assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(other, { ...base, [prop]: obj2 })); + assert.compareArray(calls2, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/leap-second.js new file mode 100644 index 0000000000..ab971deb60 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/leap-second.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for PlainYearMonth +features: [Temporal] +---*/ + +let arg = "2016-12-31T23:59:60"; + +const result1 = Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2016, 12)); +assert.sameValue(result1, 0, "leap second is a valid ISO string for PlainYearMonth (first argument)"); +const result2 = Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2016, 12), arg); +assert.sameValue(result2, 0, "leap second is a valid ISO string for PlainYearMonth (second argument)"); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; + +const result3 = Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2016, 12)); +assert.sameValue(result3, 0, "second: 60 is ignored in property bag for PlainYearMonth (first argument)"); +const result4 = Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2016, 12), arg); +assert.sameValue(result4, 0, "second: 60 is ignored in property bag for PlainYearMonth (second argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/length.js new file mode 100644 index 0000000000..dedfbae35d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.compare.length is 2 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.compare, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/name.js new file mode 100644 index 0000000000..a76b7a59e8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.compare.name is "compare". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.compare, "name", { + value: "compare", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/not-a-constructor.js new file mode 100644 index 0000000000..d83397671c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/not-a-constructor.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: Temporal.PlainYearMonth.compare does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.compare(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.compare), false, + "isConstructor(Temporal.PlainYearMonth.compare)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/prop-desc.js new file mode 100644 index 0000000000..a8a01f21da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.compare +description: The "compare" property of Temporal.PlainYearMonth +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.compare, + "function", + "`typeof PlainYearMonth.compare` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth, "compare", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/proto-in-calendar-fields.js new file mode 100644 index 0000000000..d7757e3a18 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.compare +description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; + +assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(arg, new Temporal.PlainYearMonth(2019, 6))); +assert.throws(RangeError, () => Temporal.PlainYearMonth.compare(new Temporal.PlainYearMonth(2019, 6), arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/use-internal-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/use-internal-slots.js new file mode 100644 index 0000000000..95f9927c41 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/use-internal-slots.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: compare() ignores the observable properties and uses internal slots +features: [Temporal] +---*/ + +function CustomError() {} + +class AvoidGettersYearMonth extends Temporal.PlainYearMonth { + get year() { + throw new CustomError(); + } + get month() { + throw new CustomError(); + } +} + +const one = new AvoidGettersYearMonth(2000, 5); +const two = new AvoidGettersYearMonth(2006, 3); +assert.sameValue(Temporal.PlainYearMonth.compare(one, two), -1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/year-zero.js new file mode 100644 index 0000000000..50486522de --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/compare/year-zero.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Negative zero, as an extended year, fails +esid: sec-temporal.plainyearmonth.compare +features: [Temporal] +---*/ + +const ok = new Temporal.PlainYearMonth(2000, 5); +const invalidStrings = [ + "-000000-06", + "-000000-06-24", + "-000000-06-24T15:43:27", + "-000000-06-24T15:43:27+01:00", + "-000000-06-24T15:43:27+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(arg, ok), + "Cannot use minus zero as extended year (first argument)" + ); + + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.compare(ok, arg), + "Cannot use minus zero as extended year (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/constructor.js new file mode 100644 index 0000000000..7b94464b55 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/constructor.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Temporal.PlainYearMonth constructor cannot be called as a function +info: | + 1. If NewTarget is undefined, throw a TypeError exception. +features: [Temporal] +---*/ + +assert.throws(TypeError, () => Temporal.PlainYearMonth(1970, 1)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..84532a349e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method with a property bag argument with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const arg = { year: 2000, month: 5, calendar: "iso8601" }; +Temporal.PlainYearMonth.from(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-number.js new file mode 100644 index 0000000000..d4e9bb0eae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-number.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is invalid in place of an ISO string for Temporal.PlainYearMonth +features: [Temporal] +---*/ + +const numbers = [ + 1, + 201906, + -201906, + 1234567, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.from(arg), + `A number (${arg}) is not a valid ISO string for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-object.js new file mode 100644 index 0000000000..9c63069bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-object.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An object argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from({ year: 2019, monthCode: "M11" }), + 2019, 11, "M11", "Only monthCode"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from({ year: 2019, month: 11 }), + 2019, 11, "M11", "Only month"); +assert.throws(RangeError, + () => Temporal.PlainYearMonth.from({ year: 2019, month: 11, monthCode: "M12" }), + "Mismatch between month and monthCode"); + +const monthDayItem = { year: 2019, month: 11, get day() { throw new Test262Error("should not read the day property") } }; +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from(monthDayItem), + 2019, 11, "M11", "month with day"); + +const monthCodeDayItem = { year: 2019, monthCode: "M11", get day() { throw new Test262Error("should not read the day property") } }; +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from(monthCodeDayItem), + 2019, 11, "M11", "monthCode with day"); + +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({}), + "No properties"); +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({ year: 2019 }), + "Only year"); +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({ year: 2019, months: 6 }), + "Year and plural 'months'"); +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({ month: 6 }), + "Only month"); +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({ monthCode: "M06" }), + "Only monthCode"); +assert.throws(TypeError, + () => Temporal.PlainYearMonth.from({ year: undefined, month: 6 }), + "year explicit undefined"); + +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from({ year: 1976, month: 11, months: 12 }), + 1976, 11, "M11", "Plural property ignored"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plaindate.js new file mode 100644 index 0000000000..05becd1028 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plaindate.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A PlainYearMonth argument is cloned +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = Temporal.PlainDate.from("1976-11-18"); +const plainYearMonth = Temporal.PlainYearMonth.from(plainDate); +TemporalHelpers.assertPlainYearMonth(plainYearMonth, 1976, 11, "M11"); +const fields = plainYearMonth.getISOFields(); +assert.sameValue(fields.calendar, "iso8601", "calendar slot should store a string"); +assert.sameValue(fields.isoDay, 1, "isoDay"); +assert.sameValue(fields.isoMonth, 11, "isoMonth"); +assert.sameValue(fields.isoYear, 1976, "isoYear"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plainyearmonth.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plainyearmonth.js new file mode 100644 index 0000000000..23d8832f2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-plainyearmonth.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A PlainYearMonth object is copied, not returned directly +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const orig = new Temporal.PlainYearMonth(2000, 5, undefined, 7); +const result = Temporal.PlainYearMonth.from(orig); + +TemporalHelpers.assertPlainYearMonth( + result, + 2000, 5, "M05", + "PlainYearMonth is copied", + /* era = */ undefined, /* eraYear = */ undefined, /* isoDay = */ 7 +); + +assert.sameValue(result.getISOFields().calendar, orig.getISOFields().calendar, "Calendar is copied"); + +assert.notSameValue( + result, + orig, + "When a PlainYearMonth is given, the returned value is not the original PlainYearMonth" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..1b09db947a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-case-insensitive.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = "IsO8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = Temporal.PlainYearMonth.from(arg); +TemporalHelpers.assertPlainYearMonth(result, 2019, 6, "M06", "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..22b71d7e9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-leap-second.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for a calendar in a property bag +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = Temporal.PlainYearMonth.from(arg); +TemporalHelpers.assertPlainYearMonth( + result, + 2019, 6, "M06", + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..83ccb1205b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-number.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; + +for (const calendar of numbers) { + const arg = { year: 2019, monthCode: "M06", calendar }; + assert.throws( + TypeError, + () => Temporal.PlainYearMonth.from(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..89c9e2fd19 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-string.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = "iso8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = Temporal.PlainYearMonth.from(arg); +TemporalHelpers.assertPlainYearMonth(result, 2019, 6, "M06", `Calendar created from string "${calendar}"`); +assert.sameValue(result.getISOFields().calendar, "iso8601", "calendar slot stores a string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..043b3d9d48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-wrong-type.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when a calendar property from a property bag cannot + be converted to a calendar object or string +features: [BigInt, Symbol, Temporal] +---*/ + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [calendar, description] of primitiveTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws( + typeof calendar === 'string' ? RangeError : TypeError, + () => Temporal.PlainYearMonth.from(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], + [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields() +]; + +for (const [calendar, description] of typeErrorTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws(TypeError, () => Temporal.PlainYearMonth.from(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..9d039d2365 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-propertybag-calendar-year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T17:45", + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+01:00", + "-000000-10-31T17:45+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..833cb89b30 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-calendar-annotation.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[u-ca=iso8601]", "without time zone"], + ["2019-12-15T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2019-12-15T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2019-12-15T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2019-12-15T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.from(arg); + + TemporalHelpers.assertPlainYearMonth( + result, + 2019, 12, "M12", + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..ff157f3086 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..f1eb91f5f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-date-with-utc-offset.js @@ -0,0 +1,54 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const validStrings = [ + "2019-12[Africa/Abidjan]", + "2019-12[!Africa/Abidjan]", + "2019-12[u-ca=iso8601]", + "2019-12[Africa/Abidjan][u-ca=iso8601]", + "2019-12-15T00+00:00", + "2019-12-15T00+00:00[UTC]", + "2019-12-15T00+00:00[!UTC]", + "2019-12-15T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = Temporal.PlainYearMonth.from(arg); + + TemporalHelpers.assertPlainYearMonth( + result, + 2019, 12, "M12", + `"${arg}" is a valid UTC offset with time for PlainYearMonth` + ); +} + +const invalidStrings = [ + "2022-09[u-ca=hebrew]", + "2022-09Z", + "2022-09+01:00", + "2022-09-15Z", + "2022-09-15Z[UTC]", + "2022-09-15Z[Europe/Vienna]", + "2022-09-15+00:00", + "2022-09-15+00:00[UTC]", + "2022-09-15-02:30", + "2022-09-15-02:30[America/St_Johns]", +]; + +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + `"${arg}" UTC offset without time is not valid for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-invalid.js new file mode 100644 index 0000000000..4466c79b3d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-invalid.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An invalid ISO string is never supported +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const input of TemporalHelpers.ISO.plainYearMonthStringsInvalid()) { + assert.throws(RangeError, () => Temporal.PlainYearMonth.from(input, { overflow: "reject" })); + assert.throws(RangeError, () => Temporal.PlainYearMonth.from(input, { overflow: "constrain" })); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..1cf41e7de7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-calendar.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..87c47ab87d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-separators.js new file mode 100644 index 0000000000..964481e3c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-separators.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23", "uppercase T"], + ["2019-12-15t15:23", "lowercase T"], + ["2019-12-15 15:23", "space between date and time"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.from(arg); + + TemporalHelpers.assertPlainYearMonth( + result, + 2019, 12, "M12", + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..cf078a1a26 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-time-zone-annotation.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[Asia/Kolkata]", "named, with no offset"], + ["2019-12-15T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["2019-12-15T15:23[+00:00]", "numeric, with no offset"], + ["2019-12-15T15:23[!-02:30]", "numeric, with ! and no offset"], + ["2019-12-15T15:23+00:00[UTC]", "named, with offset"], + ["2019-12-15T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["2019-12-15T15:23+00:00[+01:00]", "numeric, with offset"], + ["2019-12-15T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.from(arg); + + TemporalHelpers.assertPlainYearMonth( + result, + 2019, 12, "M12", + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-trailing-junk.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-trailing-junk.js new file mode 100644 index 0000000000..248ccdca42 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-trailing-junk.js @@ -0,0 +1,13 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: RangeError thrown if a string with trailing junk is used as a PlainYearMonth +features: [Temporal] +---*/ + +assert.throws(RangeError, () => Temporal.PlainYearMonth.from("1976-11junk")); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..982ae9ad9a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-unknown-annotation.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[foo=bar]", "alone"], + ["2019-12-15T15:23[UTC][foo=bar]", "with time zone"], + ["2019-12-15T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2019-12-15T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2019-12-15T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainYearMonth.from(arg); + + TemporalHelpers.assertPlainYearMonth( + result, + 2019, 12, "M12", + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..4841b03596 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string-with-utc-designator.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: RangeError thrown if a string with UTC designator is used as a PlainYearMonth +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + "String with UTC designator should not be valid as a PlainYearMonth" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string.js new file mode 100644 index 0000000000..59b9f44fbe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-string.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const input of TemporalHelpers.ISO.plainYearMonthStringsValid()) { + const plainYearMonth = Temporal.PlainYearMonth.from(input); + TemporalHelpers.assertPlainYearMonth(plainYearMonth, 1976, 11, "M11"); + const fields = plainYearMonth.getISOFields(); + assert.sameValue(fields.calendar, "iso8601", "calendar slot should store a string"); + assert.sameValue(fields.isoDay, 1, "isoDay"); + assert.sameValue(fields.isoMonth, 11, "isoMonth"); + assert.sameValue(fields.isoYear, 1976, "isoYear"); +} + +for (const input of TemporalHelpers.ISO.plainYearMonthStringsValidNegativeYear()) { + const plainYearMonth = Temporal.PlainYearMonth.from(input); + TemporalHelpers.assertPlainYearMonth(plainYearMonth, -9999, 11, "M11"); + const fields = plainYearMonth.getISOFields(); + assert.sameValue(fields.calendar, "iso8601", "calendar slot should store a string"); + assert.sameValue(fields.isoDay, 1, "isoDay"); + assert.sameValue(fields.isoMonth, 11, "isoMonth"); + assert.sameValue(fields.isoYear, -9999, "isoYear"); + assert.sameValue(plainYearMonth.toString(), "-009999-11"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-wrong-type.js new file mode 100644 index 0000000000..de5a5590f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/argument-wrong-type.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainYearMonth +features: [BigInt, Symbol, Temporal] +---*/ + +const primitiveTests = [ + [undefined, "undefined"], + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => Temporal.PlainYearMonth.from(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth, object"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => Temporal.PlainYearMonth.from(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/builtin.js new file mode 100644 index 0000000000..233cebcb81 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/builtin.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Tests that Temporal.PlainYearMonth.from meets the requirements for built-in objects +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.from), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.from), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.from), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.from.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..e019e44b5c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const arg = { year: 2000, month: 5, calendar }; +Temporal.PlainYearMonth.from(arg); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-fields-iterable.js new file mode 100644 index 0000000000..7f20933b28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-fields-iterable.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.from step 3: + 3. Return ? ToTemporalYearMonth(_item_, _options_). + sec-temporal-totemporalyearmonth step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "month", + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +Temporal.PlainYearMonth.from({ year: 2000, month: 5, calendar }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-temporal-object.js new file mode 100644 index 0000000000..eb863f5961 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/calendar-temporal-object.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plainyearmonth.from step 3: + 3. Return ? ToTemporalYearMonth(_item_, _options_). + sec-temporal-totemporaldate step 2.b: + b. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_). + sec-temporal-gettemporalcalendarwithisodefault step 2: + 2. Return ? ToTemporalCalendarWithISODefault(_calendar_). + sec-temporal-totemporalcalendarwithisodefault step 2: + 3. Return ? ToTemporalCalendar(_temporalCalendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject, calendar) => { + const result = Temporal.PlainYearMonth.from({ year: 2000, month: 5, calendar: temporalObject }); + assert.sameValue(result.getCalendar(), calendar, "Temporal object coerced to calendar"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..83c2be28c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/constructor-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.from +description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; + +assert.throws(RangeError, () => Temporal.PlainYearMonth.from(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/duplicate-calendar-fields.js new file mode 100644 index 0000000000..066993f13a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.from +description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + + +for (const extra_fields of [['foo', 'foo'], ['month'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + + assert.throws(RangeError, () => Temporal.PlainYearMonth.from(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..c8e260b3b1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/infinity-throws-rangeerror.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.from +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const base = { year: 2000, month: 5 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + ["constrain", "reject"].forEach((overflow) => { + assert.throws(RangeError, () => Temporal.PlainYearMonth.from({ ...base, [prop]: inf }, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => Temporal.PlainYearMonth.from({ ...base, [prop]: obj }, { overflow })); + assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/leap-second.js new file mode 100644 index 0000000000..cf9eae3c06 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/leap-second.js @@ -0,0 +1,44 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let arg = "2016-12-31T23:59:60"; + +const result1 = Temporal.PlainYearMonth.from(arg); +TemporalHelpers.assertPlainYearMonth( + result1, + 2016, 12, "M12", + "leap second is a valid ISO string for PlainYearMonth" +); + +const result2 = Temporal.PlainYearMonth.from(arg, { overflow: "reject" }); +TemporalHelpers.assertPlainYearMonth( + result2, + 2016, 12, "M12", + "leap second is a valid ISO string for PlainYearMonth" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; + +const result3 = Temporal.PlainYearMonth.from(arg); +TemporalHelpers.assertPlainYearMonth( + result3, + 2016, 12, "M12", + "second: 60 is ignored in property bag for PlainYearMonth" +); + +const result4 = Temporal.PlainYearMonth.from(arg, { overflow: "reject" }); +TemporalHelpers.assertPlainYearMonth( + result4, + 2016, 12, "M12", + "second: 60 is ignored in property bag for PlainYearMonth even with overflow: reject" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/length.js new file mode 100644 index 0000000000..f652f2ef2e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.from.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.from, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/limits.js new file mode 100644 index 0000000000..2cc1f868bd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/limits.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: PlainYearMonth.from enforces the supported range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +["reject", "constrain"].forEach((overflow) => { + [{ year: -271821, month: 3 }, { year: 275760, month: 10 }, "-271821-03", "+275760-10"].forEach((value) => { + assert.throws(RangeError, () => Temporal.PlainYearMonth.from(value, { overflow }), + `${JSON.stringify(value)} with ${overflow}`); + }); +}); + +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from({ year: -271821, month: 4 }), + -271821, 4, "M04", "min object"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from({ year: 275760, month: 9 }), + 275760, 9, "M09", "max object"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("-271821-04"), + -271821, 4, "M04", "min string"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("+275760-09"), + 275760, 9, "M09", "max string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/name.js new file mode 100644 index 0000000000..1442021f14 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.from.name is "from". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.from, "name", { + value: "from", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/not-a-constructor.js new file mode 100644 index 0000000000..df8fdb4b08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/not-a-constructor.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Temporal.PlainYearMonth.from does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.from(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.from), false, + "isConstructor(Temporal.PlainYearMonth.from)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-primitive.js new file mode 100644 index 0000000000..bb5d83b298 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-primitive.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: overflow property is extracted with string argument. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", +]; + +let actual = []; +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +const result = Temporal.PlainYearMonth.from("2021-05", options); +assert.compareArray(actual, expected, "Successful call"); +TemporalHelpers.assertPlainYearMonth(result, 2021, 5, "M05"); + +actual.splice(0); // empty it for the next check +const failureExpected = [ + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", +]; + +assert.throws(TypeError, () => Temporal.PlainYearMonth.from(7, options)); +assert.compareArray(actual, failureExpected, "Failing call"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-string-invalid.js new file mode 100644 index 0000000000..567cc6b653 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-string-invalid.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: overflow property is extracted with ISO-invalid string argument. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", +]; + +let actual = []; +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +assert.throws(RangeError, () => Temporal.PlainYearMonth.from("2020-13", options)); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-invalid.js new file mode 100644 index 0000000000..71a0c690bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-invalid.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a primitive is passed as the options argument +features: [Temporal] +---*/ + +const items = [ + { year: 2000, month: 11 }, + "2000-11", + new Temporal.PlainYearMonth(2000, 11), +]; +const values = [null, true, "hello", Symbol("foo"), 1, 1n]; + +for (const item of items) { + for (const badOptions of values) { + assert.throws(TypeError, () => Temporal.PlainYearMonth.from(item, badOptions)); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-object.js new file mode 100644 index 0000000000..e836ed81bc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-object.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.from +description: Empty object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.assertPlainYearMonth( + Temporal.PlainYearMonth.from({ year: 2021, monthCode: "M01" }, {}), 2021, 1, "M01", + "options may be an empty plain object" +); + +TemporalHelpers.assertPlainYearMonth( + Temporal.PlainYearMonth.from({ year: 2021, monthCode: "M01" }, () => {}), 2021, 1, "M01", + "options may be an empty function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-undefined.js new file mode 100644 index 0000000000..1a4d3c9afa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const fields = { year: 2000, month: 13 }; + +const explicit = Temporal.PlainYearMonth.from(fields, undefined); +assert.sameValue(explicit.month, 12, "default overflow is constrain"); + +const implicit = Temporal.PlainYearMonth.from(fields); +assert.sameValue(implicit.month, 12, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js new file mode 100644 index 0000000000..5b937ec8b7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/options-wrong-type.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/order-of-operations.js new file mode 100644 index 0000000000..7d9082ffa1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/order-of-operations.js @@ -0,0 +1,80 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Properties on an object passed to from() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + "getOwnPropertyDescriptor options.extra", + "get options.extra", + // GetTemporalCalendarSlotValueWithISODefault + "get fields.calendar", + "has fields.calendar.dateAdd", + "has fields.calendar.dateFromFields", + "has fields.calendar.dateUntil", + "has fields.calendar.day", + "has fields.calendar.dayOfWeek", + "has fields.calendar.dayOfYear", + "has fields.calendar.daysInMonth", + "has fields.calendar.daysInWeek", + "has fields.calendar.daysInYear", + "has fields.calendar.fields", + "has fields.calendar.id", + "has fields.calendar.inLeapYear", + "has fields.calendar.mergeFields", + "has fields.calendar.month", + "has fields.calendar.monthCode", + "has fields.calendar.monthDayFromFields", + "has fields.calendar.monthsInYear", + "has fields.calendar.weekOfYear", + "has fields.calendar.year", + "has fields.calendar.yearMonthFromFields", + "has fields.calendar.yearOfWeek", + // lookup + "get fields.calendar.fields", + "get fields.calendar.yearMonthFromFields", + // CalendarFields + "call fields.calendar.fields", + // PrepareTemporalFields + "get fields.month", + "get fields.month.valueOf", + "call fields.month.valueOf", + "get fields.monthCode", + "get fields.monthCode.toString", + "call fields.monthCode.toString", + "get fields.year", + "get fields.year.valueOf", + "call fields.year.valueOf", + // CalendarYearMonthFromFields + "call fields.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const fields = TemporalHelpers.propertyBagObserver(actual, { + year: 1.7, + month: 1.7, + monthCode: "M01", + calendar: TemporalHelpers.calendarObserver(actual, "fields.calendar"), +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { + overflow: "constrain", + extra: "property", +}, "options"); + +Temporal.PlainYearMonth.from(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-constrain.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-constrain.js new file mode 100644 index 0000000000..7d27364aa0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-constrain.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Reject value for overflow option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const propertyBag = { year: 2000, month: 13 }; +const plainYearMonth = Temporal.PlainYearMonth.from(propertyBag, { overflow: "constrain" }); +TemporalHelpers.assertPlainYearMonth(plainYearMonth, 2000, 12, "M12", "default overflow is constrain"); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js new file mode 100644 index 0000000000..b47d26ae14 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-invalid-string.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: RangeError thrown when overflow option not one of the allowed string values +info: | + sec-getoption step 10: + 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-totemporalyearmonth steps 2–3: + 2. If Type(_item_) is Object, then + ... + e. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalYearMonth]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalYearMonth(_item_, _options_). +features: [Temporal] +---*/ + +const validValues = [ + new Temporal.PlainYearMonth(2000, 5), + { year: 2000, month: 5 }, + "2000-05", +]; + +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}")` + ); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-reject.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-reject.js new file mode 100644 index 0000000000..204f834311 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-reject.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Reject value for overflow option +features: [Temporal] +---*/ + +const bad = { year: 2019, month: 13 }; +assert.throws(RangeError, () => Temporal.PlainYearMonth.from(bad, { overflow: "reject" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-undefined.js new file mode 100644 index 0000000000..1ead004463 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-undefined.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Fallback value for overflow option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-totemporalyearmonth steps 2–3: + 2. If Type(_item_) is Object, then + ... + e. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalYearMonth]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalYearMonth(_item_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const validValues = [ + new Temporal.PlainYearMonth(2000, 5), + "2000-05", +]; +validValues.forEach((value) => { + const explicit = Temporal.PlainYearMonth.from(value, { overflow: undefined }); + TemporalHelpers.assertPlainYearMonth(explicit, 2000, 5, "M05", "overflow is ignored"); + const implicit = Temporal.PlainYearMonth.from(value, {}); + TemporalHelpers.assertPlainYearMonth(implicit, 2000, 5, "M05", "overflow is ignored"); + const lambda = Temporal.PlainYearMonth.from(value, () => {}); + TemporalHelpers.assertPlainYearMonth(lambda, 2000, 5, "M05", "overflow is ignored"); +}); + +const propertyBag = { year: 2000, month: 13 }; +const explicit = Temporal.PlainYearMonth.from(propertyBag, { overflow: undefined }); +TemporalHelpers.assertPlainYearMonth(explicit, 2000, 12, "M12", "default overflow is constrain"); +const implicit = Temporal.PlainYearMonth.from(propertyBag, {}); +TemporalHelpers.assertPlainYearMonth(implicit, 2000, 12, "M12", "default overflow is constrain"); +const lambda = Temporal.PlainYearMonth.from(propertyBag, () => {}); +TemporalHelpers.assertPlainYearMonth(lambda, 2000, 12, "M12", "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-wrong-type.js new file mode 100644 index 0000000000..17564481ba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/overflow-wrong-type.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: Type conversions for overflow option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-totemporalyearmonth steps 2–3: + 2. If Type(_item_) is Object, then + ... + e. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalYearMonth]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalYearMonth(_item_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const validValues = [ + new Temporal.PlainYearMonth(2000, 5), + { year: 2000, month: 5 }, + "2000-05", +]; +validValues.forEach((value) => TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => Temporal.PlainYearMonth.from(value, { overflow }), + (result, descr) => TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05", descr), +)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/prop-desc.js new file mode 100644 index 0000000000..1ca65fe582 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: The "from" property of Temporal.PlainYearMonth +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.from, + "function", + "`typeof PlainYearMonth.from` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth, "from", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/proto-in-calendar-fields.js new file mode 100644 index 0000000000..eedf95b18b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/proto-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.from +description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; + +assert.throws(RangeError, () => Temporal.PlainYearMonth.from(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/subclassing-ignored.js new file mode 100644 index 0000000000..807269128f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/subclassing-ignored.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.from +description: The receiver is never called when calling from() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnoredStatic( + Temporal.PlainYearMonth, + "from", + ["2000-05"], + (result) => TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05"), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/year-zero.js new file mode 100644 index 0000000000..07ffa27808 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/from/year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-06", + "-000000-06-24", + "-000000-06-24T15:43:27", + "-000000-06-24T15:43:27+01:00", + "-000000-06-24T15:43:27+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainYearMonth.from(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..ee276ac931 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/infinity-throws-rangeerror.js @@ -0,0 +1,44 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth throws a RangeError if any numerical value is Infinity +esid: sec-temporal.plainyearmonth +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const isoCalendar = Temporal.Calendar.from('iso8601'); + +assert.throws(RangeError, () => new Temporal.PlainYearMonth(Infinity, 1)); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(1970, Infinity)); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(1970, 1, isoCalendar, Infinity)); + +const O = (primitiveValue, propertyName) => (calls) => TemporalHelpers.toPrimitiveObserver(calls, primitiveValue, propertyName); +const tests = [ + [ + "infinite year", + [O(Infinity, "year"), O(1, "month"), () => "iso8601", O(1, "day")], + ["get year.valueOf", "call year.valueOf"] + ], + [ + "infinite month", + [O(1970, "year"), O(Infinity, "month"), () => "iso8601", O(1, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf"] + ], + [ + "infinite day", + [O(1970, "year"), O(1, "month"), () => "iso8601", O(Infinity, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf", "get day.valueOf", "call day.valueOf"] + ], +]; + +for (const [description, args, expected] of tests) { + const actual = []; + const args_ = args.map((o) => o(actual)); + assert.throws(RangeError, () => new Temporal.PlainYearMonth(...args_), description); + assert.compareArray(actual, expected, `${description} order of operations`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/length.js new file mode 100644 index 0000000000..06d322c288 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Temporal.PlainYearMonth.length is 2 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/limits.js new file mode 100644 index 0000000000..92f711a442 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/limits.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Limits for the PlainYearMonth constructor. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +assert.throws(RangeError, () => new Temporal.PlainYearMonth(-271821, 3), "min"); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(275760, 10), "max"); +TemporalHelpers.assertPlainYearMonth(new Temporal.PlainYearMonth(-271821, 4), + -271821, 4, "M04", "min"); +TemporalHelpers.assertPlainYearMonth(new Temporal.PlainYearMonth(-271821, 4, "iso8601", 18), + -271821, 4, "M04", "min with referenceISODay", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 18); +TemporalHelpers.assertPlainYearMonth(new Temporal.PlainYearMonth(275760, 9), + 275760, 9, "M09", "max"); +TemporalHelpers.assertPlainYearMonth(new Temporal.PlainYearMonth(275760, 9, "iso8601", 14), + 275760, 9, "M09", "max with referenceISODay", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 14); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/missing-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/missing-arguments.js new file mode 100644 index 0000000000..0c0f0d973e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/missing-arguments.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: RangeError thrown after processing given args when invoked without all required args +includes: [compareArray.js] +features: [Temporal] +---*/ + +const expected = [ + "valueOf year", +]; +const actual = []; +const args = [ + { valueOf() { actual.push("valueOf year"); return 1; } }, +]; + +assert.throws(RangeError, () => new Temporal.PlainYearMonth(...args)); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/name.js new file mode 100644 index 0000000000..fec362e0a0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: Temporal.PlainYearMonth.name is "PlainYearMonth" +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth, "name", { + value: "PlainYearMonth", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..3bfb7a66f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/negative-infinity-throws-rangeerror.js @@ -0,0 +1,44 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth throws a RangeError if any numerical value is -Infinity +esid: sec-temporal.plainyearmonth +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const isoCalendar = Temporal.Calendar.from('iso8601'); + +assert.throws(RangeError, () => new Temporal.PlainYearMonth(-Infinity, 1)); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(1970, -Infinity)); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(1970, 1, isoCalendar, -Infinity)); + +const O = (primitiveValue, propertyName) => (calls) => TemporalHelpers.toPrimitiveObserver(calls, primitiveValue, propertyName); +const tests = [ + [ + "infinite year", + [O(-Infinity, "year"), O(1, "month"), () => "iso8601", O(1, "day")], + ["get year.valueOf", "call year.valueOf"] + ], + [ + "infinite month", + [O(1970, "year"), O(-Infinity, "month"), () => "iso8601", O(1, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf"] + ], + [ + "infinite day", + [O(1970, "year"), O(1, "month"), () => "iso8601", O(-Infinity, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf", "get day.valueOf", "call day.valueOf"] + ], +]; + +for (const [description, args, expected] of tests) { + const actual = []; + const args_ = args.map((o) => o(actual)); + assert.throws(RangeError, () => new Temporal.PlainYearMonth(...args_), description); + assert.compareArray(actual, expected, `${description} order of operations`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prop-desc.js new file mode 100644 index 0000000000..fc3afdc33d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: The "PlainYearMonth" property of Temporal +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth, + "function", + "`typeof PlainYearMonth` is `function`" +); + +verifyProperty(Temporal, "PlainYearMonth", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-max.js new file mode 100644 index 0000000000..7189fa8806 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-max.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1970, 1); + +const maxCases = [ + ["P273790Y8M12DT23H59M59.999999999S", "string with max years"], + [{ years: 273790, months: 8, days: 12, nanoseconds: 86399999999999 }, "property bag with max years"], + ["P3285488M12DT23H59M59.999999999S", "string with max months"], + [{ months: 3285488, days: 12, nanoseconds: 86399999999999 }, "property bag with max months"], + ["P14285714W2DT23H59M59.999999999S", "string with max weeks"], + [{ weeks: 14285714, days: 2, nanoseconds: 86399999999999 }, "property bag with max weeks"], + ["P100000000DT23H59M59.999999999S", "string with max days"], + [{ days: 100000000, nanoseconds: 86399999999999 }, "property bag with max days"], + ["PT2400000023H59M59.999999999S", "string with max hours"], + [{ hours: 2400000023, nanoseconds: 3599999999999 }, "property bag with max hours"], + ["PT144000001439M59.999999999S", "string with max minutes"], + [{ minutes: 144000001439, nanoseconds: 59999999999 }, "property bag with max minutes"], + ["PT8640000086399.999999999S", "string with max seconds"], + [{ seconds: 8640000086399, nanoseconds: 999999999 }, "property bag with max seconds"], +]; + +for (const [arg, descr] of maxCases) { + const result = instance.add(arg); + TemporalHelpers.assertPlainYearMonth(result, 275760, 9, "M09", `operation succeeds with ${descr}`); +} + +const minCases = [ + ["-P273790Y8M42DT23H59M59.999999999S", "string with min years"], + [{ years: -273790, months: -8, days: -42, nanoseconds: -86399999999999 }, "property bag with min years"], + ["-P3285488M42DT23H59M59.999999999S", "string with min months"], + [{ months: -3285488, days: -42, nanoseconds: -86399999999999 }, "property bag with min months"], + ["-P14285718W5DT23H59M59.999999999S", "string with min weeks"], + [{ weeks: -14285718, days: -5, nanoseconds: -86399999999999 }, "property bag with min weeks"], + ["-P100000031DT23H59M59.999999999S", "string with min days"], + [{ days: -100000031, nanoseconds: -86399999999999 }, "property bag with min days"], + ["-PT2400000767H59M59.999999999S", "string with min hours"], + [{ hours: -2400000767, nanoseconds: -3599999999999 }, "property bag with min hours"], + ["-PT144000046079M59.999999999S", "string with min minutes"], + [{ minutes: -144000046079, nanoseconds: -59999999999 }, "property bag with min minutes"], + ["-PT8640002764799.999999999S", "string with min seconds"], + [{ seconds: -8640002764799, nanoseconds: -999999999 }, "property bag with min seconds"], +]; + +for (const [arg, descr] of minCases) { + const result = instance.add(arg); + TemporalHelpers.assertPlainYearMonth(result, -271821, 4, "M04", `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-object.js new file mode 100644 index 0000000000..57fd0409c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-object.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A Duration object is supported as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const nov94 = Temporal.PlainYearMonth.from("1994-11"); +const diff = Temporal.Duration.from("P18Y7M"); +TemporalHelpers.assertPlainYearMonth(nov94.add(diff), 2013, 6, "M06"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-out-of-range.js new file mode 100644 index 0000000000..be8dff7e3e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-duration-out-of-range.js @@ -0,0 +1,75 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1970, 1); + +const cases = [ + // 2^32 = 4294967296 + ["P4294967296Y", "string with years > max"], + [{ years: 4294967296 }, "property bag with years > max"], + ["-P4294967296Y", "string with years < min"], + [{ years: -4294967296 }, "property bag with years < min"], + ["P4294967296M", "string with months > max"], + [{ months: 4294967296 }, "property bag with months > max"], + ["-P4294967296M", "string with months < min"], + [{ months: -4294967296 }, "property bag with months < min"], + ["P4294967296W", "string with weeks > max"], + [{ weeks: 4294967296 }, "property bag with weeks > max"], + ["-P4294967296W", "string with weeks < min"], + [{ weeks: -4294967296 }, "property bag with weeks < min"], + + // ceil(max safe integer / 86400) = 104249991375 + ["P104249991375D", "string with days > max"], + [{ days: 104249991375 }, "property bag with days > max"], + ["P104249991374DT24H", "string where hours balance into days > max"], + [{ days: 104249991374, hours: 24 }, "property bag where hours balance into days > max"], + ["-P104249991375D", "string with days < min"], + [{ days: -104249991375 }, "property bag with days < min"], + ["-P104249991374DT24H", "string where hours balance into days < min"], + [{ days: -104249991374, hours: -24 }, "property bag where hours balance into days < min"], + + // ceil(max safe integer / 3600) = 2501999792984 + ["PT2501999792984H", "string with hours > max"], + [{ hours: 2501999792984 }, "property bag with hours > max"], + ["PT2501999792983H60M", "string where minutes balance into hours > max"], + [{ hours: 2501999792983, minutes: 60 }, "property bag where minutes balance into hours > max"], + ["-PT2501999792984H", "string with hours < min"], + [{ hours: -2501999792984 }, "property bag with hours < min"], + ["-PT2501999792983H60M", "string where minutes balance into hours < min"], + [{ hours: -2501999792983, minutes: -60 }, "property bag where minutes balance into hours < min"], + + // ceil(max safe integer / 60) = 150119987579017 + ["PT150119987579017M", "string with minutes > max"], + [{ minutes: 150119987579017 }, "property bag with minutes > max"], + ["PT150119987579016M60S", "string where seconds balance into minutes > max"], + [{ minutes: 150119987579016, seconds: 60 }, "property bag where seconds balance into minutes > max"], + ["-PT150119987579017M", "string with minutes < min"], + [{ minutes: -150119987579017 }, "property bag with minutes < min"], + ["-PT150119987579016M60S", "string where seconds balance into minutes < min"], + [{ minutes: -150119987579016, seconds: -60 }, "property bag where seconds balance into minutes < min"], + + // 2^53 = 9007199254740992 + ["PT9007199254740992S", "string with seconds > max"], + [{ seconds: 9007199254740992 }, "property bag with seconds > max"], + [{ seconds: 9007199254740991, milliseconds: 1000 }, "property bag where milliseconds balance into seconds > max"], + [{ seconds: 9007199254740991, microseconds: 1000000 }, "property bag where microseconds balance into seconds > max"], + [{ seconds: 9007199254740991, nanoseconds: 1000000000 }, "property bag where nanoseconds balance into seconds > max"], + ["-PT9007199254740992S", "string with seconds < min"], + [{ seconds: -9007199254740992 }, "property bag with seconds < min"], + [{ seconds: -9007199254740991, milliseconds: -1000 }, "property bag where milliseconds balance into seconds < min"], + [{ seconds: -9007199254740991, microseconds: -1000000 }, "property bag where microseconds balance into seconds < min"], + [{ seconds: -9007199254740991, nanoseconds: -1000000000 }, "property bag where nanoseconds balance into seconds < min"], +]; + +for (const [arg, descr] of cases) { + assert.throws(RangeError, () => instance.add(arg), `${descr} is out of range`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-invalid-property.js new file mode 100644 index 0000000000..ca3bc50ed5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-invalid-property.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +assert.throws( + TypeError, + () => instance.add({}), + "Throws TypeError if no property is present" +); + +assert.throws( + TypeError, + () => instance.add({ nonsense: true }), + "Throws TypeError if no recognized property is present" +); + +assert.throws( + TypeError, + () => instance.add({ sign: 1 }), + "Sign property is not recognized" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-lower-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-lower-units.js new file mode 100644 index 0000000000..e7fe44f217 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-lower-units.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Using lower units in add() works +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +const tests = [ + [{ days: 1 }, 2019, 11, "M11"], + [{ days: 29 }, 2019, 11, "M11"], + [{ hours: 1 }, 2019, 11, "M11"], + [{ minutes: 1 }, 2019, 11, "M11"], + [{ seconds: 1 }, 2019, 11, "M11"], + [{ milliseconds: 1 }, 2019, 11, "M11"], + [{ microseconds: 1 }, 2019, 11, "M11"], + [{ nanoseconds: 1 }, 2019, 11, "M11"], + [{ days: 30 }, 2019, 12, "M12"], + [{ days: 31 }, 2019, 12, "M12"], + [{ days: 60 }, 2019, 12, "M12"], + [{ days: 61 }, 2020, 1, "M01"], + [{ hours: 720 }, 2019, 12, "M12"], + [{ minutes: 43200 }, 2019, 12, "M12"], + [{ seconds: 2592000 }, 2019, 12, "M12"], + [{ milliseconds: 2592000_000 }, 2019, 12, "M12"], + [{ microseconds: 2592000_000_000 }, 2019, 12, "M12"], + [{ nanoseconds: 2592000_000_000_000 }, 2019, 12, "M12"], +]; + +for (const [argument, ...expected] of tests) { + TemporalHelpers.assertPlainYearMonth(ym.add(argument), ...expected, "no options"); + TemporalHelpers.assertPlainYearMonth(ym.add(argument, { overflow: "constrain" }), ...expected, "constrain"); + TemporalHelpers.assertPlainYearMonth(ym.add(argument, { overflow: "reject" }), ...expected, "reject"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-mixed-sign.js new file mode 100644 index 0000000000..100bd0924c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-mixed-sign.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +["constrain", "reject"].forEach((overflow) => { + assert.throws( + RangeError, + () => instance.add({ hours: 1, minutes: -30 }, { overflow }), + `mixed positive and negative values always throw (overflow = "${overflow}")` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-not-object.js new file mode 100644 index 0000000000..3543c747f5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-not-object.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Passing a primitive other than string to add() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +assert.throws(TypeError, () => instance.add(undefined), "undefined"); +assert.throws(TypeError, () => instance.add(null), "null"); +assert.throws(TypeError, () => instance.add(true), "boolean"); +assert.throws(RangeError, () => instance.add(""), "empty string"); +assert.throws(TypeError, () => instance.add(Symbol()), "Symbol"); +assert.throws(TypeError, () => instance.add(7), "number"); +assert.throws(TypeError, () => instance.add(7n), "bigint"); +assert.throws(TypeError, () => instance.add([]), "array"); +assert.throws(TypeError, () => instance.add(() => {}), "function"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-object.js new file mode 100644 index 0000000000..1ea7154439 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-object.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Passing an object to add() works +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +const tests = [ + [{ months: 2 }, 2020, 1, "M01"], + [{ years: 1 }, 2020, 11, "M11"], + [{ months: -2 }, 2019, 9, "M09"], + [{ years: -1 }, 2018, 11, "M11"], +]; + +for (const [argument, ...expected] of tests) { + TemporalHelpers.assertPlainYearMonth(ym.add(argument), ...expected, "no options"); + TemporalHelpers.assertPlainYearMonth(ym.add(argument, { overflow: "constrain" }), ...expected, "constrain"); + TemporalHelpers.assertPlainYearMonth(ym.add(argument, { overflow: "reject" }), ...expected, "reject"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-singular-properties.js new file mode 100644 index 0000000000..47fdacb939 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-singular-properties.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +[ + { 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, () => instance.add(badObject), + "Throw TypeError if temporalDurationLike is not valid"); +}); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..525a26d87f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string-negative-fractional-units.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +const resultHours = instance.add("-PT24.567890123H"); +TemporalHelpers.assertPlainYearMonth(resultHours, 2000, 5, "M05", "negative fractional hours"); + +const resultMinutes = instance.add("-PT1440.567890123M"); +TemporalHelpers.assertPlainYearMonth(resultMinutes, 2000, 5, "M05", "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string.js new file mode 100644 index 0000000000..f7f1095695 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/argument-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); +const result = instance.add("P3M"); +TemporalHelpers.assertPlainYearMonth(result, 2000, 8, "M08"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/branding.js new file mode 100644 index 0000000000..7122227f4d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const add = Temporal.PlainYearMonth.prototype.add; + +assert.sameValue(typeof add, "function"); + +const args = [new Temporal.Duration(5)]; + +assert.throws(TypeError, () => add.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => add.apply(null, args), "null"); +assert.throws(TypeError, () => add.apply(true, args), "true"); +assert.throws(TypeError, () => add.apply("", args), "empty string"); +assert.throws(TypeError, () => add.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => add.apply(1, args), "1"); +assert.throws(TypeError, () => add.apply({}, args), "plain object"); +assert.throws(TypeError, () => add.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => add.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..97ad7c2fa1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.add({ years: 5, months: 2 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..4aa25749dc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dateAddOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateAdd"); +Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateAdd should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.add(new Temporal.Duration(1)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", dateAddOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin.js new file mode 100644 index 0000000000..9fc7f42ab9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: > + Tests that Temporal.PlainYearMonth.prototype.add + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.add), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.add), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.add), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.add.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments-extra-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments-extra-options.js new file mode 100644 index 0000000000..a0e16c38bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments-extra-options.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: PlainYearMonth.prototype.add should pass extra fields in copied options objects. +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.extra", + "get options.extra", + // Temporal.Calendar.prototype.dateAdd + "get options.overflow", + // overwriting property in custom calendar dateAdd + "getOwnPropertyDescriptor options.overflow", +]; +const options = TemporalHelpers.propertyBagObserver(actual, { extra: 5 }, "options"); + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(date, duration, options) { + const result = super.dateAdd(date, duration, options); + options.overflow = 'meatloaf'; + return result; + } + yearMonthFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.notSameValue(args[1], options, "args[1]"); + return super.yearMonthFromFields(...args); + } +} +const plainYearMonth = new Temporal.PlainYearMonth(2000, 3, new CustomCalendar()); +const result = plainYearMonth.add({ months: 5 }, options); +TemporalHelpers.assertPlainYearMonth(result, 2000, 8, "M08"); +assert.compareArray(actual, expected, "extra field options object order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments.js new file mode 100644 index 0000000000..1fc4f0632c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-arguments.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: PlainYearMonth.prototype.add should respect calendar arguments and pass copied options objects. +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // Temporal.Calendar.prototype.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // overwriting property in custom calendar dateAdd + "getOwnPropertyDescriptor options.overflow", + // Temporal.Calendar.prototype.yearMonthFromFields (toPrimitiveObserver copied but not options object) + "get options.overflow.toString", + "call options.overflow.toString", +]; +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(date, duration, options) { + const result = super.dateAdd(date, duration, options); + options.overflow = 'meatloaf'; + return result; + } + yearMonthFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.notSameValue(args[1], options, "args[1]"); + return super.yearMonthFromFields(...args); + } +} + +const plainYearMonth = new Temporal.PlainYearMonth(2000, 3, new CustomCalendar()); +const result = plainYearMonth.add({ months: 10 }, options); +TemporalHelpers.assertPlainYearMonth(result, 2001, 1, "M01"); +assert.compareArray(actual, expected, "copied options object order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..272afc1e73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Duration addition to PlainYearMonth calls Calendar.dateAdd the right number of times +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddPlainDateInstance(); +const instance = new Temporal.PlainYearMonth(1983, 3, calendar); +TemporalHelpers.assertPlainYearMonth(instance.add({weeks: 5}), 1983, 4, 'M04', "Adding 5 weeks to March in is8601 calendar") +assert.sameValue(calendar.dateAddCallCount, 1, "dateAdd called once with positive add"); + +calendar.dateAddCallCount = 0; +TemporalHelpers.assertPlainYearMonth(instance.add({weeks: -5}), 1983, 2, 'M02', "Adding -5 weeks to March in is8601 calendar") +assert.sameValue(calendar.dateAddCallCount, 2, "dateAdd called 2 times with negative add"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd.js new file mode 100644 index 0000000000..38f18e0d1b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: PlainYearMonth.prototype.add should call dateAdd with the appropriate values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(plainDate, duration, options) { + ++calls; + TemporalHelpers.assertPlainDate(plainDate, 2000, 3, "M03", 1, "plainDate argument"); + TemporalHelpers.assertDuration(duration, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, "duration argument"); + assert.sameValue(typeof options, "object", "options argument: type"); + assert.sameValue(Object.getPrototypeOf(options), null, "options argument: prototype"); + return super.dateAdd(plainDate, duration, options); + } +} + +const plainYearMonth = new Temporal.PlainYearMonth(2000, 3, new CustomCalendar()); +const result = plainYearMonth.add({ months: 10 }); +TemporalHelpers.assertPlainYearMonth(result, 2001, 1, "M01"); +assert.sameValue(calls, 1, "should have called dateAdd"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js new file mode 100644 index 0000000000..a69ce9aa7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js @@ -0,0 +1,164 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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) { + const {isoYear, isoMonth, isoDay} = date.getISOFields(); + let {years, months, weeks, days} = duration; + let iter = new Temporal.PlainDate(isoYear + years, isoMonth, isoDay, "iso8601"); + const monthsDays = months * 36; + if (iter.dayOfYear + monthsDays > iter.daysInYear || iter.dayOfYear + monthsDays < 1) + throw new Error("complicated addition not implemented in this test"); + return iter.add({ weeks, days: monthsDays + days }).withCalendar(this); + } + 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); + +// Reference ISO dates in the custom calendar: +// M01 = 01-01 +// M02 = 02-06 +// M03 = 03-14 + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.add(lessThanOneMonth), + 2022, 2, "M02", + "adding positive less than one month's worth of days yields the same month", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 6 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 14 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 6 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 2, "dateFromFields was called twice"); +assert.deepEqual( + calendar.dateFromFieldsCalls[1][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 1 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 2, "dateFromFields was called twice"); +assert.deepEqual( + calendar.dateFromFieldsCalls[1][0], + { year: 2022, 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"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fields-iterable.js new file mode 100644 index 0000000000..57d5f3549e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fields-iterable.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.add step 8: + 8. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.add({ months: 1 }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..0fdeb5d83c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Calendar.dateFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.add(new Temporal.Duration(1)); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should have been called on the calendar"); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-yearmonthfromfields-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-yearmonthfromfields-called-with-null-prototype-options.js new file mode 100644 index 0000000000..9daccc5f77 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-yearmonthfromfields-called-with-null-prototype-options.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Calendar.yearMonthFromFields method is called with a null-prototype object + as the options value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2019, 6, calendar); +const argument = new Temporal.Duration(1, 1); +instance.add(argument); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..f92a871207 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/constructor-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.add({days: 123})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/custom-daysInMonth-irrelevant.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/custom-daysInMonth-irrelevant.js new file mode 100644 index 0000000000..e5af2a5d7a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/custom-daysInMonth-irrelevant.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Addition of a negative duration to a PlainYearMonth is not influenced by the implementation of daysInMonth() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + daysInMonth(ym, ...args) { + return 15; + } +} + +const customCalendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(2023, 3, customCalendar); + +TemporalHelpers.assertPlainYearMonth(instance.add({days: -30}), 2023, 3, 'M03', "Adding -30 days from calendar reimplementing daysinMonth()") + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/duplicate-calendar-fields.js new file mode 100644 index 0000000000..8c26670fdc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/duplicate-calendar-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + + assert.throws(RangeError, () => ym.add({days: 123})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/end-of-month-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/end-of-month-out-of-range.js new file mode 100644 index 0000000000..58fd4b9fe3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/end-of-month-out-of-range.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: RangeError thrown when adding negative duration and end of month is out of range +features: [Temporal] +info: | + AddDurationToOrSubtractDurationFromPlainYearMonth: + 12. If _sign_ < 0, then + a. Let _oneMonthDuration_ be ! CreateTemporalDuration(0, 1, 0, 0, 0, 0, 0, 0, 0, 0). + b. Let _nextMonth_ be ? CalendarDateAdd(_calendar_, _intermediateDate_, _oneMonthDuration_, *undefined*, _dateAdd_). + c. Let _endOfMonthISO_ be ! AddISODate(_nextMonth_.[[ISOYear]], _nextMonth_.[[ISOMonth]], _nextMonth_.[[ISODay]], 0, 0, 0, -1, *"constrain"*). + d. Let _endOfMonth_ be ? CreateTemporalDate(_endOfMonthISO_.[[Year]], _endOfMonthISO_.[[Month]], _endOfMonthISO_.[[Day]], _calendar_). +---*/ + +// Based on a test case by André Bargull <andre.bargull@gmail.com> + +const duration = new Temporal.Duration(0, 0, 0, -1); + +// Calendar addition result is out of range +assert.throws(RangeError, () => new Temporal.PlainYearMonth(275760, 9).add(duration), "Addition of 1 month to receiver out of range"); + +// Calendar addition succeeds, but subtracting 1 day gives out of range result +const cal = new class extends Temporal.Calendar { + dateAdd() { + return new Temporal.PlainDate(-271821, 4, 19); + } +}("iso8601"); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(2000, 1, cal).add(duration), "Subtraction of 1 day from next month out of range"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..263c8f9532 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/infinity-throws-rangeerror.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth.prototype.add throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plainyearmonth.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); + +overflows.forEach((overflow) => { + fields.forEach((field) => { + assert.throws(RangeError, () => instance.add({ [field]: Infinity }, { overflow })); + }); +}); + +let calls = 0; +const obj = { + valueOf() { + calls++; + return Infinity; + } +}; + +overflows.forEach((overflow) => { + fields.forEach((field) => { + calls = 0; + assert.throws(RangeError, () => instance.add({ [field]: obj }, { overflow })); + assert.sameValue(calls, 1, "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/length.js new file mode 100644 index 0000000000..7fd1c9d437 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.add.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.add, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/limits.js new file mode 100644 index 0000000000..190bb5bbda --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/limits.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: RangeError thrown when going out of range +features: [Temporal] +---*/ + +const max = Temporal.PlainYearMonth.from("+275760-09"); +for (const overflow of ["reject", "constrain"]) { + assert.throws(RangeError, () => max.add({ months: 1 }, { overflow }), overflow); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/month-length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/month-length.js new file mode 100644 index 0000000000..9ab1999987 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/month-length.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: add() takes month length into account +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-02").add({ days: 27 }), + 2019, 2, "M02"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-02").add({ days: 28 }), + 2019, 3, "M03"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-02").add({ days: 28 }), + 2020, 2, "M02"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-02").add({ days: 29 }), + 2020, 3, "M03"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-11").add({ days: 29 }), + 2019, 11, "M11"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-11").add({ days: 30 }), + 2019, 12, "M12"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-01").add({ days: 30 }), + 2020, 1, "M01"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-01").add({ days: 31 }), + 2020, 2, "M02"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/name.js new file mode 100644 index 0000000000..eb28c6ec22 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Temporal.PlainYearMonth.prototype.add.name is "add". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.add, "name", { + value: "add", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..6af1f2bf62 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/negative-infinity-throws-rangeerror.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth.prototype.add throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plainyearmonth.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); + +overflows.forEach((overflow) => { + fields.forEach((field) => { + assert.throws(RangeError, () => instance.add({ [field]: -Infinity }, { overflow })); + }); +}); + +let calls = 0; +const obj = { + valueOf() { + calls++; + return -Infinity; + } +}; + +overflows.forEach((overflow) => { + fields.forEach((field) => { + calls = 0; + assert.throws(RangeError, () => instance.add({ [field]: obj }, { overflow })); + assert.sameValue(calls, 1, "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..c9291564a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/non-integer-throws-rangeerror.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const fields = [ + "years", + "months", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", +]; +fields.forEach((field) => { + assert.throws(RangeError, () => instance.add({ [field]: 1.5 })); + assert.throws(RangeError, () => instance.add({ [field]: -1.5 })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/not-a-constructor.js new file mode 100644 index 0000000000..f547f9b87f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: > + Temporal.PlainYearMonth.prototype.add does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.add(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.add), false, + "isConstructor(Temporal.PlainYearMonth.prototype.add)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-invalid.js new file mode 100644 index 0000000000..49d0259b77 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-invalid.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Invalid options throw +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); +const values = [null, true, "hello", Symbol("foo"), 1, 1n]; +for (const badOptions of values) { + assert.throws(TypeError, () => ym.add({ years: 1 }, badOptions)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-object.js new file mode 100644 index 0000000000..b1e9c17962 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-object.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.add({ months: 1 }, {}); +TemporalHelpers.assertPlainYearMonth( + result1, 2019, 11, "M11", + "options may be an empty plain object" +); + +const result2 = instance.add({ months: 1 }, () => {}); +TemporalHelpers.assertPlainYearMonth( + result2, 2019, 11, "M11", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-undefined.js new file mode 100644 index 0000000000..1dc3954e38 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-undefined.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +// overflow option has no effect on addition in the ISO calendar, so verify this +// with a custom calendar +class CheckedAdd extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(date, duration, options, constructor) { + this.called = true; + assert.notSameValue(options, undefined, "options not undefined"); + return super.dateAdd(date, duration, options, constructor); + } +} +const calendar = new CheckedAdd(); + +const yearmonth = new Temporal.PlainYearMonth(2000, 1, calendar); +const duration = { months: 1 }; + +yearmonth.add(duration, undefined); +yearmonth.add(duration); + +assert(calendar.called); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js new file mode 100644 index 0000000000..ec5796ece6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/order-of-operations.js new file mode 100644 index 0000000000..f1be5cbd2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/order-of-operations.js @@ -0,0 +1,183 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Properties on an object passed to add() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDuration + "get fields.days", + "get fields.days.valueOf", + "call fields.days.valueOf", + "get fields.hours", + "get fields.hours.valueOf", + "call fields.hours.valueOf", + "get fields.microseconds", + "get fields.microseconds.valueOf", + "call fields.microseconds.valueOf", + "get fields.milliseconds", + "get fields.milliseconds.valueOf", + "call fields.milliseconds.valueOf", + "get fields.minutes", + "get fields.minutes.valueOf", + "call fields.minutes.valueOf", + "get fields.months", + "get fields.months.valueOf", + "call fields.months.valueOf", + "get fields.nanoseconds", + "get fields.nanoseconds.valueOf", + "call fields.nanoseconds.valueOf", + "get fields.seconds", + "get fields.seconds.valueOf", + "call fields.seconds.valueOf", + "get fields.weeks", + "get fields.weeks.valueOf", + "call fields.weeks.valueOf", + "get fields.years", + "get fields.years.valueOf", + "call fields.years.valueOf", + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.day", + "get this.calendar.fields", + "get this.calendar.yearMonthFromFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarDateFromFields + "call this.calendar.dateFromFields", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // CalendarDateAdd + "call this.calendar.dateAdd", + // inside Calendar.p.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // PrepareTemporalFields on added date + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarYearMonthFromFields + "call this.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +const fields = TemporalHelpers.propertyBagObserver(actual, { + years: 1, + months: 1, + weeks: 1, + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +instance.add(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +actual.splice(0); // clear + +const noCalendarExpected = [ + // ToTemporalDuration + "get fields.days", + "get fields.days.valueOf", + "call fields.days.valueOf", + "get fields.hours", + "get fields.hours.valueOf", + "call fields.hours.valueOf", + "get fields.microseconds", + "get fields.microseconds.valueOf", + "call fields.microseconds.valueOf", + "get fields.milliseconds", + "get fields.milliseconds.valueOf", + "call fields.milliseconds.valueOf", + "get fields.minutes", + "get fields.minutes.valueOf", + "call fields.minutes.valueOf", + "get fields.months", + "get fields.nanoseconds", + "get fields.nanoseconds.valueOf", + "call fields.nanoseconds.valueOf", + "get fields.seconds", + "get fields.seconds.valueOf", + "call fields.seconds.valueOf", + "get fields.weeks", + "get fields.years", + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.day", + "get this.calendar.fields", + "get this.calendar.yearMonthFromFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarDateFromFields + "call this.calendar.dateFromFields", + // SnapshotOwnProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // AddDate + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // PrepareTemporalFields on added date + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarYearMonthFromFields + "call this.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; + +const noCalendarFields = TemporalHelpers.propertyBagObserver(actual, { + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +instance.add(noCalendarFields, options); +assert.compareArray(actual, noCalendarExpected, "order of operations with no calendar units"); + +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js new file mode 100644 index 0000000000..5ee0755a73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-invalid-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: RangeError thrown when overflow option not one of the allowed string values +info: | + sec-getoption step 10: + 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.add steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); + +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}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-undefined.js new file mode 100644 index 0000000000..be130752f5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-undefined.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Fallback value for overflow option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.add steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// In the ISO calendar, PlainYearMonth.prototype.add() actually ignores the +// overflow option. There is no addition in the ISO calendar that we could test +// which would actually show a difference between the 'constrain' and 'reject' +// values. +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); +const explicit = yearmonth.add(duration, { overflow: undefined }); +TemporalHelpers.assertPlainYearMonth(explicit, 2001, 6, "M06", "default overflow is constrain"); +const implicit = yearmonth.add(duration, {}); +TemporalHelpers.assertPlainYearMonth(implicit, 2001, 6, "M06", "default overflow is constrain"); +const lambda = yearmonth.add(duration, () => {}); +TemporalHelpers.assertPlainYearMonth(lambda, 2001, 6, "M06", "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-wrong-type.js new file mode 100644 index 0000000000..8a228a78b5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/overflow-wrong-type.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Type conversions for overflow option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.add steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); + +// See TemporalHelpers.checkStringOptionWrongType(); this code path has +// different expectations for observable calls + +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: null }), "null"); +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: true }), "true"); +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: false }), "false"); +assert.throws(TypeError, () => yearmonth.add(duration, { overflow: Symbol() }), "symbol"); +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: 2 }), "number"); +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: 2n }), "bigint"); +assert.throws(RangeError, () => yearmonth.add(duration, { overflow: {} }), "plain object"); + +// toString property is read once by Calendar.dateAdd() and then once again by +// calendar.yearMonthFromFields(). +const expected = [ + "get overflow.toString", + "call overflow.toString", + "get overflow.toString", + "call overflow.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "constrain", "overflow"); +const result = yearmonth.add(duration, { overflow: observer }); +TemporalHelpers.assertPlainYearMonth(result, 2001, 6, "M06", "object with toString"); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/prop-desc.js new file mode 100644 index 0000000000..ef7c146f3c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: The "add" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.add, + "function", + "`typeof PlainYearMonth.prototype.add` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "add", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/proto-in-calendar-fields.js new file mode 100644 index 0000000000..de323c1214 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/proto-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.add({days: 123})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/shell.js new file mode 100644 index 0000000000..346758ebd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/shell.js @@ -0,0 +1,353 @@ +// GENERATED, DO NOT EDIT +// file: deepEqual.js +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: > + Compare two values structurally +defines: [assert.deepEqual] +---*/ + +assert.deepEqual = function(actual, expected, message) { + var format = assert.deepEqual.format; + assert( + assert.deepEqual._compare(actual, expected), + `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}` + ); +}; + +assert.deepEqual.format = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return `[Function${value.name ? `: ${value.name}` : ''}]`; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return `Date "${value.toISOString()}"`; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + let usage = seen.map.get(value); + if (usage) { + usage.used = true; + return `[Ref: #${usage.id}]`; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (typeof Map !== "undefined" && value instanceof Map) { + return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`; + } + let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`; + default: + return typeof value; + } +}; + +assert.deepEqual._compare = (function () { + var EQUAL = 1; + var NOT_EQUAL = -1; + var UNKNOWN = 0; + + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + function isOptional(value) { + return value === undefined + || value === null; + } + + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + function isValueOfEquatable(value) { + return value instanceof Date; + } + + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + function getCache(cache, left, right) { + var otherCache; + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/subclassing-ignored.js new file mode 100644 index 0000000000..2afd7da12a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/add/subclassing-ignored.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.add +description: Objects of a subclass are never created as return values for add() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainYearMonth, + [2000, 5], + "add", + [{ months: 1 }], + (result) => TemporalHelpers.assertPlainYearMonth(result, 2000, 6, "M06"), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/branding.js new file mode 100644 index 0000000000..0d9b9175de --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.calendarid +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const calendarId = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "calendarId").get; + +assert.sameValue(typeof calendarId, "function"); + +assert.throws(TypeError, () => calendarId.call(undefined), "undefined"); +assert.throws(TypeError, () => calendarId.call(null), "null"); +assert.throws(TypeError, () => calendarId.call(true), "true"); +assert.throws(TypeError, () => calendarId.call(""), "empty string"); +assert.throws(TypeError, () => calendarId.call(Symbol()), "symbol"); +assert.throws(TypeError, () => calendarId.call(1), "1"); +assert.throws(TypeError, () => calendarId.call({}), "plain object"); +assert.throws(TypeError, () => calendarId.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => calendarId.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..40e1330c6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.calendarid +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const idOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id"); +Object.defineProperty(Temporal.Calendar.prototype, "id", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("id should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.calendarId; + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/prop-desc.js new file mode 100644 index 0000000000..ec83805f4c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.calendarid +description: The "calendarId" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "calendarId"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/calendarId/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/constructor.js new file mode 100644 index 0000000000..5584c1d064 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/constructor.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.constructor +description: Test for Temporal.PlainYearMonth.prototype.constructor. +info: The initial value of Temporal.PlainYearMonth.prototype.constructor is %Temporal.PlainYearMonth%. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype, "constructor", { + value: Temporal.PlainYearMonth, + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/basic.js new file mode 100644 index 0000000000..1a39263196 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/basic.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinmonth +description: daysInMonth works +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainYearMonth(1976, 2), 29], + [new Temporal.PlainYearMonth(1976, 11), 30], + [new Temporal.PlainYearMonth(1976, 12), 31], + [new Temporal.PlainYearMonth(1977, 2), 28], +]; +for (const [plainYearMonth, expected] of tests) { + assert.sameValue(plainYearMonth.daysInMonth, expected, `${expected} days in the month of ${plainYearMonth}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/branding.js new file mode 100644 index 0000000000..4f62df5ae4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinmonth +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInMonth = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "daysInMonth").get; + +assert.sameValue(typeof daysInMonth, "function"); + +assert.throws(TypeError, () => daysInMonth.call(undefined), "undefined"); +assert.throws(TypeError, () => daysInMonth.call(null), "null"); +assert.throws(TypeError, () => daysInMonth.call(true), "true"); +assert.throws(TypeError, () => daysInMonth.call(""), "empty string"); +assert.throws(TypeError, () => daysInMonth.call(Symbol()), "symbol"); +assert.throws(TypeError, () => daysInMonth.call(1), "1"); +assert.throws(TypeError, () => daysInMonth.call({}), "plain object"); +assert.throws(TypeError, () => daysInMonth.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => daysInMonth.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..a15e38458f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.daysinmonth +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const daysInMonthOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "daysInMonth"); +Object.defineProperty(Temporal.Calendar.prototype, "daysInMonth", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("daysInMonth should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.daysInMonth; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInMonth", daysInMonthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/custom.js new file mode 100644 index 0000000000..6dec04d593 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinmonth +description: Custom calendar tests for daysInMonth(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + daysInMonth(...args) { + ++calls; + assert.compareArray(args, [instance], "daysInMonth arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.daysInMonth; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/prop-desc.js new file mode 100644 index 0000000000..65a27466d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinmonth +description: The "daysInMonth" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "daysInMonth"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/validate-calendar-value.js new file mode 100644 index 0000000000..bbdfb954a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/validate-calendar-value.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinmonth +description: Validate result returned from calendar daysInMonth() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [null, TypeError], + [false, TypeError], + [Infinity, RangeError], + [-Infinity, RangeError], + [NaN, RangeError], + [-7, RangeError], + [-0.1, RangeError], + ["string", TypeError], + [Symbol("foo"), TypeError], + [7n, TypeError], + [{}, TypeError], + [true, TypeError], + [7.1, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + daysInMonth() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.daysInMonth, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/basic.js new file mode 100644 index 0000000000..d5454b3721 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/basic.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinyear +description: daysInYear works +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainYearMonth(1976, 11)).daysInYear, 366, "leap year"); +assert.sameValue((new Temporal.PlainYearMonth(1977, 11)).daysInYear, 365, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/branding.js new file mode 100644 index 0000000000..c8f726278e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInYear = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "daysInYear").get; + +assert.sameValue(typeof daysInYear, "function"); + +assert.throws(TypeError, () => daysInYear.call(undefined), "undefined"); +assert.throws(TypeError, () => daysInYear.call(null), "null"); +assert.throws(TypeError, () => daysInYear.call(true), "true"); +assert.throws(TypeError, () => daysInYear.call(""), "empty string"); +assert.throws(TypeError, () => daysInYear.call(Symbol()), "symbol"); +assert.throws(TypeError, () => daysInYear.call(1), "1"); +assert.throws(TypeError, () => daysInYear.call({}), "plain object"); +assert.throws(TypeError, () => daysInYear.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => daysInYear.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..80be46b506 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.daysinyear +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const daysInYearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "daysInYear"); +Object.defineProperty(Temporal.Calendar.prototype, "daysInYear", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("daysInYear should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.daysInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInYear", daysInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/custom.js new file mode 100644 index 0000000000..fbe58f3918 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinyear +description: Custom calendar tests for daysInYear(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + daysInYear(...args) { + ++calls; + assert.compareArray(args, [instance], "daysInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.daysInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/prop-desc.js new file mode 100644 index 0000000000..c9d5ae7d5a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinyear +description: The "daysInYear" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "daysInYear"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/validate-calendar-value.js new file mode 100644 index 0000000000..f600bdec79 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/daysInYear/validate-calendar-value.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.daysinyear +description: Validate result returned from calendar daysInYear() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [null, TypeError], + [false, TypeError], + [Infinity, RangeError], + [-Infinity, RangeError], + [NaN, RangeError], + [-7, RangeError], + [-0.1, RangeError], + ["string", TypeError], + [Symbol("foo"), TypeError], + [7n, TypeError], + [{}, TypeError], + [true, TypeError], + [7.1, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + daysInYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.daysInYear, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..88039009aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-builtin-calendar-no-array-iteration.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method with a property bag argument with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar: "iso8601" }; +instance.equals(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-cast.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-cast.js new file mode 100644 index 0000000000..b14f01000b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-cast.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: equals() casts its argument +features: [Temporal] +---*/ + +const nov94 = Temporal.PlainYearMonth.from("1994-11"); + +assert.sameValue(nov94.equals({ year: 2013, month: 6 }), false, "object"); +assert.sameValue(nov94.equals({ year: 1994, month: 11 }), true, "object"); +assert.sameValue(nov94.equals("2013-06"), false, "string"); +assert.sameValue(nov94.equals("1994-11"), true, "string"); +assert.throws(TypeError, () => nov94.equals({ year: 2013 }), "missing property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-number.js new file mode 100644 index 0000000000..abcf713fd2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-number.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is invalid in place of an ISO string for Temporal.PlainYearMonth +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const numbers = [ + 1, + 201906, + -201906, + 1234567, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.equals(arg), + `A number (${arg}) is not a valid ISO string for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..785f769b50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-case-insensitive.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "IsO8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.equals(arg); +assert.sameValue(result, true, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..1b405e75e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-leap-second.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for a calendar in a property bag +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.equals(arg); +assert.sameValue( + result, + true, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..d0c0c6570a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-number.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; + +for (const calendar of numbers) { + const arg = { year: 2019, monthCode: "M06", calendar }; + assert.throws( + TypeError, + () => instance.equals(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..1f6ce3ef8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-string.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "iso8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.equals(arg); +assert.sameValue(result, true, `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..5ee7390dad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-wrong-type.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when a calendar property from a property bag cannot + be converted to a calendar object or string +features: [BigInt, Symbol, Temporal] +---*/ + +const timeZone = new Temporal.TimeZone("UTC"); +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [calendar, description] of primitiveTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws( + typeof calendar === 'string' ? RangeError : TypeError, + () => instance.equals(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], + [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields() +]; + +for (const [calendar, description] of typeErrorTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws(TypeError, () => instance.equals(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..0e652fd79b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-propertybag-calendar-year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T17:45", + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+01:00", + "-000000-10-31T17:45+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..5ba6126ca4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-calendar-annotation.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[u-ca=iso8601]", "without time zone"], + ["2019-12-15T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2019-12-15T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2019-12-15T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2019-12-15T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.equals(arg); + + assert.sameValue( + result, + true, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..9d108c2a70 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..b24b89be0b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-date-with-utc-offset.js @@ -0,0 +1,55 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 12); + +const validStrings = [ + "2019-12[Africa/Abidjan]", + "2019-12[!Africa/Abidjan]", + "2019-12[u-ca=iso8601]", + "2019-12[Africa/Abidjan][u-ca=iso8601]", + "2019-12-15T00+00:00", + "2019-12-15T00+00:00[UTC]", + "2019-12-15T00+00:00[!UTC]", + "2019-12-15T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = instance.equals(arg); + + assert.sameValue( + result, + true, + `"${arg}" is a valid UTC offset with time for PlainYearMonth` + ); +} + +const invalidStrings = [ + "2022-09[u-ca=hebrew]", + "2022-09Z", + "2022-09+01:00", + "2022-09-15Z", + "2022-09-15Z[UTC]", + "2022-09-15Z[Europe/Vienna]", + "2022-09-15+00:00", + "2022-09-15+00:00[UTC]", + "2022-09-15-02:30", + "2022-09-15-02:30[America/St_Johns]", +]; + +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.equals(arg), + `"${arg}" UTC offset without time is not valid for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-invalid.js new file mode 100644 index 0000000000..dd4584f445 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-invalid.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An invalid ISO string is never supported +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); + +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsInvalid()) { + assert.throws(RangeError, () => instance.equals(arg), `"${arg}" is not a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..e2abd6b0ef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-calendar.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..76e3ea2a8a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-separators.js new file mode 100644 index 0000000000..5eb55c5eed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-separators.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23", "uppercase T"], + ["2019-12-15t15:23", "lowercase T"], + ["2019-12-15 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.equals(arg); + + assert.sameValue( + result, + true, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..797b6ceaf1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-time-zone-annotation.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[Asia/Kolkata]", "named, with no offset"], + ["2019-12-15T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["2019-12-15T15:23[+00:00]", "numeric, with no offset"], + ["2019-12-15T15:23[!-02:30]", "numeric, with ! and no offset"], + ["2019-12-15T15:23+00:00[UTC]", "named, with offset"], + ["2019-12-15T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["2019-12-15T15:23+00:00[+01:00]", "numeric, with offset"], + ["2019-12-15T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.equals(arg); + + assert.sameValue( + result, + true, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..ce906672c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-unknown-annotation.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["2019-12-15T15:23[foo=bar]", "alone"], + ["2019-12-15T15:23[UTC][foo=bar]", "with time zone"], + ["2019-12-15T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2019-12-15T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2019-12-15T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.equals(arg); + + assert.sameValue( + result, + true, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..7a5ffda315 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-with-utc-designator.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: RangeError thrown if a string with UTC designator is used as a PlainYearMonth +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + "String with UTC designator should not be valid as a PlainYearMonth" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string.js new file mode 100644 index 0000000000..2a3cae1340 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A string argument is parsed into a PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValid()) { + const result = instance.equals(arg); + assert.sameValue(result, true, `"${arg}" is a valid PlainYearMonth string`); +} + +const instanceNegativeYear = new Temporal.PlainYearMonth(-9999, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValidNegativeYear()) { + const result = instanceNegativeYear.equals(arg); + assert.sameValue(result, true, `"${arg}" is a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..1ea064cb25 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/argument-wrong-type.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainYearMonth +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [undefined, "undefined"], + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => instance.equals(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth, object"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.equals(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/basic.js new file mode 100644 index 0000000000..11e1fdfeba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/basic.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Basic tests for equals() +features: [Temporal] +---*/ + +const nov94 = Temporal.PlainYearMonth.from("1994-11"); +const nov94bis = Temporal.PlainYearMonth.from("1994-11"); +const jun13 = Temporal.PlainYearMonth.from("2013-06"); +assert.sameValue(nov94.equals(nov94), true, "same object"); +assert.sameValue(nov94.equals(nov94bis), true, "different object"); +assert.sameValue(nov94.equals(jun13), false, "different year-months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/branding.js new file mode 100644 index 0000000000..5245e85687 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const equals = Temporal.PlainYearMonth.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +const args = [new Temporal.PlainYearMonth(2022, 6)]; + +assert.throws(TypeError, () => equals.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => equals.apply(null, args), "null"); +assert.throws(TypeError, () => equals.apply(true, args), "true"); +assert.throws(TypeError, () => equals.apply("", args), "empty string"); +assert.throws(TypeError, () => equals.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => equals.apply(1, args), "1"); +assert.throws(TypeError, () => equals.apply({}, args), "plain object"); +assert.throws(TypeError, () => equals.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => equals.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..5e517712ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const idOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id"); +Object.defineProperty(Temporal.Calendar.prototype, "id", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("id should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.equals(new Temporal.PlainYearMonth(2000, 5)); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin.js new file mode 100644 index 0000000000..13b8448d6e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: > + Tests that Temporal.PlainYearMonth.prototype.equals + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.equals), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.equals), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.equals), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.equals.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..02d8d9ee6a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar }; +instance.equals(arg); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-fields-iterable.js new file mode 100644 index 0000000000..d82f9bd6d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-fields-iterable.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal-totemporalyearmonth step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +yearmonth.equals({ year: 2005, month: 6, calendar: calendar2 }); + +assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called"); +assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-temporal-object.js new file mode 100644 index 0000000000..358f74051f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-temporal-object.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plainyearmonth.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal-totemporalyearmonth step 2.b: + b. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_). + sec-temporal-gettemporalcalendarwithisodefault step 2: + 2. Return ? ToTemporalCalendarWithISODefault(_calendar_). + sec-temporal-totemporalcalendarwithisodefault step 2: + 3. Return ? ToTemporalCalendar(_temporalCalendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, temporalObject); + yearmonth.equals({ year: 2005, month: 6, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..b9dfa79a80 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-calendar.js new file mode 100644 index 0000000000..b16fab695c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-calendar.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: equals() takes the calendar into account +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +class CustomCalendar extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this._id = id; + } + get id() { + actual.push(this._id); + return this._id; + } + toString() { + TemporalHelpers.assertUnreachable("should not call toString"); + } +} + +const sharedCalendar = new CustomCalendar("a"); +const ym1 = new Temporal.PlainYearMonth(2000, 1, sharedCalendar, 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, sharedCalendar, 1); +assert.sameValue(ym1.equals(ym2), true); +assert.compareArray(actual, [], "should not call toString if objects are equal"); + +const ym3 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("b"), 1); +const ym4 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("c"), 2); +assert.sameValue(ym3.equals(ym4), false); +assert.compareArray(actual, [], "should not call toString if ISO dates differ"); + +const ym5 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("d"), 1); +const ym6 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("e"), 1); +assert.sameValue(ym5.equals(ym6), false); +assert.compareArray(actual, ["d", "e"], "order of operations"); + +actual.splice(0); // empty it for the next check +const ym7 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("f"), 1); +const ym8 = new Temporal.PlainYearMonth(2000, 1, new CustomCalendar("f"), 1); +assert.sameValue(ym7.equals(ym8), true); +assert.compareArray(actual, ["f", "f"], "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-reference-day.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-reference-day.js new file mode 100644 index 0000000000..12a1ebcfe6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/compare-reference-day.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: equals() takes the reference day into account +features: [Temporal] +---*/ + +const iso = Temporal.Calendar.from("iso8601"); +const ym1 = new Temporal.PlainYearMonth(2000, 1, iso, 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, iso, 2); +assert.sameValue(ym1.equals(ym2), false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..a86af5a09d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/duplicate-calendar-fields.js new file mode 100644 index 0000000000..028b5de48e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['month'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + + assert.throws(RangeError, () => instance.equals(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..51b7eb7e73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/infinity-throws-rangeerror.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.prototype.equals +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const base = { year: 2000, month: 5 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + assert.throws(RangeError, () => instance.equals({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.equals({ ...base, [prop]: obj })); + assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/leap-second.js new file mode 100644 index 0000000000..ecfb5aa8e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/leap-second.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for PlainYearMonth +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2016, 12); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.equals(arg); +assert.sameValue( + result1, + true, + "leap second is a valid ISO string for PlainYearMonth" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +const result2 = instance.equals(arg); +assert.sameValue( + result2, + true, + "second: 60 is ignored in property bag for PlainYearMonth" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/length.js new file mode 100644 index 0000000000..844a0f96da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.equals.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.equals, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/name.js new file mode 100644 index 0000000000..686b5adae1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: Temporal.PlainYearMonth.prototype.equals.name is "equals". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.equals, "name", { + value: "equals", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/not-a-constructor.js new file mode 100644 index 0000000000..77c8d7e6eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.equals +description: > + Temporal.PlainYearMonth.prototype.equals does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.equals(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.equals), false, + "isConstructor(Temporal.PlainYearMonth.prototype.equals)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..8da8c28acc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: The "equals" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.equals, + "function", + "`typeof PlainYearMonth.prototype.equals` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/proto-in-calendar-fields.js new file mode 100644 index 0000000000..cf77b12b86 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/use-internal-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/use-internal-slots.js new file mode 100644 index 0000000000..a7d728148c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/use-internal-slots.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: equals() ignores the observable properties and uses internal slots +features: [Temporal] +---*/ + +function CustomError() {} + +class AvoidGettersYearMonth extends Temporal.PlainYearMonth { + get year() { + throw new CustomError(); + } + get month() { + throw new CustomError(); + } +} + +const one = new AvoidGettersYearMonth(2000, 5); +const two = new AvoidGettersYearMonth(2006, 3); +assert.sameValue(one.equals(two), false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/year-zero.js new file mode 100644 index 0000000000..97c0979390 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/equals/year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-06", + "-000000-06-24", + "-000000-06-24T15:43:27", + "-000000-06-24T15:43:27+01:00", + "-000000-06-24T15:43:27+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/branding.js new file mode 100644 index 0000000000..e98b91f378 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getcalendar +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getCalendar = Temporal.PlainYearMonth.prototype.getCalendar; + +assert.sameValue(typeof getCalendar, "function"); + +assert.throws(TypeError, () => getCalendar.call(undefined), "undefined"); +assert.throws(TypeError, () => getCalendar.call(null), "null"); +assert.throws(TypeError, () => getCalendar.call(true), "true"); +assert.throws(TypeError, () => getCalendar.call(""), "empty string"); +assert.throws(TypeError, () => getCalendar.call(Symbol()), "symbol"); +assert.throws(TypeError, () => getCalendar.call(1), "1"); +assert.throws(TypeError, () => getCalendar.call({}), "plain object"); +assert.throws(TypeError, () => getCalendar.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => getCalendar.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/builtin.js new file mode 100644 index 0000000000..dd5e96de16 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getcalendar +description: > + Tests that Temporal.PlainYearMonth.prototype.getCalendar + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.getCalendar), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.getCalendar), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.getCalendar), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.getCalendar.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/length.js new file mode 100644 index 0000000000..197adcd4d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getcalendar +description: Temporal.PlainYearMonth.prototype.getCalendar.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.getCalendar, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/name.js new file mode 100644 index 0000000000..80d117d82e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getcalendar +description: Temporal.PlainYearMonth.prototype.getCalendar.name is "getCalendar". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.getCalendar, "name", { + value: "getCalendar", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/not-a-constructor.js new file mode 100644 index 0000000000..4da964f6cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getcalendar +description: > + Temporal.PlainYearMonth.prototype.getCalendar does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.getCalendar(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.getCalendar), false, + "isConstructor(Temporal.PlainYearMonth.prototype.getCalendar)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/prop-desc.js new file mode 100644 index 0000000000..76161c39d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getcalendar +description: The "getCalendar" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.getCalendar, + "function", + "`typeof PlainYearMonth.prototype.getCalendar` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "getCalendar", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getCalendar/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/branding.js new file mode 100644 index 0000000000..c8b335d42a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getisofields +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getISOFields = Temporal.PlainYearMonth.prototype.getISOFields; + +assert.sameValue(typeof getISOFields, "function"); + +assert.throws(TypeError, () => getISOFields.call(undefined), "undefined"); +assert.throws(TypeError, () => getISOFields.call(null), "null"); +assert.throws(TypeError, () => getISOFields.call(true), "true"); +assert.throws(TypeError, () => getISOFields.call(""), "empty string"); +assert.throws(TypeError, () => getISOFields.call(Symbol()), "symbol"); +assert.throws(TypeError, () => getISOFields.call(1), "1"); +assert.throws(TypeError, () => getISOFields.call({}), "plain object"); +assert.throws(TypeError, () => getISOFields.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => getISOFields.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/builtin.js new file mode 100644 index 0000000000..802f49025f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: > + Tests that Temporal.PlainYearMonth.prototype.getISOFields + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.getISOFields), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.getISOFields), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.getISOFields), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.getISOFields.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/custom.js new file mode 100644 index 0000000000..66cdc86229 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/custom.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.getisofields +description: getISOFields does not call into user code. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarThrowEverything(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +const result = instance.getISOFields(); + +assert.sameValue(result.isoYear, 2000, "isoYear result"); +assert.sameValue(result.isoMonth, 5, "isoMonth result"); +assert.sameValue(result.isoDay, 1, "isoDay result"); +assert.sameValue(result.calendar, calendar, "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-names.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-names.js new file mode 100644 index 0000000000..e655c4af18 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-names.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: Correct field names on the object returned from getISOFields +features: [Temporal] +---*/ + +const ym = new Temporal.PlainYearMonth(2000, 5); + +const result = ym.getISOFields(); +assert.sameValue(result.isoYear, 2000, "isoYear result"); +assert.sameValue(result.isoMonth, 5, "isoMonth result"); +assert.sameValue(result.isoDay, 1, "isoDay result"); +assert.sameValue(result.calendar, "iso8601", "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-prop-desc.js new file mode 100644 index 0000000000..cc86065908 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-prop-desc.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: Properties on the returned object have the correct descriptor +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +const expected = [ + "calendar", + "isoDay", + "isoMonth", + "isoYear", +]; + +const ym = new Temporal.PlainYearMonth(2000, 5); +const result = ym.getISOFields(); + +for (const property of expected) { + verifyProperty(result, property, { + writable: true, + enumerable: true, + configurable: true, + }); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-traversal-order.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-traversal-order.js new file mode 100644 index 0000000000..0134ca0cbd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/field-traversal-order.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: Properties added in correct order to object returned from getISOFields +includes: [compareArray.js] +features: [Temporal] +---*/ + +const expected = [ + "calendar", + "isoDay", + "isoMonth", + "isoYear", +]; + +const ym = new Temporal.PlainYearMonth(2000, 5); +const result = ym.getISOFields(); + +assert.compareArray(Object.keys(result), expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/length.js new file mode 100644 index 0000000000..ce4b0d448f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getisofields +description: Temporal.PlainYearMonth.prototype.getISOFields.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.getISOFields, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/name.js new file mode 100644 index 0000000000..5294ab200d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: Temporal.PlainYearMonth.prototype.getISOFields.name is "getISOFields". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.getISOFields, "name", { + value: "getISOFields", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/not-a-constructor.js new file mode 100644 index 0000000000..c1b408b939 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.getisofields +description: > + Temporal.PlainYearMonth.prototype.getISOFields does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.getISOFields(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.getISOFields), false, + "isConstructor(Temporal.PlainYearMonth.prototype.getISOFields)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prop-desc.js new file mode 100644 index 0000000000..654a834e03 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.getisofields +description: The "getISOFields" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.getISOFields, + "function", + "`typeof PlainYearMonth.prototype.getISOFields` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "getISOFields", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prototype.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prototype.js new file mode 100644 index 0000000000..7f6bdda8ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/prototype.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.getisofields +description: Correct prototype on the object returned from getISOFields +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const result = instance.getISOFields(); +assert.sameValue(Object.getPrototypeOf(result), Object.prototype, "prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/getISOFields/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/basic.js new file mode 100644 index 0000000000..3797a79e4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/basic.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.inleapyear +description: Basic test for inLeapYear +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainYearMonth(1976, 11)).inLeapYear, + true, "leap year"); +assert.sameValue((new Temporal.PlainYearMonth(1977, 11)).inLeapYear, + false, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/branding.js new file mode 100644 index 0000000000..d89a21bde5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.inleapyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const inLeapYear = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "inLeapYear").get; + +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.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => inLeapYear.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..a826d38570 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.inleapyear +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const inLeapYearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "inLeapYear"); +Object.defineProperty(Temporal.Calendar.prototype, "inLeapYear", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("inLeapYear should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.inLeapYear; + +Object.defineProperty(Temporal.Calendar.prototype, "inLeapYear", inLeapYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/custom.js new file mode 100644 index 0000000000..f131227eac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.inleapyear +description: Custom calendar tests for inLeapYear(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + inLeapYear(...args) { + ++calls; + assert.compareArray(args, [instance], "inLeapYear arguments"); + return true; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.inLeapYear; +assert.sameValue(result, true, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/prop-desc.js new file mode 100644 index 0000000000..ab83da7706 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.inleapyear +description: The "inLeapYear" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "inLeapYear"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/validate-calendar-value.js new file mode 100644 index 0000000000..dbcb59baec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/validate-calendar-value.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.inleapyear +description: Validate result returned from calendar inLeapYear() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [null, TypeError], + [0, TypeError], + [-0, TypeError], + [42, TypeError], + [7.1, TypeError], + [NaN, TypeError], + [Infinity, TypeError], + [-Infinity, TypeError], + ["", TypeError], + ["a string", TypeError], + ["0", TypeError], + [Symbol("foo"), TypeError], + [0n, TypeError], + [42n, TypeError], + [{}, TypeError], + [{valueOf() { return false; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + inLeapYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.inLeapYear, `${typeof result} ${String(result)} not converted to boolean`); +}); + +const preservedResults = [ + true, + false, +]; + +preservedResults.forEach(result => { + const calendar = new class extends Temporal.Calendar { + inLeapYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.sameValue(instance.inLeapYear, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/branding.js new file mode 100644 index 0000000000..5f69bd865d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.month +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const month = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "month").get; + +assert.sameValue(typeof month, "function"); + +assert.throws(TypeError, () => month.call(undefined), "undefined"); +assert.throws(TypeError, () => month.call(null), "null"); +assert.throws(TypeError, () => month.call(true), "true"); +assert.throws(TypeError, () => month.call(""), "empty string"); +assert.throws(TypeError, () => month.call(Symbol()), "symbol"); +assert.throws(TypeError, () => month.call(1), "1"); +assert.throws(TypeError, () => month.call({}), "plain object"); +assert.throws(TypeError, () => month.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => month.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..5750040a72 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.month +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const monthOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "month"); +Object.defineProperty(Temporal.Calendar.prototype, "month", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("month should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.month; + +Object.defineProperty(Temporal.Calendar.prototype, "month", monthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/custom.js new file mode 100644 index 0000000000..64afcd70f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.month +description: Custom calendar tests for month(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + month(...args) { + ++calls; + assert.compareArray(args, [instance], "month arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.month; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/prop-desc.js new file mode 100644 index 0000000000..b4f16e85ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.month +description: The "month" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "month"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/validate-calendar-value.js new file mode 100644 index 0000000000..2beafb2476 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/month/validate-calendar-value.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.month +description: Validate result returned from calendar month() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [null, TypeError], + [false, TypeError], + [Infinity, RangeError], + [-Infinity, RangeError], + [NaN, RangeError], + [-7, RangeError], + [-0.1, RangeError], + ["string", TypeError], + [Symbol("foo"), TypeError], + [7n, TypeError], + [{}, TypeError], + [true, TypeError], + [7.1, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + month() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.month, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/branding.js new file mode 100644 index 0000000000..d6b41374a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthcode +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthCode = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "monthCode").get; + +assert.sameValue(typeof monthCode, "function"); + +assert.throws(TypeError, () => monthCode.call(undefined), "undefined"); +assert.throws(TypeError, () => monthCode.call(null), "null"); +assert.throws(TypeError, () => monthCode.call(true), "true"); +assert.throws(TypeError, () => monthCode.call(""), "empty string"); +assert.throws(TypeError, () => monthCode.call(Symbol()), "symbol"); +assert.throws(TypeError, () => monthCode.call(1), "1"); +assert.throws(TypeError, () => monthCode.call({}), "plain object"); +assert.throws(TypeError, () => monthCode.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => monthCode.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..d3db8ede45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.monthcode +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const monthCodeOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "monthCode"); +Object.defineProperty(Temporal.Calendar.prototype, "monthCode", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("monthCode should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.monthCode; + +Object.defineProperty(Temporal.Calendar.prototype, "monthCode", monthCodeOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/custom.js new file mode 100644 index 0000000000..bb7255b0ee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthcode +description: Custom calendar tests for monthCode(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + monthCode(...args) { + ++calls; + assert.compareArray(args, [instance], "monthCode arguments"); + return "M01"; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.monthCode; +assert.sameValue(result, "M01", "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/prop-desc.js new file mode 100644 index 0000000000..00fd595d89 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthcode +description: The "monthCode" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "monthCode"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/validate-calendar-value.js new file mode 100644 index 0000000000..49326950bd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthCode/validate-calendar-value.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthcode +description: Validate result returned from calendar monthCode() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [Symbol("foo"), TypeError], + [null, TypeError], + [true, TypeError], + [false, TypeError], + [7.1, TypeError], + [{toString() { return "M01"; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + monthCode() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.monthCode, `${typeof result} ${String(result)} not converted to string`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/basic.js new file mode 100644 index 0000000000..9b6c340271 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/basic.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthsinyear +description: monthsInYear works +features: [Temporal] +---*/ + +const ym = new Temporal.PlainYearMonth(1976, 11); +assert.sameValue(ym.monthsInYear, 12); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/branding.js new file mode 100644 index 0000000000..a96c7b5a5f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthsinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthsInYear = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "monthsInYear").get; + +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.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => monthsInYear.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..1ecaeffa7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.monthsinyear +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const monthsInYearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "monthsInYear"); +Object.defineProperty(Temporal.Calendar.prototype, "monthsInYear", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("monthsInYear should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.monthsInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "monthsInYear", monthsInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/custom.js new file mode 100644 index 0000000000..db48e8f44f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthsinyear +description: Custom calendar tests for monthsInYear(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + monthsInYear(...args) { + ++calls; + assert.compareArray(args, [instance], "monthsInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.monthsInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/prop-desc.js new file mode 100644 index 0000000000..b877378c7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthsinyear +description: The "monthsInYear" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "monthsInYear"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/validate-calendar-value.js new file mode 100644 index 0000000000..a06c23ef68 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/validate-calendar-value.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.monthsinyear +description: Validate result returned from calendar monthsInYear() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [null, TypeError], + [false, TypeError], + [Infinity, RangeError], + [-Infinity, RangeError], + [NaN, RangeError], + [-7, RangeError], + [-0.1, RangeError], + ["string", TypeError], + [Symbol("foo"), TypeError], + [7n, TypeError], + [{}, TypeError], + [true, TypeError], + [7.1, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + monthsInYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.monthsInYear, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/prop-desc.js new file mode 100644 index 0000000000..3444d7fc57 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/prop-desc.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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-plainyearmonth-prototype +description: The "prototype" property of Temporal.PlainYearMonth +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue(typeof Temporal.PlainYearMonth.prototype, "object"); +assert.notSameValue(Temporal.PlainYearMonth.prototype, null); + +verifyProperty(Temporal.PlainYearMonth, "prototype", { + writable: false, + enumerable: false, + configurable: false, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..7a611af37f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-builtin-calendar-no-array-iteration.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method with a property bag argument with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar: "iso8601" }; +instance.since(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-casting.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-casting.js new file mode 100644 index 0000000000..22f10a717e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-casting.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Calls to PYM.since cast arguments. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const nov94 = new Temporal.PlainYearMonth(1994, 11); +const jun13 = new Temporal.PlainYearMonth(2013, 6); +const diff = jun13.since(nov94); + +TemporalHelpers.assertDurationsEqual(jun13.since({ year: 1994, month: 11 }), diff, 'Casts object argument'); +TemporalHelpers.assertDurationsEqual(jun13.since('1994-11'), diff, 'Casts string argument'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-number.js new file mode 100644 index 0000000000..a156c0e661 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-number.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is invalid in place of an ISO string for Temporal.PlainYearMonth +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const numbers = [ + 1, + 201906, + -201906, + 1234567, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.since(arg), + `A number (${arg}) is not a valid ISO string for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..0c2882525b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-case-insensitive.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "IsO8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.since(arg); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..4c9b860cff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-leap-second.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for a calendar in a property bag +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.since(arg); +TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..08a1caa46b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-number.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; +for (const calendar of numbers) { + const arg = { year: 2019, monthCode: "M06", calendar }; + assert.throws( + TypeError, + () => instance.since(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..94f7794ff5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-string.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "iso8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.since(arg); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..6f2564adcd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-wrong-type.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when a calendar property from a property bag cannot + be converted to a calendar object or string +features: [BigInt, Symbol, Temporal] +---*/ + +const timeZone = new Temporal.TimeZone("UTC"); +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [calendar, description] of primitiveTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws( + typeof calendar === 'string' ? RangeError : TypeError, + () => instance.since(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], + [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields() +]; + +for (const [calendar, description] of typeErrorTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws(TypeError, () => instance.since(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..6c0b70f03b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-propertybag-calendar-year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T17:45", + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+01:00", + "-000000-10-31T17:45+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..49771507ed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-calendar-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[u-ca=iso8601]", "without time zone"], + ["2019-12-15T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2019-12-15T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2019-12-15T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2019-12-15T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.since(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..5ecbd63ffa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..fc41f5a947 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-date-with-utc-offset.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 12); + +const validStrings = [ + "2019-12[Africa/Abidjan]", + "2019-12[!Africa/Abidjan]", + "2019-12[u-ca=iso8601]", + "2019-12[Africa/Abidjan][u-ca=iso8601]", + "2019-12-15T00+00:00", + "2019-12-15T00+00:00[UTC]", + "2019-12-15T00+00:00[!UTC]", + "2019-12-15T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = instance.since(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `"${arg}" is a valid UTC offset with time for PlainYearMonth` + ); +} + +const invalidStrings = [ + "2022-09[u-ca=hebrew]", + "2022-09Z", + "2022-09+01:00", + "2022-09-15Z", + "2022-09-15Z[UTC]", + "2022-09-15Z[Europe/Vienna]", + "2022-09-15+00:00", + "2022-09-15+00:00[UTC]", + "2022-09-15-02:30", + "2022-09-15-02:30[America/St_Johns]", +]; + +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.since(arg), + `"${arg}" UTC offset without time is not valid for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-invalid.js new file mode 100644 index 0000000000..8c2f08fa7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-invalid.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An invalid ISO string is never supported +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); + +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsInvalid()) { + assert.throws(RangeError, () => instance.since(arg), `"${arg}" is not a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..f2ee8748ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-calendar.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..24999eface --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-separators.js new file mode 100644 index 0000000000..266a179849 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-separators.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23", "uppercase T"], + ["2019-12-15t15:23", "lowercase T"], + ["2019-12-15 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.since(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..683d085094 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-time-zone-annotation.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[Asia/Kolkata]", "named, with no offset"], + ["2019-12-15T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["2019-12-15T15:23[+00:00]", "numeric, with no offset"], + ["2019-12-15T15:23[!-02:30]", "numeric, with ! and no offset"], + ["2019-12-15T15:23+00:00[UTC]", "named, with offset"], + ["2019-12-15T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["2019-12-15T15:23+00:00[+01:00]", "numeric, with offset"], + ["2019-12-15T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.since(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..cdc91aed7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-unknown-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[foo=bar]", "alone"], + ["2019-12-15T15:23[UTC][foo=bar]", "with time zone"], + ["2019-12-15T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2019-12-15T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2019-12-15T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.since(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..1ee9e2d49b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-with-utc-designator.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown if a string with UTC designator is used as a PlainYearMonth +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + "String with UTC designator should not be valid as a PlainYearMonth" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string.js new file mode 100644 index 0000000000..efc5c95b3f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-string.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A string argument is parsed into a PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValid()) { + const result = instance.since(arg); + TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `"${arg}" is a valid PlainYearMonth string`); +} + +const instanceNegativeYear = new Temporal.PlainYearMonth(-9999, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValidNegativeYear()) { + const result = instanceNegativeYear.since(arg); + TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `"${arg}" is a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-wrong-type.js new file mode 100644 index 0000000000..b2951d004b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/argument-wrong-type.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainYearMonth +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [undefined, "undefined"], + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => instance.since(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth, object"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.since(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/arguments-missing-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/arguments-missing-throws.js new file mode 100644 index 0000000000..4627a2af88 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/arguments-missing-throws.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Calls to PYM.since throw when missing required arguments. +features: [Temporal] +---*/ + +const jun13 = new Temporal.PlainYearMonth(2013, 6); + +assert.throws(TypeError, () => jun13.since({ year: 1994 }), 'Throws when missing required month'); +assert.throws(TypeError, () => jun13.since({ month: 11 }), 'Throws when missing required year'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/branding.js new file mode 100644 index 0000000000..5b9adf908e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const since = Temporal.PlainYearMonth.prototype.since; + +assert.sameValue(typeof since, "function"); + +const args = [new Temporal.PlainYearMonth(2022, 6)]; + +assert.throws(TypeError, () => since.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => since.apply(null, args), "null"); +assert.throws(TypeError, () => since.apply(true, args), "true"); +assert.throws(TypeError, () => since.apply("", args), "empty string"); +assert.throws(TypeError, () => since.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => since.apply(1, args), "1"); +assert.throws(TypeError, () => since.apply({}, args), "plain object"); +assert.throws(TypeError, () => since.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => since.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..2b862b8a7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.since({ year: 2005, month: 3 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..9332585b8c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dateUntilOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateUntil"); +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateUntil should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.since(new Temporal.PlainYearMonth(1999, 4)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin.js new file mode 100644 index 0000000000..c6d3d8a7c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: > + Tests that Temporal.PlainYearMonth.prototype.since + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.since), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.since), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.since), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.since.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..9ee3ebe408 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: > + relativeTo parameters that are not ZonedDateTime or undefined, are always + converted to PlainDate for observable calendar calls +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddPlainDateInstance(); +const instance = new Temporal.PlainYearMonth(1970, 1, calendar); +instance.since(new Temporal.PlainYearMonth(2000, 5, calendar), { smallestUnit: "year" }); +assert(calendar.dateAddCallCount > 0, "assertions in calendar.dateAdd() should have been tested"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..75f16cfa45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar }; +instance.since(arg); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..af2e53d56a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: 6, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..bfa120aab8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.dateUntil method is called with a null-prototype object as the + options value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +const argument = new Temporal.PlainYearMonth(2022, 6, calendar); +instance.since(argument); +assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..5c4df0383d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plainyearmonth.prototype.since steps 21–22: + 21. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _largestUnit_). + 22. Let _result_ be ? CalendarDateUntil(_calendar_, _thisDate_, _otherDate_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainYearMonth(2000, 5, calendar); + const later = new Temporal.PlainYearMonth(2001, 6, calendar); + later.since(earlier, { largestUnit }); + }, + { + years: ["year"], + months: ["month"] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fields-iterable.js new file mode 100644 index 0000000000..9404d314da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fields-iterable.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.since step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal.plainyearmonth.prototype.since step 14: + 14. Let fieldNames be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »). + sec-temporal-totemporalyearmonth step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected1 = [ + "monthCode", + "year", +]; +const expected2 = [ + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +yearmonth.since({ year: 2005, month: 6, calendar: calendar2 }); + +assert.sameValue(calendar1.fieldsCallCount, 1, "fields() method not called"); +assert.compareArray(calendar1.fieldsCalledWith[0], expected1, "fields() method called with correct args"); +assert(calendar1.iteratorExhausted[0], "iterated through the whole iterable"); +assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar2.fieldsCalledWith[0], expected2, "fields() method called with correct args"); +assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..db22d52738 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.since(new Temporal.PlainYearMonth(2019, 2)); +assert.sameValue(calendar.dateFromFieldsCallCount, 2, "dateFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-temporal-object.js new file mode 100644 index 0000000000..4bcf60f6ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-temporal-object.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plainyearmonth.prototype.since step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal-totemporalyearmonth step 2.b: + b. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_). + sec-temporal-gettemporalcalendarwithisodefault step 2: + 2. Return ? ToTemporalCalendarWithISODefault(_calendar_). + sec-temporal-totemporalcalendarwithisodefault step 2: + 3. Return ? ToTemporalCalendar(_temporalCalendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, temporalObject); + yearmonth.since({ year: 2005, month: 6, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..e1e6c19be5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..7bb6258ee7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/duplicate-calendar-fields.js new file mode 100644 index 0000000000..54cb1ae302 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['month'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + + assert.throws(RangeError, () => instance.since(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..e8aa44d442 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/infinity-throws-rangeerror.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.prototype.since +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const base = { year: 2000, month: 5 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + assert.throws(RangeError, () => instance.since({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.since({ ...base, [prop]: obj })); + assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-auto.js new file mode 100644 index 0000000000..dbcc180f93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-auto.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: auto value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(later.since(earlier, { largestUnit: "auto" }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "auto largestUnit is year (pos)"); +TemporalHelpers.assertDuration(earlier.since(later, { largestUnit: "auto" }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "auto largestUnit is year (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-disallowed-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-disallowed-units.js new file mode 100644 index 0000000000..72b038c0ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-disallowed-units.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Since throws on to0-small largestUnit +features: [Temporal, arrow-function] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +[ + 'weeks', + 'days', + 'hours', + 'minutes', + 'seconds', + 'milliseconds', + 'microseconds', + 'nanoseconds' +].forEach((largestUnit) => { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }),`throws on disallowed or invalid largestUnit: ${largestUnit}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js new file mode 100644 index 0000000000..29cf4602f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-invalid-string.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +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`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-months.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-months.js new file mode 100644 index 0000000000..61ce3f3567 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-months.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: months value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(later.since(earlier, { largestUnit: "months" }), + 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is months (pos)"); +TemporalHelpers.assertDuration(earlier.since(later, { largestUnit: "months" }), + 0, -13, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is months (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..e47e7c6112 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-plurals-accepted.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const validUnits = [ + "year", + "month", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => later.since(earlier, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..6b212d9377 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-smallestunit-mismatch.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const units = ["years", "months"]; +for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { + for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { + const largestUnit = units[largestIdx]; + const smallestUnit = units[smallestIdx]; + assert.throws(RangeError, () => later.since(earlier, { largestUnit, smallestUnit })); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-undefined.js new file mode 100644 index 0000000000..8abe071470 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-undefined.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(later.since(earlier, { largestUnit: undefined }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, pos)"); +TemporalHelpers.assertDuration(earlier.since(later, { largestUnit: undefined }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, neg)"); + +TemporalHelpers.assertDuration(later.since(earlier, {}), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, pos)"); +TemporalHelpers.assertDuration(earlier.since(later, {}), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, neg)"); + +TemporalHelpers.assertDuration(later.since(earlier, () => {}), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (arrow function, pos)"); +TemporalHelpers.assertDuration(earlier.since(later, () => {}), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (arrow function, neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-wrong-type.js new file mode 100644 index 0000000000..17711d11e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "month", + (largestUnit) => later.since(earlier, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-years.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-years.js new file mode 100644 index 0000000000..b5d8cea58a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/largestunit-years.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: years value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(later.since(earlier, { largestUnit: "years" }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is years (pos)"); +TemporalHelpers.assertDuration(earlier.since(later, { largestUnit: "years" }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is years (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/leap-second.js new file mode 100644 index 0000000000..1ad065f65a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/leap-second.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2016, 12); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.since(arg); +TemporalHelpers.assertDuration( + result1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "leap second is a valid ISO string for PlainYearMonth" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +const result2 = instance.since(arg); +TemporalHelpers.assertDuration( + result2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "second: 60 is ignored in property bag for PlainYearMonth" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/length.js new file mode 100644 index 0000000000..2883b71ed8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.since.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.since, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/mixed-calendar-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/mixed-calendar-invalid.js new file mode 100644 index 0000000000..9db026f10b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/mixed-calendar-invalid.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Mixed calendars throw as invalid +features: [Temporal] +---*/ + +class customCal extends Temporal.Calendar { + constructor () { + super('iso8601'); + } + + get id() { + return "I am a secret cal."; + } +} + +const ym1 = new Temporal.PlainYearMonth(2000, 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, new customCal()); + +assert.throws(RangeError, () => ym1.since(ym2), 'since throws with different calendars'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/name.js new file mode 100644 index 0000000000..29a276f95f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Temporal.PlainYearMonth.prototype.since.name is "since". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.since, "name", { + value: "since", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/not-a-constructor.js new file mode 100644 index 0000000000..69770b793b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: > + Temporal.PlainYearMonth.prototype.since does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.since(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.since), false, + "isConstructor(Temporal.PlainYearMonth.prototype.since)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-invalid.js new file mode 100644 index 0000000000..822d4570a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-invalid.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Verify that invalid options are handled correctly. +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainYearMonth(2020, 2); +const feb21 = new Temporal.PlainYearMonth(2021, 2); + +[ + null, + 1, + 'hello', + true, + Symbol('foo'), + 1n +].forEach((badOption) => + assert.throws(TypeError, () => feb21.since(feb20, badOption), `${String(badOption)} throws TypeError`) +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-object.js new file mode 100644 index 0000000000..dacf123949 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-object.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.since(new Temporal.PlainYearMonth(1976, 11), {}); +TemporalHelpers.assertDuration( + result1, 42, 11, 0, 0, 0, 0, 0, 0, 0, 0, + "options may be an empty plain object" +); + +const result2 = instance.since(new Temporal.PlainYearMonth(1976, 11), () => {}); +TemporalHelpers.assertDuration( + result2, 42, 11, 0, 0, 0, 0, 0, 0, 0, 0, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-undefined.js new file mode 100644 index 0000000000..29fc58b30a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-undefined.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Verify that undefined options are handled correctly. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2002, 12); + +TemporalHelpers.assertDuration(later.since(earlier, undefined), + 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, pos)"); +TemporalHelpers.assertDuration(earlier.since(later, undefined), + -2, -7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, neg)"); + +TemporalHelpers.assertDuration(later.since(earlier), + 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, pos)"); +TemporalHelpers.assertDuration(earlier.since(later), + -2, -7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js new file mode 100644 index 0000000000..5a166db02a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js new file mode 100644 index 0000000000..d5ca77eff3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js @@ -0,0 +1,192 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expectedMinimal = [ + // ToTemporalYearMonth + "get other.calendar", + "has other.calendar.dateAdd", + "has other.calendar.dateFromFields", + "has other.calendar.dateUntil", + "has other.calendar.day", + "has other.calendar.dayOfWeek", + "has other.calendar.dayOfYear", + "has other.calendar.daysInMonth", + "has other.calendar.daysInWeek", + "has other.calendar.daysInYear", + "has other.calendar.fields", + "has other.calendar.id", + "has other.calendar.inLeapYear", + "has other.calendar.mergeFields", + "has other.calendar.month", + "has other.calendar.monthCode", + "has other.calendar.monthDayFromFields", + "has other.calendar.monthsInYear", + "has other.calendar.weekOfYear", + "has other.calendar.year", + "has other.calendar.yearMonthFromFields", + "has other.calendar.yearOfWeek", + "get other.calendar.fields", + "get other.calendar.yearMonthFromFields", + "call other.calendar.fields", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "call other.calendar.yearMonthFromFields", + // CalendarEquals + "get this.calendar.id", + "get other.calendar.id", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.roundingIncrement", + "get options.roundingIncrement", + "getOwnPropertyDescriptor options.roundingMode", + "get options.roundingMode", + "getOwnPropertyDescriptor options.largestUnit", + "get options.largestUnit", + "getOwnPropertyDescriptor options.smallestUnit", + "get options.smallestUnit", + "getOwnPropertyDescriptor options.additional", + "get options.additional", + // GetDifferenceSettings + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", +]; + +const expected = expectedMinimal.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.dateUntil", + "get this.calendar.fields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields / CalendarDateFromFields (receiver) + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + "call this.calendar.dateFromFields", + // PrepareTemporalFields / CalendarDateFromFields (argument) + "get other.calendar.monthCode", + "call other.calendar.monthCode", + "get other.calendar.year", + "call other.calendar.year", + "call this.calendar.dateFromFields", + // CalendarDateUntil + "call this.calendar.dateUntil", +]); +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); + +const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "months", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0); + +// code path that skips RoundDuration: +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 1 })); +assert.compareArray(actual, expected, "order of operations with no rounding"); +actual.splice(0); // clear + +// short-circuit for identical objects: +const identicalPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.since(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expectedMinimal, "order of operations with identical year-months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + // RoundDuration + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateUntil", // 7.o + "call this.calendar.dateAdd", // 7.y MoveRelativeDate + // (7.s not called because other units can't add up to >1 year at this point) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call +const otherYearMonthPropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate + // (7.o not called because months and weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.since(otherYearMonthPropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + // RoundDuration + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate + // (10.n.iii MoveRelativeDate not called because weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil" // 10.e +]); +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 2 })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/prop-desc.js new file mode 100644 index 0000000000..252d36870d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: The "since" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.since, + "function", + "`typeof PlainYearMonth.prototype.since` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "since", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/proto-in-calendar-fields.js new file mode 100644 index 0000000000..9a2d96724b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/round-cross-unit-boundary.js new file mode 100644 index 0000000000..89a4645edd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/round-cross-unit-boundary.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2022, 1); +const later = new Temporal.PlainYearMonth(2023, 12); +const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingIncrement: 3, roundingMode: "expand" }); +TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -12 months balances to -2 years"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/rounding-zero-year-month-length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/rounding-zero-year-month-length.js new file mode 100644 index 0000000000..c91f5bab6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/rounding-zero-year-month-length.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + A malicious calendar resulting in a year, month, or week length of zero is + handled correctly +info: | + RoundDuration + 10.z. If _oneYearDays_ = 0, throw a *RangeError* exception. + ... + 11.z. If _oneMonthDays_ = 0, throw a *RangeError* exception. + ... + 12.s. If _oneWeekDays_ = 0, throw a *RangeError* exception. +features: [Temporal] +---*/ + +const cal = new class extends Temporal.Calendar { + dateAdd(date, duration, options) { + // Called several times, last call sets oneYear/Month/WeekDays to 0 + return new Temporal.PlainDate(1970, 1, 1); + } +}("iso8601"); + +const ym1 = new Temporal.PlainYearMonth(1970, 1, cal); +const ym2 = new Temporal.PlainYearMonth(1971, 1, cal); + +assert.throws(RangeError, () => ym1.since(ym2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => ym1.since(ym2, { smallestUnit: "months", roundingIncrement: 2 }), "zero month length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js new file mode 100644 index 0000000000..4baad1a8f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Since rounding increments work as expected +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const laterSinceYear = later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }); +TemporalHelpers.assertDuration(laterSinceYear, + /* years = */ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of years"); + +const laterSinceMixed = later.since(earlier, { smallestUnit: "months", roundingIncrement: 5 }); +TemporalHelpers.assertDuration(laterSinceMixed, + /* years = */ 2, /* months = */ 5, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of months mixed with years"); + +const laterSinceMonth = later.since(earlier, { largestUnit: "months", smallestUnit: "months", roundingIncrement: 10 }); +TemporalHelpers.assertDuration(laterSinceMonth, + 0, /* months = */ 30, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of pure months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-nan.js new file mode 100644 index 0000000000..b6fd705a95 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-nan.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when roundingIncrement option is NaN +info: | + sec-getoption step 8.b: + b. If _value_ is *NaN*, throw a *RangeError* exception. + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.since step 13: + 13. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-non-integer.js new file mode 100644 index 0000000000..b0a7983f1a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-non-integer.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Rounding for roundingIncrement option +info: | + ToTemporalRoundingIncrement ( _normalizedOptions_ ) + + 1. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, *"number"*, *undefined*, *1*<sub>𝔽</sub>). + 2. If _increment_ is not finite, throw a *RangeError* exception. + 3. Let _integerIncrement_ be truncate(ℝ(_increment_)). + 4. If _integerIncrement_ < 1 or _integerIncrement_ > 10<sup>9</sup>, throw a *RangeError* exception. + 5. Return _integerIncrement_. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2000, 10); +const result = later.since(earlier, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, "roundingIncrement 2.5 truncates to 2"); +// Cannot test the upper bound of 1e9 + 0.5 here, because the duration is +// rounded relative to the receiver PlainYearMonth, and 1e9 months is outside of +// the PlainYearMonth range. + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..2a75b13429 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-out-of-range.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when roundingIncrement option out of range +info: | + ToTemporalRoundingIncrement ( _normalizedOptions_ ) + + 1. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, *"number"*, *undefined*, *1*<sub>𝔽</sub>). + 2. If _increment_ is not finite, throw a *RangeError* exception. + 3. Let _integerIncrement_ be truncate(ℝ(_increment_)). + 4. If _integerIncrement_ < 1 or _integerIncrement_ > 10<sup>9</sup>, throw a *RangeError* exception. + 5. Return _integerIncrement_. +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2000, 10); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: -Infinity })); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: -1 })); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: 0 })); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: 0.9 })); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: 1e9 + 1 })); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: Infinity })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-undefined.js new file mode 100644 index 0000000000..b0aee1cfb8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Fallback value for roundingIncrement option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.since step 13: + 13. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +const explicit = later.since(earlier, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..5760d55317 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Type conversions for roundingIncrement option +info: | + sec-getoption step 8.a: + a. Set _value_ to ? ToNumber(value). + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.since step 13: + 13. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => later.since(earlier, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-ceil.js new file mode 100644 index 0000000000..1a0df86da5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-ceil.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-2]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "ceil"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-expand.js new file mode 100644 index 0000000000..dda697ab6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-expand.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "expand"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-floor.js new file mode 100644 index 0000000000..43295a8cb0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-floor.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [2], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "floor"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfCeil.js new file mode 100644 index 0000000000..c1c743a1ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfCeil.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfCeil"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfEven.js new file mode 100644 index 0000000000..1d264b755a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfEven.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfEven"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfExpand.js new file mode 100644 index 0000000000..e68173a741 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfExpand.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfExpand"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfFloor.js new file mode 100644 index 0000000000..cdd03d23af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfFloor.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfFloor"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..55b3f2a109 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-halfTrunc.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfTrunc"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-invalid-string.js new file mode 100644 index 0000000000..f4b95b6588 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-invalid-string.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +for (const roundingMode of ["other string", "cile", "CEIL", "ce\u0131l", "auto", "halfexpand", "floor\0"]) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit: "microsecond", roundingMode })); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-trunc.js new file mode 100644 index 0000000000..a8b5763120 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-trunc.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [2], [-2]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "trunc"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + earlier.since(later, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-undefined.js new file mode 100644 index 0000000000..b87ea94053 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-undefined.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 1); + +const later1 = new Temporal.PlainYearMonth(2005, 2); +const explicit1 = later1.since(earlier, { smallestUnit: "year", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); +const implicit1 = later1.since(earlier, { smallestUnit: "year" }); +TemporalHelpers.assertDuration(implicit1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); + +const later2 = new Temporal.PlainYearMonth(2005, 12); +const explicit2 = later2.since(earlier, { smallestUnit: "year", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); +const implicit2 = later2.since(earlier, { smallestUnit: "year" }); +TemporalHelpers.assertDuration(implicit2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-wrong-type.js new file mode 100644 index 0000000000..d31c4709c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingmode-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "trunc", + (roundingMode) => later.since(earlier, { smallestUnit: "year", roundingMode }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js new file mode 100644 index 0000000000..ff7ea1df01 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-invalid-string.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +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`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..147d14b4cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-plurals-accepted.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const validUnits = [ + "year", + "month", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => later.since(earlier, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-undefined.js new file mode 100644 index 0000000000..a041e0b4d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-undefined.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +const explicit = later.since(earlier, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default smallestUnit is month"); +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default smallestUnit is month"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-wrong-type.js new file mode 100644 index 0000000000..d25b44a89c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/smallestunit-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "year", + (smallestUnit) => later.since(earlier, { smallestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/symmetry.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/symmetry.js new file mode 100644 index 0000000000..f5d8a8396a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/symmetry.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.since +description: Since observes symmetry with until +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const nov94 = new Temporal.PlainYearMonth(1994, 11); +const jun13 = new Temporal.PlainYearMonth(2013, 6); +const diff = jun13.since(nov94); + +TemporalHelpers.assertDurationsEqual(diff, nov94.until(jun13), 'Since is inverse of until'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/year-zero.js new file mode 100644 index 0000000000..5558dc3927 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/since/year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-06", + "-000000-06-24", + "-000000-06-24T15:43:27", + "-000000-06-24T15:43:27+01:00", + "-000000-06-24T15:43:27+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-max.js new file mode 100644 index 0000000000..2396a974c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-max.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1970, 1); + +const maxCases = [ + ["P273790Y8M42DT23H59M59.999999999S", "string with max years"], + [{ years: 273790, months: 8, days: 42, nanoseconds: 86399999999999 }, "property bag with max years"], + ["P3285488M42DT23H59M59.999999999S", "string with max months"], + [{ months: 3285488, days: 42, nanoseconds: 86399999999999 }, "property bag with max months"], + ["P14285718W5DT23H59M59.999999999S", "string with max weeks"], + [{ weeks: 14285718, days: 5, nanoseconds: 86399999999999 }, "property bag with max weeks"], + ["P100000031DT23H59M59.999999999S", "string with max days"], + [{ days: 100000031, nanoseconds: 86399999999999 }, "property bag with max days"], + ["PT2400000767H59M59.999999999S", "string with max hours"], + [{ hours: 2400000767, nanoseconds: 3599999999999 }, "property bag with max hours"], + ["PT144000046079M59.999999999S", "string with max minutes"], + [{ minutes: 144000046079, nanoseconds: 59999999999 }, "property bag with max minutes"], + ["PT8640002764799.999999999S", "string with max seconds"], + [{ seconds: 8640002764799, nanoseconds: 999999999 }, "property bag with max seconds"], +]; + +for (const [arg, descr] of maxCases) { + const result = instance.subtract(arg); + TemporalHelpers.assertPlainYearMonth(result, -271821, 4, "M04", `operation succeeds with ${descr}`); +} + +const minCases = [ + ["-P273790Y8M12DT23H59M59.999999999S", "string with min years"], + [{ years: -273790, months: -8, days: -12, nanoseconds: -86399999999999 }, "property bag with min years"], + ["-P3285488M12DT23H59M59.999999999S", "string with min months"], + [{ months: -3285488, days: -12, nanoseconds: -86399999999999 }, "property bag with min months"], + ["-P14285714W2DT23H59M59.999999999S", "string with min weeks"], + [{ weeks: -14285714, days: -2, nanoseconds: -86399999999999 }, "property bag with min weeks"], + ["-P100000000DT23H59M59.999999999S", "string with min days"], + [{ days: -100000000, nanoseconds: -86399999999999 }, "property bag with min days"], + ["-PT2400000023H59M59.999999999S", "string with min hours"], + [{ hours: -2400000023, nanoseconds: -3599999999999 }, "property bag with min hours"], + ["-PT144000001439M59.999999999S", "string with min minutes"], + [{ minutes: -144000001439, nanoseconds: -59999999999 }, "property bag with min minutes"], + ["-PT8640000086399.999999999S", "string with min seconds"], + [{ seconds: -8640000086399, nanoseconds: -999999999 }, "property bag with min seconds"], +]; + +for (const [arg, descr] of minCases) { + const result = instance.subtract(arg); + TemporalHelpers.assertPlainYearMonth(result, 275760, 9, "M09", `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-object.js new file mode 100644 index 0000000000..3d72383b35 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-object.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A Duration object is supported as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const jun13 = Temporal.PlainYearMonth.from("2013-06"); +const diff = Temporal.Duration.from("P18Y7M"); +TemporalHelpers.assertPlainYearMonth(jun13.subtract(diff), 1994, 11, "M11"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-out-of-range.js new file mode 100644 index 0000000000..d0977de87a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-duration-out-of-range.js @@ -0,0 +1,75 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1970, 1); + +const cases = [ + // 2^32 = 4294967296 + ["P4294967296Y", "string with years > max"], + [{ years: 4294967296 }, "property bag with years > max"], + ["-P4294967296Y", "string with years < min"], + [{ years: -4294967296 }, "property bag with years < min"], + ["P4294967296M", "string with months > max"], + [{ months: 4294967296 }, "property bag with months > max"], + ["-P4294967296M", "string with months < min"], + [{ months: -4294967296 }, "property bag with months < min"], + ["P4294967296W", "string with weeks > max"], + [{ weeks: 4294967296 }, "property bag with weeks > max"], + ["-P4294967296W", "string with weeks < min"], + [{ weeks: -4294967296 }, "property bag with weeks < min"], + + // ceil(max safe integer / 86400) = 104249991375 + ["P104249991375D", "string with days > max"], + [{ days: 104249991375 }, "property bag with days > max"], + ["P104249991374DT24H", "string where hours balance into days > max"], + [{ days: 104249991374, hours: 24 }, "property bag where hours balance into days > max"], + ["-P104249991375D", "string with days < min"], + [{ days: -104249991375 }, "property bag with days < min"], + ["-P104249991374DT24H", "string where hours balance into days < min"], + [{ days: -104249991374, hours: -24 }, "property bag where hours balance into days < min"], + + // ceil(max safe integer / 3600) = 2501999792984 + ["PT2501999792984H", "string with hours > max"], + [{ hours: 2501999792984 }, "property bag with hours > max"], + ["PT2501999792983H60M", "string where minutes balance into hours > max"], + [{ hours: 2501999792983, minutes: 60 }, "property bag where minutes balance into hours > max"], + ["-PT2501999792984H", "string with hours < min"], + [{ hours: -2501999792984 }, "property bag with hours < min"], + ["-PT2501999792983H60M", "string where minutes balance into hours < min"], + [{ hours: -2501999792983, minutes: -60 }, "property bag where minutes balance into hours < min"], + + // ceil(max safe integer / 60) = 150119987579017 + ["PT150119987579017M", "string with minutes > max"], + [{ minutes: 150119987579017 }, "property bag with minutes > max"], + ["PT150119987579016M60S", "string where seconds balance into minutes > max"], + [{ minutes: 150119987579016, seconds: 60 }, "property bag where seconds balance into minutes > max"], + ["-PT150119987579017M", "string with minutes < min"], + [{ minutes: -150119987579017 }, "property bag with minutes < min"], + ["-PT150119987579016M60S", "string where seconds balance into minutes < min"], + [{ minutes: -150119987579016, seconds: -60 }, "property bag where seconds balance into minutes < min"], + + // 2^53 = 9007199254740992 + ["PT9007199254740992S", "string with seconds > max"], + [{ seconds: 9007199254740992 }, "property bag with seconds > max"], + [{ seconds: 9007199254740991, milliseconds: 1000 }, "property bag where milliseconds balance into seconds > max"], + [{ seconds: 9007199254740991, microseconds: 1000000 }, "property bag where microseconds balance into seconds > max"], + [{ seconds: 9007199254740991, nanoseconds: 1000000000 }, "property bag where nanoseconds balance into seconds > max"], + ["-PT9007199254740992S", "string with seconds < min"], + [{ seconds: -9007199254740992 }, "property bag with seconds < min"], + [{ seconds: -9007199254740991, milliseconds: -1000 }, "property bag where milliseconds balance into seconds < min"], + [{ seconds: -9007199254740991, microseconds: -1000000 }, "property bag where microseconds balance into seconds < min"], + [{ seconds: -9007199254740991, nanoseconds: -1000000000 }, "property bag where nanoseconds balance into seconds < min"], +]; + +for (const [arg, descr] of cases) { + assert.throws(RangeError, () => instance.subtract(arg), `${descr} is out of range`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-invalid-property.js new file mode 100644 index 0000000000..21ff0edfc5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-invalid-property.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +assert.throws( + TypeError, + () => instance.subtract({}), + "Throws TypeError if no property is present" +); + +assert.throws( + TypeError, + () => instance.subtract({ nonsense: true }), + "Throws TypeError if no recognized property is present" +); + +assert.throws( + TypeError, + () => instance.subtract({ sign: 1 }), + "Sign property is not recognized" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-lower-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-lower-units.js new file mode 100644 index 0000000000..ea3156580b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-lower-units.js @@ -0,0 +1,40 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Using lower units in subtract() works +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +const tests = [ + [{ days: 1 }, 2019, 11, "M11"], + [{ hours: 1 }, 2019, 11, "M11"], + [{ minutes: 1 }, 2019, 11, "M11"], + [{ seconds: 1 }, 2019, 11, "M11"], + [{ milliseconds: 1 }, 2019, 11, "M11"], + [{ microseconds: 1 }, 2019, 11, "M11"], + [{ nanoseconds: 1 }, 2019, 11, "M11"], + [{ days: 29 }, 2019, 11, "M11"], + [{ days: 30 }, 2019, 10, "M10"], + [{ days: 60 }, 2019, 10, "M10"], + [{ days: 61 }, 2019, 9, "M09"], + [{ hours: 720 }, 2019, 10, "M10"], + [{ minutes: 43200 }, 2019, 10, "M10"], + [{ seconds: 2592000 }, 2019, 10, "M10"], + [{ milliseconds: 2592000_000 }, 2019, 10, "M10"], + [{ microseconds: 2592000_000_000 }, 2019, 10, "M10"], + [{ nanoseconds: 2592000_000_000_000 }, 2019, 10, "M10"], +]; + +for (const [argument, ...expected] of tests) { + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument), ...expected, "no options"); + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument, { overflow: "constrain" }), ...expected, "constrain"); + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument, { overflow: "reject" }), ...expected, "reject"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-mixed-sign.js new file mode 100644 index 0000000000..f66b8abada --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-mixed-sign.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +["constrain", "reject"].forEach((overflow) => { + assert.throws( + RangeError, + () => instance.subtract({ hours: 1, minutes: -30 }, { overflow }), + `mixed positive and negative values always throw (overflow = "${overflow}")` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-not-object.js new file mode 100644 index 0000000000..f9460b024d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-not-object.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Passing a primitive other than string to subtract() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +assert.throws(TypeError, () => instance.subtract(undefined), "undefined"); +assert.throws(TypeError, () => instance.subtract(null), "null"); +assert.throws(TypeError, () => instance.subtract(true), "boolean"); +assert.throws(RangeError, () => instance.subtract(""), "empty string"); +assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol"); +assert.throws(TypeError, () => instance.subtract(7), "number"); +assert.throws(TypeError, () => instance.subtract(7n), "bigint"); +assert.throws(TypeError, () => instance.subtract([]), "array"); +assert.throws(TypeError, () => instance.subtract(() => {}), "function"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-object.js new file mode 100644 index 0000000000..8b7393da1d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-object.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Passing an object to subtract() works +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +const tests = [ + [{ months: 2 }, 2019, 9, "M09"], + [{ years: 1 }, 2018, 11, "M11"], + [{ months: -2 }, 2020, 1, "M01"], + [{ years: -1 }, 2020, 11, "M11"], +]; + +for (const [argument, ...expected] of tests) { + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument), ...expected, "no options"); + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument, { overflow: "constrain" }), ...expected, "constrain"); + TemporalHelpers.assertPlainYearMonth(ym.subtract(argument, { overflow: "reject" }), ...expected, "reject"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-singular-properties.js new file mode 100644 index 0000000000..779b7dbd08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-singular-properties.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +[ + { 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, () => instance.subtract(badObject), + "Throw TypeError if temporalDurationLike is not valid"); +}); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..b3e7c9a74c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string-negative-fractional-units.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +const resultHours = instance.subtract("-PT24.567890123H"); +TemporalHelpers.assertPlainYearMonth(resultHours, 2000, 5, "M05", "negative fractional hours"); + +const resultMinutes = instance.subtract("-PT1440.567890123M"); +TemporalHelpers.assertPlainYearMonth(resultMinutes, 2000, 5, "M05", "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string.js new file mode 100644 index 0000000000..deb2820797 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/argument-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); +const result = instance.subtract("P3M"); +TemporalHelpers.assertPlainYearMonth(result, 2000, 2, "M02"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/branding.js new file mode 100644 index 0000000000..badb8f195c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const subtract = Temporal.PlainYearMonth.prototype.subtract; + +assert.sameValue(typeof subtract, "function"); + +const args = [new Temporal.Duration(5)]; + +assert.throws(TypeError, () => subtract.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => subtract.apply(null, args), "null"); +assert.throws(TypeError, () => subtract.apply(true, args), "true"); +assert.throws(TypeError, () => subtract.apply("", args), "empty string"); +assert.throws(TypeError, () => subtract.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => subtract.apply(1, args), "1"); +assert.throws(TypeError, () => subtract.apply({}, args), "plain object"); +assert.throws(TypeError, () => subtract.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => subtract.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..97b965d7d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.subtract({ years: 5, months: 2 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..6b2834cf80 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dateAddOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateAdd"); +Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateAdd should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.subtract(new Temporal.Duration(1)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", dateAddOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin.js new file mode 100644 index 0000000000..e69c799d31 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: > + Tests that Temporal.PlainYearMonth.prototype.subtract + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.subtract), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.subtract), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.subtract), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.subtract.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments-extra-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments-extra-options.js new file mode 100644 index 0000000000..b636036de0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments-extra-options.js @@ -0,0 +1,53 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: plainyearmonth.prototype.subtract should pass extra fields in copied options objects. +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.extra", + "get options.extra", + // Temporal.Calendar.prototype.dateAdd + "get options.overflow", + // overwriting property in custom calendar dateAdd + "getOwnPropertyDescriptor options.overflow", +]; +const options = TemporalHelpers.propertyBagObserver(actual, { extra: 5 }, "options"); + +let dateAddCalls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(date, duration, options) { + const result = super.dateAdd(date, duration, options); + dateAddCalls++; + if (dateAddCalls == 2) + options.overflow = 'meatloaf'; + return result; + } + yearMonthFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.notSameValue(args[1], options, "args[1]"); + return super.yearMonthFromFields(...args); + } +} +const plainYearMonth = new Temporal.PlainYearMonth(2000, 3, new CustomCalendar()); +const result = plainYearMonth.subtract({ months: 5 }, options); +TemporalHelpers.assertPlainYearMonth(result, 1999, 10, "M10"); +assert.compareArray(actual, expected, "extra field options object order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments.js new file mode 100644 index 0000000000..49e74d46b8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: plainyearmonth.prototype.subtract should respect calendar arguments and pass copied options objects. +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // Temporal.Calendar.prototype.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // overwriting property in custom calendar dateAdd + "getOwnPropertyDescriptor options.overflow", + // Temporal.Calendar.prototype.yearMonthFromFields (toPrimitiveObserver copied but not options object) + "get options.overflow.toString", + "call options.overflow.toString", +]; +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +let dateAddCalls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(date, duration, options) { + const result = super.dateAdd(date, duration, options); + dateAddCalls++; + if (dateAddCalls == 2) + options.overflow = 'meatloaf'; + return result; + } + yearMonthFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.notSameValue(args[1], options, "args[1]"); + return super.yearMonthFromFields(...args); + } +} +const plainYearMonth = new Temporal.PlainYearMonth(2000, 7, new CustomCalendar()); +const result = plainYearMonth.subtract({ months: 9 }, options); +TemporalHelpers.assertPlainYearMonth(result, 1999, 10, "M10"); +assert.compareArray(actual, expected, "copied options object order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..c788dd00cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Duration subtraction from PlainYearMonth calls Calendar.dateAdd the right number of times +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddPlainDateInstance(); +const instance = new Temporal.PlainYearMonth(1983, 3, calendar); +TemporalHelpers.assertPlainYearMonth(instance.subtract({weeks: 5}), 1983, 2, 'M02', "Removing 5 weeks from March in is8601 calendar") +assert.sameValue(calendar.dateAddCallCount, 2, "dateAdd called 2 times with positive subtract"); + +calendar.dateAddCallCount = 0; +TemporalHelpers.assertPlainYearMonth(instance.subtract({weeks: -5}), 1983, 4, 'M04', "Removing -5 weeks from March in is8601 calendar") +assert.sameValue(calendar.dateAddCallCount, 1, "dateAdd called once with negative subtract"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd.js new file mode 100644 index 0000000000..72455866bc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: PlainYearMonth.prototype.subtract should call dateAdd with the appropriate values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(plainDate, duration, options) { + ++calls; + if (calls == 2) { + TemporalHelpers.assertPlainDate(plainDate, 2000, 3, "M03", 31, "plainDate argument"); + TemporalHelpers.assertDuration(duration, 0, -10, 0, 0, 0, 0, 0, 0, 0, 0, "duration argument"); + assert.sameValue(typeof options, "object", "options argument: type"); + assert.sameValue(Object.getPrototypeOf(options), null, "options argument: prototype"); + } + return super.dateAdd(plainDate, duration, options); + } +} + +const plainYearMonth = new Temporal.PlainYearMonth(2000, 3, new CustomCalendar()); +const result = plainYearMonth.subtract({ months: 10 }); +TemporalHelpers.assertPlainYearMonth(result, 1999, 5, "M05"); +assert.sameValue(calls, 2, "should have called dateAdd 2 times"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js new file mode 100644 index 0000000000..b83c3ccd36 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js @@ -0,0 +1,164 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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) { + const {isoYear, isoMonth, isoDay} = date.getISOFields(); + let {years, months, weeks, days} = duration; + let iter = new Temporal.PlainDate(isoYear + years, isoMonth, isoDay, "iso8601"); + const monthsDays = months * 36; + if (iter.dayOfYear + monthsDays > iter.daysInYear || iter.dayOfYear + monthsDays < 1) + throw new Error("complicated addition not implemented in this test"); + return iter.add({ weeks, days: monthsDays + days }).withCalendar(this); + } + 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); + +// Reference ISO dates in the custom calendar: +// M01 = 01-01 +// M02 = 02-06 +// M03 = 03-14 + +calendar.dateFromFieldsCalls = []; +TemporalHelpers.assertPlainYearMonth( + month2.subtract(lessThanOneMonth), + 2022, 2, "M02", + "subtracting positive less than one month's worth of days yields the same month", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 6 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 2, "dateFromFields was called twice"); +assert.deepEqual( + calendar.dateFromFieldsCalls[1][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 1 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 2, "dateFromFields was called twice"); +assert.deepEqual( + calendar.dateFromFieldsCalls[1][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 6 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, 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", + /* era = */ undefined, /* eraYear = */ undefined, /* referenceISODay = */ 14 +); +assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called"); +assert.deepEqual( + calendar.dateFromFieldsCalls[0][0], + { year: 2022, 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"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fields-iterable.js new file mode 100644 index 0000000000..0c5ca99437 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fields-iterable.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.subtract step 8: + 8. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.subtract({ months: 1 }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..897d365a8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Calendar.dateFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.subtract(new Temporal.Duration(1)); +assert.sameValue(calendar.dateFromFieldsCallCount, 2, "dateFromFields should have been called twice on the calendar"); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-yearmonthfromfields-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-yearmonthfromfields-called-with-null-prototype-options.js new file mode 100644 index 0000000000..b3ad583339 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-yearmonthfromfields-called-with-null-prototype-options.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Calendar.yearMonthFromFields method is called with a null-prototype object + as the options value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2019, 6, calendar); +const argument = new Temporal.Duration(1, 1); +instance.subtract(argument); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..5ee587243a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/constructor-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.subtract({days: 123})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/custom-daysInMonth-irrelevant.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/custom-daysInMonth-irrelevant.js new file mode 100644 index 0000000000..d611f5e50c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/custom-daysInMonth-irrelevant.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Subtraction of positive duration to a PlainYearMonth is not influenced by the implementation of daysInMonth() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + daysInMonth(ym, ...args) { + return 15; + } +} + +const customCalendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(2023, 3, customCalendar); + +TemporalHelpers.assertPlainYearMonth(instance.subtract({days: 30}), 2023, 3, 'M03', "Subtracting 30 days from calendar reimplementing daysinMonth()") + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/duplicate-calendar-fields.js new file mode 100644 index 0000000000..9a56dc9ee7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/duplicate-calendar-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + + assert.throws(RangeError, () => ym.subtract({days: 123})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/end-of-month-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/end-of-month-out-of-range.js new file mode 100644 index 0000000000..947f07589f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/end-of-month-out-of-range.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: RangeError thrown when subtracting positive duration and end of month is out of range +features: [Temporal] +info: | + AddDurationToOrSubtractDurationFromPlainYearMonth: + 12. If _sign_ < 0, then + a. Let _oneMonthDuration_ be ! CreateTemporalDuration(0, 1, 0, 0, 0, 0, 0, 0, 0, 0). + b. Let _nextMonth_ be ? CalendarDateAdd(_calendar_, _intermediateDate_, _oneMonthDuration_, *undefined*, _dateAdd_). + c. Let _endOfMonthISO_ be ! AddISODate(_nextMonth_.[[ISOYear]], _nextMonth_.[[ISOMonth]], _nextMonth_.[[ISODay]], 0, 0, 0, -1, *"constrain"*). + d. Let _endOfMonth_ be ? CreateTemporalDate(_endOfMonthISO_.[[Year]], _endOfMonthISO_.[[Month]], _endOfMonthISO_.[[Day]], _calendar_). +---*/ + +// Based on a test case by André Bargull <andre.bargull@gmail.com> + +const duration = new Temporal.Duration(0, 0, 0, 1); + +// Calendar addition result is out of range +assert.throws(RangeError, () => new Temporal.PlainYearMonth(275760, 9).subtract(duration), "Addition of 1 month to receiver out of range"); + +// Calendar addition succeeds, but subtracting 1 day gives out of range result +const cal = new class extends Temporal.Calendar { + dateAdd() { + return new Temporal.PlainDate(-271821, 4, 19); + } +}("iso8601"); +assert.throws(RangeError, () => new Temporal.PlainYearMonth(2000, 1, cal).subtract(duration), "Subtraction of 1 day from next month out of range"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..d529ef21c1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/infinity-throws-rangeerror.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth.prototype.subtract throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plainyearmonth.prototype.subtract +features: [Temporal] +---*/ +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); + +overflows.forEach((overflow) => { + fields.forEach((field) => { + assert.throws(RangeError, () => instance.subtract({ [field]: Infinity }, { overflow })); + }); +}); + +let calls = 0; +const obj = { + valueOf() { + calls++; + return Infinity; + } +}; + +overflows.forEach((overflow) => { + fields.forEach((field) => { + calls = 0; + assert.throws(RangeError, () => instance.subtract({ [field]: obj }, { overflow })); + assert.sameValue(calls, 1, "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/length.js new file mode 100644 index 0000000000..7b0ef46739 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.subtract.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.subtract, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/limits.js new file mode 100644 index 0000000000..6489ed09a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/limits.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: RangeError thrown when going out of range +features: [Temporal] +---*/ + +const min = Temporal.PlainYearMonth.from("-271821-04"); +for (const overflow of ["reject", "constrain"]) { + assert.throws(RangeError, () => min.subtract({ months: 1 }, { overflow }), overflow); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/month-length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/month-length.js new file mode 100644 index 0000000000..ab18f8ef9a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/month-length.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: subtract() takes month length into account +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); + +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-02").subtract({ days: 27 }), + 2019, 2, "M02"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-02").subtract({ days: 28 }), + 2019, 1, "M01"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-02").subtract({ days: 28 }), + 2020, 2, "M02"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-02").subtract({ days: 29 }), + 2020, 1, "M01"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-11").subtract({ days: 29 }), + 2019, 11, "M11"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2019-11").subtract({ days: 30 }), + 2019, 10, "M10"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-01").subtract({ days: 30 }), + 2020, 1, "M01"); +TemporalHelpers.assertPlainYearMonth(Temporal.PlainYearMonth.from("2020-01").subtract({ days: 31 }), + 2019, 12, "M12"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/name.js new file mode 100644 index 0000000000..fe1133c53d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Temporal.PlainYearMonth.prototype.subtract.name is "subtract". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.subtract, "name", { + value: "subtract", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..5412bb0f7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/negative-infinity-throws-rangeerror.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Temporal.PlainYearMonth.prototype.subtract throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plainyearmonth.prototype.subtract +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainYearMonth.from({ year: 2000, month: 5 }); + +overflows.forEach((overflow) => { + fields.forEach((field) => { + assert.throws(RangeError, () => instance.subtract({ [field]: -Infinity }, { overflow })); + }); +}); + +let calls = 0; +const obj = { + valueOf() { + calls++; + return -Infinity; + } +}; + +overflows.forEach((overflow) => { + fields.forEach((field) => { + calls = 0; + assert.throws(RangeError, () => instance.subtract({ [field]: obj }, { overflow })); + assert.sameValue(calls, 1, "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..e5073101a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/non-integer-throws-rangeerror.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const fields = [ + "years", + "months", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", +]; +fields.forEach((field) => { + assert.throws(RangeError, () => instance.subtract({ [field]: 1.5 })); + assert.throws(RangeError, () => instance.subtract({ [field]: -1.5 })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/not-a-constructor.js new file mode 100644 index 0000000000..14d79bcdd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: > + Temporal.PlainYearMonth.prototype.subtract does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.subtract(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.subtract), false, + "isConstructor(Temporal.PlainYearMonth.prototype.subtract)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-invalid.js new file mode 100644 index 0000000000..73622a2eb3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-invalid.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Invalid options throw +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-11"); +const values = [null, true, "hello", Symbol("foo"), 1, 1n]; +for (const badOptions of values) { + assert.throws(TypeError, () => ym.subtract({ years: 1 }, badOptions)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-object.js new file mode 100644 index 0000000000..7c8aa9302d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-object.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.subtract({ months: 1 }, {}); +TemporalHelpers.assertPlainYearMonth( + result1, 2019, 9, "M09", + "options may be an empty plain object" +); + +const result2 = instance.subtract({ months: 1 }, () => {}); +TemporalHelpers.assertPlainYearMonth( + result2, 2019, 9, "M09", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-undefined.js new file mode 100644 index 0000000000..fa37762e41 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-undefined.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +// overflow option has no effect on addition in the ISO calendar, so verify this +// with a custom calendar +class CheckedAdd extends Temporal.Calendar { + constructor() { + super("iso8601"); + this.called = 0; + } + dateAdd(date, duration, options, constructor) { + this.called += 1; + if (this.called == 2) + assert.notSameValue(options, undefined, "options not undefined"); + return super.dateAdd(date, duration, options, constructor); + } +} +const calendar = new CheckedAdd(); + +const yearmonth = new Temporal.PlainYearMonth(2000, 3, calendar); +const duration = { months: 1 }; + +yearmonth.subtract(duration, undefined); +assert.sameValue(calendar.called, 2, "dateAdd should have been called twice"); + +calendar.called = 0; +yearmonth.subtract(duration); +assert.sameValue(calendar.called, 2, "dateAdd should have been called twice"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js new file mode 100644 index 0000000000..cec4d21c4e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/order-of-operations.js new file mode 100644 index 0000000000..c12b7bd1a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/order-of-operations.js @@ -0,0 +1,190 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Properties on an object passed to subtract() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDuration + "get fields.days", + "get fields.days.valueOf", + "call fields.days.valueOf", + "get fields.hours", + "get fields.hours.valueOf", + "call fields.hours.valueOf", + "get fields.microseconds", + "get fields.microseconds.valueOf", + "call fields.microseconds.valueOf", + "get fields.milliseconds", + "get fields.milliseconds.valueOf", + "call fields.milliseconds.valueOf", + "get fields.minutes", + "get fields.minutes.valueOf", + "call fields.minutes.valueOf", + "get fields.months", + "get fields.months.valueOf", + "call fields.months.valueOf", + "get fields.nanoseconds", + "get fields.nanoseconds.valueOf", + "call fields.nanoseconds.valueOf", + "get fields.seconds", + "get fields.seconds.valueOf", + "call fields.seconds.valueOf", + "get fields.weeks", + "get fields.weeks.valueOf", + "call fields.weeks.valueOf", + "get fields.years", + "get fields.years.valueOf", + "call fields.years.valueOf", + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.day", + "get this.calendar.fields", + "get this.calendar.yearMonthFromFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // calculate last day of month + "call this.calendar.dateFromFields", + "call this.calendar.dateAdd", + "call this.calendar.day", + "call this.calendar.dateFromFields", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // CalendarDateAdd + "call this.calendar.dateAdd", + // inside Calendar.p.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // PrepareTemporalFields on added date + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarYearMonthFromFields + "call this.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +const fields = TemporalHelpers.propertyBagObserver(actual, { + years: 1, + months: 1, + weeks: 1, + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options"); + +instance.subtract(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +actual.splice(0); // clear + +const noCalendarExpected = [ + // ToTemporalDuration + "get fields.days", + "get fields.days.valueOf", + "call fields.days.valueOf", + "get fields.hours", + "get fields.hours.valueOf", + "call fields.hours.valueOf", + "get fields.microseconds", + "get fields.microseconds.valueOf", + "call fields.microseconds.valueOf", + "get fields.milliseconds", + "get fields.milliseconds.valueOf", + "call fields.milliseconds.valueOf", + "get fields.minutes", + "get fields.minutes.valueOf", + "call fields.minutes.valueOf", + "get fields.months", + "get fields.nanoseconds", + "get fields.nanoseconds.valueOf", + "call fields.nanoseconds.valueOf", + "get fields.seconds", + "get fields.seconds.valueOf", + "call fields.seconds.valueOf", + "get fields.weeks", + "get fields.years", + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.day", + "get this.calendar.fields", + "get this.calendar.yearMonthFromFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarDateFromFields + "call this.calendar.dateFromFields", + // calculate last day of month + "call this.calendar.dateAdd", + "call this.calendar.day", + "call this.calendar.dateFromFields", + // SnapshotOwnProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + // AddDate + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", + // PrepareTemporalFields on added date + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // CalendarYearMonthFromFields + "call this.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; + +const noCalendarFields = TemporalHelpers.propertyBagObserver(actual, { + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +instance.subtract(noCalendarFields, options); +assert.compareArray(actual, noCalendarExpected, "order of operations with no calendar units"); + +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js new file mode 100644 index 0000000000..96af1e7847 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-invalid-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: RangeError thrown when overflow option not one of the allowed string values +info: | + sec-getoption step 10: + 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.subtract steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); + +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}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-undefined.js new file mode 100644 index 0000000000..f87903ef12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-undefined.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Fallback value for overflow option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.subtract steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// In the ISO calendar, PlainYearMonth.prototype.subtract() actually ignores the +// overflow option. There is no subtraction in the ISO calendar that we could +// test which would actually show a difference between the 'constrain' and +// 'reject' values. +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); +const explicit = yearmonth.subtract(duration, { overflow: undefined }); +TemporalHelpers.assertPlainYearMonth(explicit, 1999, 4, "M04", "default overflow is constrain"); +const implicit = yearmonth.subtract(duration, {}); +TemporalHelpers.assertPlainYearMonth(implicit, 1999, 4, "M04", "default overflow is constrain"); +const lambda = yearmonth.subtract(duration, () => {}); +TemporalHelpers.assertPlainYearMonth(lambda, 1999, 4, "M04", "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-wrong-type.js new file mode 100644 index 0000000000..30a23df9cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-wrong-type.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Type conversions for overflow option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.subtract steps 13–15: + 13. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _options_). + 14. ... + 15. Return ? YearMonthFromFields(_calendar_, _addedDateFields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const duration = new Temporal.Duration(1, 1); + +// See TemporalHelpers.checkStringOptionWrongType(); this code path has +// different expectations for observable calls + +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: null }), "null"); +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: true }), "true"); +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: false }), "false"); +assert.throws(TypeError, () => yearmonth.subtract(duration, { overflow: Symbol() }), "symbol"); +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: 2 }), "number"); +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: 2n }), "bigint"); +assert.throws(RangeError, () => yearmonth.subtract(duration, { overflow: {} }), "plain object"); + +// toString property is read once by Calendar.dateAdd() and then once again by +// calendar.yearMonthFromFields(). +const expected = [ + "get overflow.toString", + "call overflow.toString", + "get overflow.toString", + "call overflow.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "constrain", "overflow"); +const result = yearmonth.subtract(duration, { overflow: observer }); +TemporalHelpers.assertPlainYearMonth(result, 1999, 4, "M04", "object with toString"); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/prop-desc.js new file mode 100644 index 0000000000..ed4a5ff063 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: The "subtract" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.subtract, + "function", + "`typeof PlainYearMonth.prototype.subtract` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "subtract", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/proto-in-calendar-fields.js new file mode 100644 index 0000000000..5660520393 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/proto-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.subtract({days: 123})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/shell.js new file mode 100644 index 0000000000..346758ebd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/shell.js @@ -0,0 +1,353 @@ +// GENERATED, DO NOT EDIT +// file: deepEqual.js +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: > + Compare two values structurally +defines: [assert.deepEqual] +---*/ + +assert.deepEqual = function(actual, expected, message) { + var format = assert.deepEqual.format; + assert( + assert.deepEqual._compare(actual, expected), + `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}` + ); +}; + +assert.deepEqual.format = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return `[Function${value.name ? `: ${value.name}` : ''}]`; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return `Date "${value.toISOString()}"`; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + let usage = seen.map.get(value); + if (usage) { + usage.used = true; + return `[Ref: #${usage.id}]`; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (typeof Map !== "undefined" && value instanceof Map) { + return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`; + } + let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`; + default: + return typeof value; + } +}; + +assert.deepEqual._compare = (function () { + var EQUAL = 1; + var NOT_EQUAL = -1; + var UNKNOWN = 0; + + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + function isOptional(value) { + return value === undefined + || value === null; + } + + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + function isValueOfEquatable(value) { + return value instanceof Date; + } + + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + function getCache(cache, left, right) { + var otherCache; + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/subclassing-ignored.js new file mode 100644 index 0000000000..14e0e703f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/subtract/subclassing-ignored.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.subtract +description: Objects of a subclass are never created as return values for subtract() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainYearMonth, + [2000, 5], + "subtract", + [{ months: 1 }], + (result) => TemporalHelpers.assertPlainYearMonth(result, 2000, 4, "M04"), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/branding.js new file mode 100644 index 0000000000..01c34dadba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tojson +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toJSON = Temporal.PlainYearMonth.prototype.toJSON; + +assert.sameValue(typeof toJSON, "function"); + +assert.throws(TypeError, () => toJSON.call(undefined), "undefined"); +assert.throws(TypeError, () => toJSON.call(null), "null"); +assert.throws(TypeError, () => toJSON.call(true), "true"); +assert.throws(TypeError, () => toJSON.call(""), "empty string"); +assert.throws(TypeError, () => toJSON.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toJSON.call(1), "1"); +assert.throws(TypeError, () => toJSON.call({}), "plain object"); +assert.throws(TypeError, () => toJSON.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => toJSON.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..4468fb65e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const idOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id"); +Object.defineProperty(Temporal.Calendar.prototype, "id", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("id should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.toJSON(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin.js new file mode 100644 index 0000000000..b33d4a9b59 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tojson +description: > + Tests that Temporal.PlainYearMonth.prototype.toJSON + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.toJSON), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.toJSON), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.toJSON), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.toJSON.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/length.js new file mode 100644 index 0000000000..89b7904e89 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.toJSON.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toJSON, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/name.js new file mode 100644 index 0000000000..9e761d32a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tojson +description: Temporal.PlainYearMonth.prototype.toJSON.name is "toJSON". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toJSON, "name", { + value: "toJSON", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/not-a-constructor.js new file mode 100644 index 0000000000..213d7d5e7a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tojson +description: > + Temporal.PlainYearMonth.prototype.toJSON does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.toJSON(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.toJSON), false, + "isConstructor(Temporal.PlainYearMonth.prototype.toJSON)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/prop-desc.js new file mode 100644 index 0000000000..326cedaeab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tojson +description: The "toJSON" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.toJSON, + "function", + "`typeof PlainYearMonth.prototype.toJSON` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "toJSON", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js new file mode 100644 index 0000000000..c988038991 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toJSON/year-format.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/branding.js new file mode 100644 index 0000000000..3effa5b45c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tolocalestring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toLocaleString = Temporal.PlainYearMonth.prototype.toLocaleString; + +assert.sameValue(typeof toLocaleString, "function"); + +assert.throws(TypeError, () => toLocaleString.call(undefined), "undefined"); +assert.throws(TypeError, () => toLocaleString.call(null), "null"); +assert.throws(TypeError, () => toLocaleString.call(true), "true"); +assert.throws(TypeError, () => toLocaleString.call(""), "empty string"); +assert.throws(TypeError, () => toLocaleString.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toLocaleString.call(1), "1"); +assert.throws(TypeError, () => toLocaleString.call({}), "plain object"); +assert.throws(TypeError, () => toLocaleString.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => toLocaleString.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..ed40d63388 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.tolocalestring +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const idOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id"); +Object.defineProperty(Temporal.Calendar.prototype, "id", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("id should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.toLocaleString(undefined, { calendar: "iso8601" }); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin.js new file mode 100644 index 0000000000..ae655de729 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tolocalestring +description: > + Tests that Temporal.PlainYearMonth.prototype.toLocaleString + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.toLocaleString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.toLocaleString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.toLocaleString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.toLocaleString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/length.js new file mode 100644 index 0000000000..ff34afa4b5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.tolocalestring +description: Temporal.PlainYearMonth.prototype.toLocaleString.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toLocaleString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/name.js new file mode 100644 index 0000000000..eceae6dcd1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tolocalestring +description: Temporal.PlainYearMonth.prototype.toLocaleString.name is "toLocaleString". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toLocaleString, "name", { + value: "toLocaleString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/not-a-constructor.js new file mode 100644 index 0000000000..7cab6ecebe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tolocalestring +description: > + Temporal.PlainYearMonth.prototype.toLocaleString does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.toLocaleString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.toLocaleString), false, + "isConstructor(Temporal.PlainYearMonth.prototype.toLocaleString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/prop-desc.js new file mode 100644 index 0000000000..9d35419db3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tolocalestring +description: The "toLocaleString" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.toLocaleString, + "function", + "`typeof PlainYearMonth.prototype.toLocaleString` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "toLocaleString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toLocaleString/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/argument-not-object.js new file mode 100644 index 0000000000..e97cf63771 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/argument-not-object.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Throws a TypeError if the argument is not an Object, before any other observable actions +includes: [compareArray.js, temporalHelpers.js] +features: [BigInt, Symbol, Temporal] +---*/ + +[null, undefined, true, 3.1416, "a string", Symbol("symbol"), 7n].forEach((primitive) => { + const calendar = TemporalHelpers.calendarThrowEverything(); + const plainYearMonth = new Temporal.PlainYearMonth(2000, 5, calendar); + assert.throws(TypeError, () => plainYearMonth.toPlainDate(primitive)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/basic.js new file mode 100644 index 0000000000..904e36750c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/basic.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Basic check for toPlainDate() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2002-01"); +TemporalHelpers.assertPlainDate(ym.toPlainDate({ day: 22 }), 2002, 1, "M01", 22); +assert.throws(TypeError, () => ym.toPlainDate({ something: "nothing" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/branding.js new file mode 100644 index 0000000000..40902ba67c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainDate = Temporal.PlainYearMonth.prototype.toPlainDate; + +assert.sameValue(typeof toPlainDate, "function"); + +const args = [{ day: 7 }]; + +assert.throws(TypeError, () => toPlainDate.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => toPlainDate.apply(null, args), "null"); +assert.throws(TypeError, () => toPlainDate.apply(true, args), "true"); +assert.throws(TypeError, () => toPlainDate.apply("", args), "empty string"); +assert.throws(TypeError, () => toPlainDate.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => toPlainDate.apply(1, args), "1"); +assert.throws(TypeError, () => toPlainDate.apply({}, args), "plain object"); +assert.throws(TypeError, () => toPlainDate.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => toPlainDate.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..470d1d697e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.toPlainDate({ day: 5 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..f271fe42cc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin-calendar-no-observable-calls.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const fieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "fields"); +Object.defineProperty(Temporal.Calendar.prototype, "fields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("fields should not be looked up"); + }, +}); +const mergeFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "mergeFields"); +Object.defineProperty(Temporal.Calendar.prototype, "mergeFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("mergeFields should not be looked up"); + }, +}); +const dateFromFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateFromFields"); +Object.defineProperty(Temporal.Calendar.prototype, "dateFromFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateFromFields should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.toPlainDate({ day: 12 }); + +Object.defineProperty(Temporal.Calendar.prototype, "fields", fieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "mergeFields", mergeFieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "dateFromFields", dateFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin.js new file mode 100644 index 0000000000..4017d9b961 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: > + Tests that Temporal.PlainYearMonth.prototype.toPlainDate + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.toPlainDate), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.toPlainDate), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.toPlainDate), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.toPlainDate.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fields-iterable.js new file mode 100644 index 0000000000..76bfe5946d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fields-iterable.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.toplaindate step 5: + 5. Let _receiverFieldNames_ be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »). + sec-temporal.plainyearmonth.prototype.toplaindate step 7: + 7. Let _inputFieldNames_ be ? CalendarFields(_calendar_, « *"day"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected1 = [ + "monthCode", + "year", +]; +const expected2 = [ + "day", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.toPlainDate({ day: 15 }); + +assert.sameValue(calendar.fieldsCallCount, 2, "fields() method called twice"); +assert.compareArray(calendar.fieldsCalledWith[0], expected1, "fields() method called first time with correct args"); +assert.compareArray(calendar.fieldsCalledWith[1], expected2, "fields() method called second time with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole first iterable"); +assert(calendar.iteratorExhausted[1], "iterated through the whole second iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..0830c5b67c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.toplaindate +description: > + Calendar.dateFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.toPlainDate({ day: 24 }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-merge-fields-returns-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-merge-fields-returns-primitive.js new file mode 100644 index 0000000000..60f61d7a64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-merge-fields-returns-primitive.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: > + with() should throw a TypeError if mergeFields() returns a primitive, + without passing the value on to any other calendar methods +includes: [compareArray.js, temporalHelpers.js] +features: [BigInt, Symbol, Temporal] +---*/ + +[undefined, null, true, 3.14159, "bad value", Symbol("no"), 7n].forEach((primitive) => { + const calendar = TemporalHelpers.calendarMergeFieldsReturnsPrimitive(primitive); + const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + assert.throws(TypeError, () => instance.toPlainDate({ day: 2 }), "bad return from mergeFields() throws"); + assert.sameValue(calendar.dateFromFieldsCallCount, 0, "dateFromFields() never called"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-mergefields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-mergefields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..5b420c1d69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-mergefields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.toplaindate +description: > + Calendar.mergeFields method is called with null-prototype fields objects +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckMergeFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.toPlainDate({ day: 24 }); +assert.sameValue(calendar.mergeFieldsCallCount, 1, "mergeFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..0bf6ede55d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/constructor-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.toPlainDate({day: 1})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/copies-merge-fields-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/copies-merge-fields-object.js new file mode 100644 index 0000000000..e786b86e42 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/copies-merge-fields-object.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: The object returned from mergeFields() is copied before being passed to monthDayFromFields(). +info: | + sec-temporal.plainyearmonth.prototype.toplaindate steps 9 and 11: + 9. Let _mergedFields_ be ? CalendarMergeFields(_calendar_, _fields_, _inputFields_). + 11. Set _mergedFields_ to ? PrepareTemporalFields(_mergedFields_, _mergedFieldNames_, «»). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get day", + "get day.valueOf", + "call day.valueOf", + "get monthCode", + "get monthCode.toString", + "call monthCode.toString", + "get year", + "get year.valueOf", + "call year.valueOf", +]; + +const calendar = TemporalHelpers.calendarMergeFieldsGetters(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.toPlainDate({ day: 2 }); + +assert.compareArray(calendar.mergeFieldsReturnOperations, expected, "getters called on mergeFields return"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js new file mode 100644 index 0000000000..6cc15dadd2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: A nonexistent resulting date is constrained to an existing date +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const febCommonYear = new Temporal.PlainYearMonth(2023, 2); +const result = febCommonYear.toPlainDate({ day: 29 }); +// 2023-02-29 does not exist because 2023 is a common year +TemporalHelpers.assertPlainDate(result, 2023, 2, "M02", 28, "2023-02 + 29 = 2023-02-28"); + +const juneAnyYear = new Temporal.PlainYearMonth(1998, 6); +const result2 = juneAnyYear.toPlainDate({ day: 31 }); +// 06-31 does not exist in any year +TemporalHelpers.assertPlainDate(result2, 1998, 6, "M06", 30, "1998-06 + 31 = 1998-06-31"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/duplicate-calendar-fields.js new file mode 100644 index 0000000000..13243c741f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/duplicate-calendar-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['monthCode'], ['year'], ['day']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + + assert.throws(RangeError, () => ym.toPlainDate({day: 1})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..327232c113 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/infinity-throws-rangeerror.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.prototype.toplaindate +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +[Infinity, -Infinity].forEach((inf) => { + assert.throws(RangeError, () => instance.toPlainDate({ day: inf }), `day property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, "day"); + assert.throws(RangeError, () => instance.toPlainDate({ day: obj })); + assert.compareArray(calls, ["get day.valueOf", "call day.valueOf"], "it fails after fetching the primitive value"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/length.js new file mode 100644 index 0000000000..27fab0fa9e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: Temporal.PlainYearMonth.prototype.toPlainDate.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toPlainDate, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/limits.js new file mode 100644 index 0000000000..78fc602c1e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/limits.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Throws a RangeError if the resulting PlainDate is out of range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const min = Temporal.PlainYearMonth.from("-271821-04"); +assert.throws(RangeError, () => min.toPlainDate({ day: 18 }), "min"); +TemporalHelpers.assertPlainDate(min.toPlainDate({ day: 19 }), + -271821, 4, "M04", 19, "min"); + +const max = Temporal.PlainYearMonth.from("+275760-09"); +assert.throws(RangeError, () => max.toPlainDate({ day: 14 }), "max"); +TemporalHelpers.assertPlainDate(max.toPlainDate({ day: 13 }), + 275760, 9, "M09", 13, "max"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/name.js new file mode 100644 index 0000000000..b40f6b1e63 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: Temporal.PlainYearMonth.prototype.toPlainDate.name is "toPlainDate". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toPlainDate, "name", { + value: "toPlainDate", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/not-a-constructor.js new file mode 100644 index 0000000000..9c6fe3cc19 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: > + Temporal.PlainYearMonth.prototype.toPlainDate does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.toPlainDate(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.toPlainDate), false, + "isConstructor(Temporal.PlainYearMonth.prototype.toPlainDate)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/prop-desc.js new file mode 100644 index 0000000000..4cbf1717e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.toplaindate +description: The "toPlainDate" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.toPlainDate, + "function", + "`typeof PlainYearMonth.prototype.toPlainDate` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "toPlainDate", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/proto-in-calendar-fields.js new file mode 100644 index 0000000000..cd560586d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/proto-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.toplaindate +description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.toPlainDate({day: 1})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/branding.js new file mode 100644 index 0000000000..aea563d4a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toString = Temporal.PlainYearMonth.prototype.toString; + +assert.sameValue(typeof toString, "function"); + +assert.throws(TypeError, () => toString.call(undefined), "undefined"); +assert.throws(TypeError, () => toString.call(null), "null"); +assert.throws(TypeError, () => toString.call(true), "true"); +assert.throws(TypeError, () => toString.call(""), "empty string"); +assert.throws(TypeError, () => toString.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toString.call(1), "1"); +assert.throws(TypeError, () => toString.call({}), "plain object"); +assert.throws(TypeError, () => toString.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => toString.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..c10fcdbef1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const idOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id"); +Object.defineProperty(Temporal.Calendar.prototype, "id", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("id should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.toString(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin.js new file mode 100644 index 0000000000..54557224d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: > + Tests that Temporal.PlainYearMonth.prototype.toString + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.toString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.toString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.toString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.toString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendar-tostring.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendar-tostring.js new file mode 100644 index 0000000000..60e9b1fd9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendar-tostring.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.protoype.tostring +description: Number of observable 'toString' calls on the calendar for each value of calendarName +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calls; +const customCalendar = { + get id() { + ++calls; + return "custom"; + }, + toString() { + TemporalHelpers.assertUnreachable('toString should not be called'); + }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const yearmonth = new Temporal.PlainYearMonth(2000, 5, customCalendar); +[ + ["always", "2000-05-01[u-ca=custom]", 1], + ["auto", "2000-05-01[u-ca=custom]", 1], + ["critical", "2000-05-01[!u-ca=custom]", 1], + ["never", "2000-05-01", 1], + [undefined, "2000-05-01[u-ca=custom]", 1], +].forEach(([calendarName, expectedResult, expectedCalls]) => { + calls = 0; + const result = yearmonth.toString({ calendarName }); + assert.sameValue(result, expectedResult, `id for calendarName = ${calendarName}`); + assert.sameValue(calls, expectedCalls, `calls to id getter for calendarName = ${calendarName}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js new file mode 100644 index 0000000000..5736e96050 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-always.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: If calendarName is "always", the calendar ID should be included. +features: [Temporal] +---*/ + +const calendarMethods = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const tests = [ + [[], "2000-05-01[u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-01[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-01[u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-01[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-01[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, ...args); + const result = yearmonth.toString({ calendarName: "always" }); + assert.sameValue(result, expected, `${description} calendar for calendarName = always`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-auto.js new file mode 100644 index 0000000000..30c4f108f5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-auto.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: If calendarName is "auto", "iso8601" should be omitted. +features: [Temporal] +---*/ + +const calendarMethods = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const tests = [ + [[], "2000-05", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-01[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-01[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-01[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, ...args); + const result = yearmonth.toString({ calendarName: "auto" }); + assert.sameValue(result, expected, `${description} calendar for calendarName = auto`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-critical.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-critical.js new file mode 100644 index 0000000000..108bbe3a60 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-critical.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + If calendarName is "calendar", the calendar ID should be included and prefixed + with "!". +features: [Temporal] +---*/ + +const calendarMethods = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const tests = [ + [[], "2000-05-01[!u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-01[!u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-01[!u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-01[!u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-01[!u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, ...args); + const result = yearmonth.toString({ calendarName: "critical" }); + assert.sameValue(result, expected, `${description} calendar for calendarName = critical`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-invalid-string.js new file mode 100644 index 0000000000..9a940adaf5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-invalid-string.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.protoype.tostring +description: RangeError thrown when calendarName option not one of the allowed string values +info: | + sec-getoption step 10: + 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-toshowcalendaroption step 1: + 1. Return ? GetOption(_normalizedOptions_, *"calendarName"*, « *"string"* », « *"auto"*, *"always"*, *"never"*, *"critical"* », *"auto"*). + sec-temporal.plainyearmonth.protoype.tostring step 4: + 4. Let _showCalendar_ be ? ToShowCalendarOption(_options_). +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const invalidValues = ["ALWAYS", "sometimes", "other string", "auto\0"]; + +for (const calendarName of invalidValues) { + assert.throws( + RangeError, + () => yearmonth.toString({ calendarName }), + `${calendarName} is an invalid value for calendarName option` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-never.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-never.js new file mode 100644 index 0000000000..c73c8ec551 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-never.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: If calendarName is "never", the calendar ID should be omitted. +features: [Temporal] +---*/ + +const calendarMethods = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const tests = [ + [[], "2000-05", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-01", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-01", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-01", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, ...args); + const result = yearmonth.toString({ calendarName: "never" }); + assert.sameValue(result, expected, `${description} calendar for calendarName = never`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-undefined.js new file mode 100644 index 0000000000..af3159efb9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-undefined.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.protoype.tostring +description: Fallback value for calendarName option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-toshowcalendaroption step 1: + 1. Return ? GetOption(_normalizedOptions_, *"calendarName"*, « *"string"* », « *"auto"*, *"always"*, *"never"*, *"critical"* », *"auto"*). + sec-temporal.plainyearmonth.protoype.tostring step 4: + 4. Let _showCalendar_ be ? ToShowCalendarOption(_options_). +features: [Temporal] +---*/ + +const calendarMethods = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const tests = [ + [[], "2000-05", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-01[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-01[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-01[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, ...args); + const result = yearmonth.toString({ calendarName: undefined }); + assert.sameValue(result, expected, `default calendarName option is auto with ${description} calendar`); + // See options-object.js for {} and options-undefined.js for absent options arg +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-wrong-type.js new file mode 100644 index 0000000000..7370fa065f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/calendarname-wrong-type.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.protoype.tostring +description: Type conversions for calendarName option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-toshowcalendaroption step 1: + 1. Return ? GetOption(_normalizedOptions_, *"calendarName"*, « *"string"* », « *"auto"*, *"always"*, *"never"*, *"critical"* », *"auto"*). + sec-temporal.plainyearmonth.protoype.tostring step 4: + 4. Let _showCalendar_ be ? ToShowCalendarOption(_options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = { + id: "custom", + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); + +TemporalHelpers.checkStringOptionWrongType("calendarName", "auto", + (calendarName) => yearmonth.toString({ calendarName }), + (result, descr) => assert.sameValue(result, "2000-05-01[u-ca=custom]", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/length.js new file mode 100644 index 0000000000..cd1685cbce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 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: Temporal.PlainYearMonth.prototype.toString.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/name.js new file mode 100644 index 0000000000..1a70a1464f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: Temporal.PlainYearMonth.prototype.toString.name is "toString". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.toString, "name", { + value: "toString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/not-a-constructor.js new file mode 100644 index 0000000000..6e1e7ddf03 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: > + Temporal.PlainYearMonth.prototype.toString does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.toString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.toString), false, + "isConstructor(Temporal.PlainYearMonth.prototype.toString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-object.js new file mode 100644 index 0000000000..e4d36a0f37 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-object.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Empty or a function object may be used as options +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.toString({}); +assert.sameValue( + result1, "2019-10", + "options may be an empty plain object" +); + +const result2 = instance.toString(() => {}); +assert.sameValue( + result2, "2019-10", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-undefined.js new file mode 100644 index 0000000000..13b358188c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-undefined.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const calendar = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "custom", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const yearmonth1 = new Temporal.PlainYearMonth(2000, 5); +const yearmonth2 = new Temporal.PlainYearMonth(2000, 5, calendar); + +[ + [yearmonth1, "2000-05"], + [yearmonth2, "2000-05-01[u-ca=custom]"], +].forEach(([yearmonth, expected]) => { + const explicit = yearmonth.toString(undefined); + assert.sameValue(explicit, expected, "default calendarName option is auto"); + + const implicit = yearmonth.toString(); + assert.sameValue(implicit, expected, "default calendarName option is auto"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js new file mode 100644 index 0000000000..0c698aa19e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/order-of-operations.js new file mode 100644 index 0000000000..3dd5392f8e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/order-of-operations.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Properties on an object passed to toString() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get options.calendarName", + "get options.calendarName.toString", + "call options.calendarName.toString", + "get this.calendar.id", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +const options = TemporalHelpers.propertyBagObserver(actual, { + calendarName: "auto", +}, "options"); + +instance.toString(options); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/prop-desc.js new file mode 100644 index 0000000000..c741e7538b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.tostring +description: The "toString" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.toString, + "function", + "`typeof PlainYearMonth.prototype.toString` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "toString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js new file mode 100644 index 0000000000..f9c1876054 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toString/year-format.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/prop-desc.js new file mode 100644 index 0000000000..12c51f56d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/prop-desc.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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-@@tostringtag +description: The @@toStringTag property of Temporal.PlainYearMonth +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype, Symbol.toStringTag, { + value: "Temporal.PlainYearMonth", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/toStringTag/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..071b4b5311 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-builtin-calendar-no-array-iteration.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method with a property bag argument with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar: "iso8601" }; +instance.until(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-casting.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-casting.js new file mode 100644 index 0000000000..1762b1bf2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-casting.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Calls to PYM.until cast arguments. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const nov94 = new Temporal.PlainYearMonth(1994, 11); +const jun13 = new Temporal.PlainYearMonth(2013, 6); +const diff = nov94.until(jun13); + +TemporalHelpers.assertDurationsEqual(nov94.until({ year: 2013, month: 6 }), diff, "Casts object argument"); +TemporalHelpers.assertDurationsEqual(nov94.until("2013-06"), diff, "Casts string argument"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-number.js new file mode 100644 index 0000000000..765d9b3208 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-number.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number is invalid in place of an ISO string for Temporal.PlainYearMonth +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const numbers = [ + 1, + 201906, + -201906, + 1234567, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.until(arg), + `A number (${arg}) is not a valid ISO string for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..607c1a84d6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-case-insensitive.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "IsO8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.until(arg); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..4293ad5c60 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-leap-second.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for a calendar in a property bag +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.until(arg); +TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..363d158d7a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-number.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; +for (const calendar of numbers) { + const arg = { year: 2019, monthCode: "M06", calendar }; + assert.throws( + TypeError, + () => instance.until(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..2254ed6c2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-string.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 6); + +const calendar = "iso8601"; + +const arg = { year: 2019, monthCode: "M06", calendar }; +const result = instance.until(arg); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..b575729f01 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-wrong-type.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when a calendar property from a property bag cannot + be converted to a calendar object or string +features: [BigInt, Symbol, Temporal] +---*/ + +const timeZone = new Temporal.TimeZone("UTC"); +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [calendar, description] of primitiveTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws( + typeof calendar === 'string' ? RangeError : TypeError, + () => instance.until(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object that doesn't implement the protocol"], + [new Temporal.TimeZone("UTC"), "time zone instance"], + [Temporal.Calendar, "Temporal.Calendar, object"], + [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields() +]; + +for (const [calendar, description] of typeErrorTests) { + const arg = { year: 2019, monthCode: "M11", day: 1, calendar }; + assert.throws(TypeError, () => instance.until(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..71400ef76d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T17:45", + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+01:00", + "-000000-10-31T17:45+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..a354acab55 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-calendar-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[u-ca=iso8601]", "without time zone"], + ["2019-12-15T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2019-12-15T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2019-12-15T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2019-12-15T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.until(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..64cb1aa2c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..0f07321125 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-date-with-utc-offset.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 12); + +const validStrings = [ + "2019-12[Africa/Abidjan]", + "2019-12[!Africa/Abidjan]", + "2019-12[u-ca=iso8601]", + "2019-12[Africa/Abidjan][u-ca=iso8601]", + "2019-12-15T00+00:00", + "2019-12-15T00+00:00[UTC]", + "2019-12-15T00+00:00[!UTC]", + "2019-12-15T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = instance.until(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `"${arg}" is a valid UTC offset with time for PlainYearMonth` + ); +} + +const invalidStrings = [ + "2022-09[u-ca=hebrew]", + "2022-09Z", + "2022-09+01:00", + "2022-09-15Z", + "2022-09-15Z[UTC]", + "2022-09-15Z[Europe/Vienna]", + "2022-09-15+00:00", + "2022-09-15+00:00[UTC]", + "2022-09-15-02:30", + "2022-09-15-02:30[America/St_Johns]", +]; + +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.until(arg), + `"${arg}" UTC offset without time is not valid for PlainYearMonth` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-invalid.js new file mode 100644 index 0000000000..9a744d64fd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-invalid.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: An invalid ISO string is never supported +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); + +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsInvalid()) { + assert.throws(RangeError, () => instance.until(arg), `"${arg}" is not a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..2b54b2263f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-calendar.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..29a0d1c74c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-separators.js new file mode 100644 index 0000000000..40e31b9143 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-separators.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23", "uppercase T"], + ["2019-12-15t15:23", "lowercase T"], + ["2019-12-15 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.until(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..f1c5a1b4fd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-time-zone-annotation.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[Asia/Kolkata]", "named, with no offset"], + ["2019-12-15T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["2019-12-15T15:23[+00:00]", "numeric, with no offset"], + ["2019-12-15T15:23[!-02:30]", "numeric, with ! and no offset"], + ["2019-12-15T15:23+00:00[UTC]", "named, with offset"], + ["2019-12-15T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["2019-12-15T15:23+00:00[+01:00]", "numeric, with offset"], + ["2019-12-15T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.until(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..c31afa03a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-unknown-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2019-12-15T15:23[foo=bar]", "alone"], + ["2019-12-15T15:23[UTC][foo=bar]", "with time zone"], + ["2019-12-15T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2019-12-15T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2019-12-15T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainYearMonth(2019, 12); + +tests.forEach(([arg, description]) => { + const result = instance.until(arg); + + TemporalHelpers.assertDuration( + result, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..f45f28a365 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-with-utc-designator.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown if a string with UTC designator is used as a PlainYearMonth +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + "String with UTC designator should not be valid as a PlainYearMonth" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string.js new file mode 100644 index 0000000000..e0cf058da2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-string.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: A string argument is parsed into a PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(1976, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValid()) { + const result = instance.until(arg); + TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `"${arg}" is a valid PlainYearMonth string`); +} + +const instanceNegativeYear = new Temporal.PlainYearMonth(-9999, 11); +for (const arg of TemporalHelpers.ISO.plainYearMonthStringsValidNegativeYear()) { + const result = instanceNegativeYear.until(arg); + TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `"${arg}" is a valid PlainYearMonth string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-wrong-type.js new file mode 100644 index 0000000000..65dde25fd0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/argument-wrong-type.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainYearMonth +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +const primitiveTests = [ + [undefined, "undefined"], + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [1n, "bigint"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => instance.until(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth, object"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.until(arg), `${description} is not a valid property bag and does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/arguments-missing-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/arguments-missing-throws.js new file mode 100644 index 0000000000..f7ae571fbd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/arguments-missing-throws.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Calls to PYM.until throw when missing required arguments. +features: [Temporal] +---*/ + +const jun13 = new Temporal.PlainYearMonth(2013, 6); + +assert.throws(TypeError, () => jun13.until({ year: 1994 }), 'Throws when missing required month'); +assert.throws(TypeError, () => jun13.until({ month: 11 }), 'Throws when missing required year'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/branding.js new file mode 100644 index 0000000000..4fa0323443 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const until = Temporal.PlainYearMonth.prototype.until; + +assert.sameValue(typeof until, "function"); + +const args = [new Temporal.PlainYearMonth(2022, 6)]; + +assert.throws(TypeError, () => until.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => until.apply(null, args), "null"); +assert.throws(TypeError, () => until.apply(true, args), "true"); +assert.throws(TypeError, () => until.apply("", args), "empty string"); +assert.throws(TypeError, () => until.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => until.apply(1, args), "1"); +assert.throws(TypeError, () => until.apply({}, args), "plain object"); +assert.throws(TypeError, () => until.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => until.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..15839e5969 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.until({ year: 2070, month: 7 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..da8a43e025 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dateUntilOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateUntil"); +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dateUntil should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.until(new Temporal.PlainYearMonth(2001, 6)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin.js new file mode 100644 index 0000000000..3ce2efa436 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: > + Tests that Temporal.PlainYearMonth.prototype.until + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.until), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.until), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.until), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.until.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..0442eba080 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: > + relativeTo parameters that are not ZonedDateTime or undefined, are always + converted to PlainDate for observable calendar calls +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarDateAddPlainDateInstance(); +const instance = new Temporal.PlainYearMonth(1970, 1, calendar); +instance.until(new Temporal.PlainYearMonth(2000, 5, calendar), { smallestUnit: "year" }); +assert(calendar.dateAddCallCount > 0, "assertions in calendar.dateAdd() should have been tested"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..532ef791a0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5); +const arg = { year: 2000, month: 5, calendar }; +instance.until(arg); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..5e362ee8ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-datefromfields-called-with-options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: 6, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..aa70bb2d12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.dateUntil method is called with a null-prototype object as the + options value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +const argument = new Temporal.PlainYearMonth(2022, 6, calendar); +instance.until(argument); +assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..3d969c6ad6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plainyearmonth.prototype.until steps 20–21: + 20. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _largestUnit_). + 21. Let _result_ be ? CalendarDateUntil(_calendar_, _thisDate_, _otherDate_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainYearMonth(2000, 5, calendar); + const later = new Temporal.PlainYearMonth(2001, 6, calendar); + earlier.until(later, { largestUnit }); + }, + { + years: ["year"], + months: ["month"] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fields-iterable.js new file mode 100644 index 0000000000..bc123e6c33 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fields-iterable.js @@ -0,0 +1,43 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.until step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal.plainyearmonth.prototype.until step 13: + 13. Let fieldNames be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »). + sec-temporal-totemporalyearmonth step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected1 = [ + "monthCode", + "year", +]; +const expected2 = [ + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +yearmonth.until({ year: 2005, month: 6, calendar: calendar2 }); + +assert.sameValue(calendar1.fieldsCallCount, 1, "fields() method not called"); +assert.compareArray(calendar1.fieldsCalledWith[0], expected1, "fields() method called with correct args"); +assert(calendar1.iteratorExhausted[0], "iterated through the whole iterable"); +assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar2.fieldsCalledWith[0], expected2, "fields() method called with correct args"); +assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..d95e655a47 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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 a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.until(new Temporal.PlainYearMonth(2019, 2)); +assert.sameValue(calendar.dateFromFieldsCallCount, 2, "dateFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-temporal-object.js new file mode 100644 index 0000000000..7e5adc104d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-temporal-object.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plainyearmonth.prototype.until step 3: + 3. Set _other_ to ? ToTemporalYearMonth(_other_). + sec-temporal-totemporalyearmonth step 2.b: + b. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_). + sec-temporal-gettemporalcalendarwithisodefault step 2: + 2. Return ? ToTemporalCalendarWithISODefault(_calendar_). + sec-temporal-totemporalcalendarwithisodefault step 2: + 3. Return ? ToTemporalCalendar(_temporalCalendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => { + const yearmonth = new Temporal.PlainYearMonth(2000, 5, temporalObject); + yearmonth.until({ year: 2005, month: 6, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..50658a49d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/calendar-yearmonthfromfields-called-with-options-undefined.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..85e8b20103 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/duplicate-calendar-fields.js new file mode 100644 index 0000000000..5d3fafbaf7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['month'], ['monthCode'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + + assert.throws(RangeError, () => instance.until(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..f738387d6e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/infinity-throws-rangeerror.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.prototype.until +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); +const base = { year: 2000, month: 5 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + assert.throws(RangeError, () => instance.until({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.until({ ...base, [prop]: obj })); + assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-auto.js new file mode 100644 index 0000000000..afbff2bee6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-auto.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: auto value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(earlier.until(later, { largestUnit: "auto" }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "auto largestUnit is year (pos)"); +TemporalHelpers.assertDuration(later.until(earlier, { largestUnit: "auto" }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "auto largestUnit is year (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-disallowed-units.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-disallowed-units.js new file mode 100644 index 0000000000..c55e4c4c77 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-disallowed-units.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Until throws on to0-small largestUnit +features: [Temporal, arrow-function] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +[ + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds" +].forEach((largestUnit) => { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `throws on disallowed or invalid largestUnit: ${largestUnit}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js new file mode 100644 index 0000000000..02ab42568f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-invalid-string.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +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`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-months.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-months.js new file mode 100644 index 0000000000..711dd53b1d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-months.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: months value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(earlier.until(later, { largestUnit: "months" }), + 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is months (pos)"); +TemporalHelpers.assertDuration(later.until(earlier, { largestUnit: "months" }), + 0, -13, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is months (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..d84a89e5f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-plurals-accepted.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const validUnits = [ + "year", + "month", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => earlier.until(later, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..e5f3042e75 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-smallestunit-mismatch.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const units = ["years", "months"]; +for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { + for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { + const largestUnit = units[largestIdx]; + const smallestUnit = units[smallestIdx]; + assert.throws(RangeError, () => earlier.until(later, { largestUnit, smallestUnit })); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-undefined.js new file mode 100644 index 0000000000..6a8ae1753f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-undefined.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(earlier.until(later, { largestUnit: undefined }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, pos)"); +TemporalHelpers.assertDuration(later.until(earlier, { largestUnit: undefined }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, neg)"); + +TemporalHelpers.assertDuration(earlier.until(later, {}), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, pos)"); +TemporalHelpers.assertDuration(later.until(earlier, {}), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, neg)"); + +TemporalHelpers.assertDuration(earlier.until(later, () => {}), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (arrow function, pos)"); +TemporalHelpers.assertDuration(later.until(earlier, () => {}), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (arrow function, neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-wrong-type.js new file mode 100644 index 0000000000..cc87b1025f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "month", + (largestUnit) => earlier.until(later, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-years.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-years.js new file mode 100644 index 0000000000..249eb4b32b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/largestunit-years.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: years value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.assertDuration(earlier.until(later, { largestUnit: "years" }), + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is years (pos)"); +TemporalHelpers.assertDuration(later.until(earlier, { largestUnit: "years" }), + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, "largestUnit is years (neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/leap-second.js new file mode 100644 index 0000000000..46b09c470c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/leap-second.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Leap second is a valid ISO string for PlainYearMonth +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2016, 12); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.until(arg); +TemporalHelpers.assertDuration( + result1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "leap second is a valid ISO string for PlainYearMonth" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +const result2 = instance.until(arg); +TemporalHelpers.assertDuration( + result2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "second: 60 is ignored in property bag for PlainYearMonth" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/length.js new file mode 100644 index 0000000000..883f548bfc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Temporal.PlainYearMonth.prototype.until.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.until, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/mixed-calendar-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/mixed-calendar-invalid.js new file mode 100644 index 0000000000..c3e00f3d99 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/mixed-calendar-invalid.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Mixed calendars throw as invalid +features: [Temporal] +---*/ + +class customCal extends Temporal.Calendar { + constructor () { + super('iso8601'); + } + + get id() { + return "I am a secret cal."; + } +} + +const ym1 = new Temporal.PlainYearMonth(2000, 1); +const ym2 = new Temporal.PlainYearMonth(2000, 1, new customCal()); + +assert.throws(RangeError, () => ym1.until(ym2), 'until throws with different calendars'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/name.js new file mode 100644 index 0000000000..191af91c8d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Temporal.PlainYearMonth.prototype.until.name is "until". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.until, "name", { + value: "until", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/not-a-constructor.js new file mode 100644 index 0000000000..be0a4a674e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: > + Temporal.PlainYearMonth.prototype.until does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.until(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.until), false, + "isConstructor(Temporal.PlainYearMonth.prototype.until)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-invalid.js new file mode 100644 index 0000000000..c29a89d3ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-invalid.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Verify that invalid options are handled correctly. +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainYearMonth(2020, 2); +const feb21 = new Temporal.PlainYearMonth(2021, 2); + +[ + null, + 1, + "hello", + true, + Symbol("foo"), + 1n +].forEach((badOption) => + assert.throws(TypeError, () => feb20.until(feb21, badOption), `${String(badOption)} throws TypeError`) +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-object.js new file mode 100644 index 0000000000..ba9bd522ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-object.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.until(new Temporal.PlainYearMonth(1976, 11), {}); +TemporalHelpers.assertDuration( + result1, -42, -11, 0, 0, 0, 0, 0, 0, 0, 0, + "options may be an empty plain object" +); + +const result2 = instance.until(new Temporal.PlainYearMonth(1976, 11), () => {}); +TemporalHelpers.assertDuration( + result2, -42, -11, 0, 0, 0, 0, 0, 0, 0, 0, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-undefined.js new file mode 100644 index 0000000000..293aeffcbe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-undefined.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Verify that undefined options are handled correctly. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2002, 12); + +TemporalHelpers.assertDuration(earlier.until(later, undefined), + 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, pos)"); +TemporalHelpers.assertDuration(later.until(earlier, undefined), + -2, -7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (explicit, neg)"); + +TemporalHelpers.assertDuration(earlier.until(later), + 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, pos)"); +TemporalHelpers.assertDuration(later.until(earlier), + -2, -7, 0, 0, 0, 0, 0, 0, 0, 0, "default largestUnit is year (implicit, neg)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js new file mode 100644 index 0000000000..d8d91f94f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js new file mode 100644 index 0000000000..bbc4f29916 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js @@ -0,0 +1,193 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expectedMinimal = [ + // ToTemporalYearMonth + "get other.calendar", + "has other.calendar.dateAdd", + "has other.calendar.dateFromFields", + "has other.calendar.dateUntil", + "has other.calendar.day", + "has other.calendar.dayOfWeek", + "has other.calendar.dayOfYear", + "has other.calendar.daysInMonth", + "has other.calendar.daysInWeek", + "has other.calendar.daysInYear", + "has other.calendar.fields", + "has other.calendar.id", + "has other.calendar.inLeapYear", + "has other.calendar.mergeFields", + "has other.calendar.month", + "has other.calendar.monthCode", + "has other.calendar.monthDayFromFields", + "has other.calendar.monthsInYear", + "has other.calendar.weekOfYear", + "has other.calendar.year", + "has other.calendar.yearMonthFromFields", + "has other.calendar.yearOfWeek", + "get other.calendar.fields", + "get other.calendar.yearMonthFromFields", + "call other.calendar.fields", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "call other.calendar.yearMonthFromFields", + // CalendarEquals + "get this.calendar.id", + "get other.calendar.id", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.roundingIncrement", + "get options.roundingIncrement", + "getOwnPropertyDescriptor options.roundingMode", + "get options.roundingMode", + "getOwnPropertyDescriptor options.largestUnit", + "get options.largestUnit", + "getOwnPropertyDescriptor options.smallestUnit", + "get options.smallestUnit", + "getOwnPropertyDescriptor options.additional", + "get options.additional", + // GetDifferenceSettings + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", +]; + +const expected = expectedMinimal.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateFromFields", + "get this.calendar.dateUntil", + "get this.calendar.fields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields / CalendarDateFromFields (receiver) + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + "call this.calendar.dateFromFields", + // PrepareTemporalFields / CalendarDateFromFields (argument) + "get other.calendar.monthCode", + "call other.calendar.monthCode", + "get other.calendar.year", + "call other.calendar.year", + "call this.calendar.dateFromFields", + // CalendarDateUntil + "call this.calendar.dateUntil", +]); +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); + +const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "months", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0); + +// code path that skips RoundDuration: +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 1 })); +assert.compareArray(actual, expected, "order of operations with no rounding"); +actual.splice(0); // clear + +// short-circuit for identical objects: +const identicalPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.until(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expectedMinimal, "order of operations with identical year-months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + // RoundDuration + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateUntil", // 7.o + "call this.calendar.dateAdd", // 7.y MoveRelativeDate + // (7.s not called because other units can't add up to >1 year at this point) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.until(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call +const otherYearMonthPropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate + // (7.o not called because months and weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.until(otherYearMonthPropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + // RoundDuration + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate + // (10.n.iii MoveRelativeDate not called because weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil" // 10.e +]); +instance.until(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 2 })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/prop-desc.js new file mode 100644 index 0000000000..ca70d809b2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: The "until" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.until, + "function", + "`typeof PlainYearMonth.prototype.until` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "until", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/proto-in-calendar-fields.js new file mode 100644 index 0000000000..cebfe1a96b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar}; +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/round-cross-unit-boundary.js new file mode 100644 index 0000000000..f570eed198 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/round-cross-unit-boundary.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2022, 1); +const later = new Temporal.PlainYearMonth(2023, 12); +const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingIncrement: 3, roundingMode: "expand" }); +TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 12 months balances to 2 years"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/rounding-zero-year-month-length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/rounding-zero-year-month-length.js new file mode 100644 index 0000000000..b714ddca6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/rounding-zero-year-month-length.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 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: > + A malicious calendar resulting in a year, month, or week length of zero is + handled correctly +info: | + RoundDuration + 10.z. If _oneYearDays_ = 0, throw a *RangeError* exception. + ... + 11.z. If _oneMonthDays_ = 0, throw a *RangeError* exception. + ... + 12.s. If _oneWeekDays_ = 0, throw a *RangeError* exception. +features: [Temporal] +---*/ + +const cal = new class extends Temporal.Calendar { + dateAdd(date, duration, options) { + // Called several times, last call sets oneYear/Month/WeekDays to 0 + return new Temporal.PlainDate(1970, 1, 1); + } +}("iso8601"); + +const ym1 = new Temporal.PlainYearMonth(1970, 1, cal); +const ym2 = new Temporal.PlainYearMonth(1971, 1, cal); + +assert.throws(RangeError, () => ym1.until(ym2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => ym1.until(ym2, { smallestUnit: "months", roundingIncrement: 2 }), "zero month length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-as-expected.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-as-expected.js new file mode 100644 index 0000000000..e9430e2d33 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-as-expected.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Until rounding increments work as expected +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const laterSinceYear = earlier.until(later, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }); +TemporalHelpers.assertDuration(laterSinceYear, + /* years = */ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of years"); + +const laterSinceMixed = earlier.until(later, { smallestUnit: "months", roundingIncrement: 5 }); +TemporalHelpers.assertDuration(laterSinceMixed, + /* years = */ 2, /* months = */ 5, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of months mixed with years"); + +const laterSinceMonth = earlier.until(later, { largestUnit: "months", smallestUnit: "months", roundingIncrement: 10 }); +TemporalHelpers.assertDuration(laterSinceMonth, + 0, /* months = */ 30, 0, 0, 0, 0, 0, 0, 0, 0, "rounds to an increment of pure months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-nan.js new file mode 100644 index 0000000000..d1f0aa1100 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-nan.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when roundingIncrement option is NaN +info: | + sec-getoption step 8.b: + b. If _value_ is *NaN*, throw a *RangeError* exception. + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-non-integer.js new file mode 100644 index 0000000000..743e0b0c87 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-non-integer.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Rounding for roundingIncrement option +info: | + ToTemporalRoundingIncrement ( _normalizedOptions_ ) + + 1. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, *"number"*, *undefined*, *1*<sub>𝔽</sub>). + 2. If _increment_ is not finite, throw a *RangeError* exception. + 3. Let _integerIncrement_ be truncate(ℝ(_increment_)). + 4. If _integerIncrement_ < 1 or _integerIncrement_ > 10<sup>9</sup>, throw a *RangeError* exception. + 5. Return _integerIncrement_. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2000, 10); +const result = earlier.until(later, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, "roundingIncrement 2.5 truncates to 2"); +// Cannot test the upper bound of 1e9 + 0.5 here, because the duration is +// rounded relative to the receiver PlainYearMonth, and 1e9 months is outside of +// the PlainYearMonth range. + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..e2540546a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-out-of-range.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when roundingIncrement option out of range +info: | + ToTemporalRoundingIncrement ( _normalizedOptions_ ) + + 1. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, *"number"*, *undefined*, *1*<sub>𝔽</sub>). + 2. If _increment_ is not finite, throw a *RangeError* exception. + 3. Let _integerIncrement_ be truncate(ℝ(_increment_)). + 4. If _integerIncrement_ < 1 or _integerIncrement_ > 10<sup>9</sup>, throw a *RangeError* exception. + 5. Return _integerIncrement_. +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2000, 10); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: -Infinity })); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: -1 })); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: 0 })); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: 0.9 })); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: 1e9 + 1 })); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: Infinity })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-undefined.js new file mode 100644 index 0000000000..8179e49442 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Fallback value for roundingIncrement option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +const explicit = earlier.until(later, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..cca7ee7078 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingincrement-wrong-type.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Type conversions for roundingIncrement option +info: | + sec-getoption step 8.a: + a. Set _value_ to ? ToNumber(value). + sec-temporal-totemporalroundingincrement step 5: + 5. Let _increment_ be ? GetOption(_normalizedOptions_, *"roundingIncrement"*, « Number », *undefined*, 1). + sec-temporal.plainyearmonth.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => earlier.until(later, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-ceil.js new file mode 100644 index 0000000000..baa45e6263 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-ceil.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-2]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "ceil"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-expand.js new file mode 100644 index 0000000000..24a911a328 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-expand.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "expand"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-floor.js new file mode 100644 index 0000000000..dbc6cc1343 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-floor.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [2], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "floor"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfCeil.js new file mode 100644 index 0000000000..d07eebdc1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfCeil.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfCeil"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfEven.js new file mode 100644 index 0000000000..9ec8af04ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfEven.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfEven"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfExpand.js new file mode 100644 index 0000000000..989b59e5ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfExpand.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfExpand"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfFloor.js new file mode 100644 index 0000000000..2bd83d6f2f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfFloor.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfFloor"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..bed39ed9e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-halfTrunc.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [3], [-3]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "halfTrunc"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-invalid-string.js new file mode 100644 index 0000000000..8e80a0c598 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-invalid-string.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +for (const roundingMode of ["other string", "cile", "CEIL", "ce\u0131l", "auto", "halfexpand", "floor\0"]) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit: "microsecond", roundingMode })); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-trunc.js new file mode 100644 index 0000000000..06dd0e1964 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-trunc.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2019, 1); +const later = new Temporal.PlainYearMonth(2021, 9); + +const expected = [ + ["years", [2], [-2]], + ["months", [2, 8], [-2, -8]], +]; + +const roundingMode = "trunc"; + +expected.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { + const [py, pm = 0, pw = 0, pd = 0, ph = 0, pmin = 0, ps = 0, pms = 0, pµs = 0, pns = 0] = expectedPositive; + const [ny, nm = 0, nw = 0, nd = 0, nh = 0, nmin = 0, ns = 0, nms = 0, nµs = 0, nns = 0] = expectedNegative; + TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit, roundingMode }), + py, pm, pw, pd, ph, pmin, ps, pms, pµs, pns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode}, positive case)` + ); + TemporalHelpers.assertDuration( + later.until(earlier, { smallestUnit, roundingMode }), + ny, nm, nw, nd, nh, nmin, ns, nms, nµs, nns, + `rounds to ${smallestUnit} (rounding mode = ${roundingMode}, negative case)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-undefined.js new file mode 100644 index 0000000000..1c73dfc3ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-undefined.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 1); + +const later1 = new Temporal.PlainYearMonth(2005, 2); +const explicit1 = earlier.until(later1, { smallestUnit: "year", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); +const implicit1 = earlier.until(later1, { smallestUnit: "year" }); +TemporalHelpers.assertDuration(implicit1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); + +const later2 = new Temporal.PlainYearMonth(2005, 12); +const explicit2 = earlier.until(later2, { smallestUnit: "year", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); +const implicit2 = earlier.until(later2, { smallestUnit: "year" }); +TemporalHelpers.assertDuration(implicit2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, "default roundingMode is trunc"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-wrong-type.js new file mode 100644 index 0000000000..4f2b3b3d8e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/roundingmode-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "trunc", + (roundingMode) => earlier.until(later, { smallestUnit: "year", roundingMode }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js new file mode 100644 index 0000000000..00a17e14d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-invalid-string.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +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`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..ae5c26042b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-plurals-accepted.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +const validUnits = [ + "year", + "month", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => earlier.until(later, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-undefined.js new file mode 100644 index 0000000000..d2f70d5b1d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-undefined.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); + +const explicit = earlier.until(later, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default smallestUnit is month"); +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "default smallestUnit is month"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-wrong-type.js new file mode 100644 index 0000000000..fddccb6ae7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/smallestunit-wrong-type.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.until +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainYearMonth(2000, 5); +const later = new Temporal.PlainYearMonth(2001, 6); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "year", + (smallestUnit) => earlier.until(later, { smallestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/year-zero.js new file mode 100644 index 0000000000..20ce83cdb0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/until/year-zero.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-06", + "-000000-06-24", + "-000000-06-24T15:43:27", + "-000000-06-24T15:43:27+01:00", + "-000000-06-24T15:43:27+00:00[UTC]", +]; +const instance = new Temporal.PlainYearMonth(2000, 5); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/basic.js new file mode 100644 index 0000000000..6ce4e91289 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/basic.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.valueof +description: Basic tests for valueOf(). +features: [Temporal] +---*/ + +const plainYearMonth = Temporal.PlainYearMonth.from("1963-02"); +const plainYearMonth2 = Temporal.PlainYearMonth.from("1963-02"); + +assert.throws(TypeError, () => plainYearMonth.valueOf(), "valueOf"); +assert.throws(TypeError, () => plainYearMonth < plainYearMonth, "<"); +assert.throws(TypeError, () => plainYearMonth <= plainYearMonth, "<="); +assert.throws(TypeError, () => plainYearMonth > plainYearMonth, ">"); +assert.throws(TypeError, () => plainYearMonth >= plainYearMonth, ">="); +assert.sameValue(plainYearMonth === plainYearMonth, true, "==="); +assert.sameValue(plainYearMonth === plainYearMonth2, false, "==="); +assert.sameValue(plainYearMonth !== plainYearMonth, false, "!=="); +assert.sameValue(plainYearMonth !== plainYearMonth2, true, "!=="); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/branding.js new file mode 100644 index 0000000000..c566f848c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.valueof +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const valueOf = Temporal.PlainYearMonth.prototype.valueOf; + +assert.sameValue(typeof valueOf, "function"); + +assert.throws(TypeError, () => valueOf.call(undefined), "undefined"); +assert.throws(TypeError, () => valueOf.call(null), "null"); +assert.throws(TypeError, () => valueOf.call(true), "true"); +assert.throws(TypeError, () => valueOf.call(""), "empty string"); +assert.throws(TypeError, () => valueOf.call(Symbol()), "symbol"); +assert.throws(TypeError, () => valueOf.call(1), "1"); +assert.throws(TypeError, () => valueOf.call({}), "plain object"); +assert.throws(TypeError, () => valueOf.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => valueOf.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/builtin.js new file mode 100644 index 0000000000..12d63be064 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.valueof +description: > + Tests that Temporal.PlainYearMonth.prototype.valueOf + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.valueOf), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.valueOf), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.valueOf), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.valueOf.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/length.js new file mode 100644 index 0000000000..bf0edd10ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.valueof +description: Temporal.PlainYearMonth.prototype.valueOf.length is 0 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.valueOf, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/name.js new file mode 100644 index 0000000000..44179950c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.valueof +description: Temporal.PlainYearMonth.prototype.valueOf.name is "valueOf". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.valueOf, "name", { + value: "valueOf", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/not-a-constructor.js new file mode 100644 index 0000000000..11d2048fe9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.valueof +description: > + Temporal.PlainYearMonth.prototype.valueOf does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.valueOf(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.valueOf), false, + "isConstructor(Temporal.PlainYearMonth.prototype.valueOf)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/prop-desc.js new file mode 100644 index 0000000000..142e78030d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.valueof +description: The "valueOf" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.valueOf, + "function", + "`typeof PlainYearMonth.prototype.valueOf` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "valueOf", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/valueOf/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-calendar-field.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-calendar-field.js new file mode 100644 index 0000000000..a51a817c86 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-calendar-field.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: Throw if the argument has a calendar field +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-10"); +assert.throws(TypeError, () => ym.with({ year: 2021, calendar: "iso8601" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-missing-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-missing-fields.js new file mode 100644 index 0000000000..fa12608d71 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-missing-fields.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: TypeError thrown when argument doesn't contain any of the supported properties +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-10"); +assert.throws(TypeError, () => ym.with({}), "No properties"); +assert.throws(TypeError, () => ym.with({ months: 12 }), "Only plural 'months' property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-timezone-field.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-timezone-field.js new file mode 100644 index 0000000000..1c502ac58f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/argument-timezone-field.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: Throw if the argument has a timeZone field +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-10"); +assert.throws(TypeError, () => ym.with({ year: 2021, timeZone: "UTC" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/basic.js new file mode 100644 index 0000000000..23e536c3ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/basic.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: Basic tests for with +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const ym = Temporal.PlainYearMonth.from("2019-10"); + +TemporalHelpers.assertPlainYearMonth(ym.with({ year: 2020 }), 2020, 10, "M10", "year"); +TemporalHelpers.assertPlainYearMonth(ym.with({ month: 9 }), 2019, 9, "M09", "month"); +TemporalHelpers.assertPlainYearMonth(ym.with({ monthCode: "M09" }), 2019, 9, "M09", "monthCode"); + +assert.throws(RangeError, () => ym.with({ month: 9, monthCode: "M10" }), "month/monthCode mismatch"); +TemporalHelpers.assertPlainYearMonth(ym.with({ month: 1, years: 2020 }), 2019, 1, "M01", "plural 'years'"); + +const withDay = ym.with({ year: 2019, get day() { throw new Test262Error("should not read the day property") } }); +TemporalHelpers.assertPlainYearMonth(withDay, 2019, 10, "M10", "day property"); +assert.sameValue(withDay.getISOFields().isoDay, 1); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/branding.js new file mode 100644 index 0000000000..cf57a3a840 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const with_ = Temporal.PlainYearMonth.prototype.with; + +assert.sameValue(typeof with_, "function"); + +const args = [{ year: 2022 }]; + +assert.throws(TypeError, () => with_.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => with_.apply(null, args), "null"); +assert.throws(TypeError, () => with_.apply(true, args), "true"); +assert.throws(TypeError, () => with_.apply("", args), "empty string"); +assert.throws(TypeError, () => with_.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => with_.apply(1, args), "1"); +assert.throws(TypeError, () => with_.apply({}, args), "plain object"); +assert.throws(TypeError, () => with_.apply(Temporal.PlainYearMonth, args), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => with_.apply(Temporal.PlainYearMonth.prototype, args), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..68911e8e03 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-array-iteration.js @@ -0,0 +1,23 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable array iteration when getting the calendar fields. +features: [Temporal] +---*/ + +const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator]; +Array.prototype[Symbol.iterator] = function arrayIterator() { + throw new Test262Error("Array should not be iterated"); +} + +const instance = new Temporal.PlainYearMonth(2023, 5, "iso8601"); +instance.with({ month: 4 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..61550c948d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin-calendar-no-observable-calls.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const fieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "fields"); +Object.defineProperty(Temporal.Calendar.prototype, "fields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("fields should not be looked up"); + }, +}); +const mergeFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "mergeFields"); +Object.defineProperty(Temporal.Calendar.prototype, "mergeFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("mergeFields should not be looked up"); + }, +}); +const yearMonthFromFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "yearMonthFromFields"); +Object.defineProperty(Temporal.Calendar.prototype, "yearMonthFromFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("yearMonthFromFields should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.with({ year: 2001 }); + +Object.defineProperty(Temporal.Calendar.prototype, "fields", fieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "mergeFields", mergeFieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "yearMonthFromFields", yearMonthFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin.js new file mode 100644 index 0000000000..f4352832ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: > + Tests that Temporal.PlainYearMonth.prototype.with + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainYearMonth.prototype.with), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainYearMonth.prototype.with), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainYearMonth.prototype.with), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainYearMonth.prototype.with.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-arguments.js new file mode 100644 index 0000000000..c7ed6aa754 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-arguments.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Correct options value is passed to calendar method +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const options = { + extra: "property", +}; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + yearMonthFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.notSameValue(args[1], options, "args[1] is a copy of options"); + assert.sameValue(args[1].extra, "property", "All properties are copied"); + assert.sameValue(Object.getPrototypeOf(args[1]), null, "Copy has null prototype"); + return super.yearMonthFromFields(...args); + } +} +const plainYearMonth = new Temporal.PlainYearMonth(2000, 7, new CustomCalendar()); +const result = plainYearMonth.with({ month: 5 }, options); +TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fields-iterable.js new file mode 100644 index 0000000000..cddf4d51e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fields-iterable.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plainyearmonth.prototype.with step 9: + 9. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "month", + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.with({ year: 2005 }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..4cc5cd6348 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: > + Calendar.yearMonthFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.with({ year: 2019 }); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1, "yearMonthFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-merge-fields-returns-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-merge-fields-returns-primitive.js new file mode 100644 index 0000000000..142b9f4be0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-merge-fields-returns-primitive.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: > + with() should throw a TypeError if mergeFields() returns a primitive, + without passing the value on to any other calendar methods +includes: [compareArray.js, temporalHelpers.js] +features: [BigInt, Symbol, Temporal] +---*/ + +[undefined, null, true, 3.14159, "bad value", Symbol("no"), 7n].forEach((primitive) => { + const calendar = TemporalHelpers.calendarMergeFieldsReturnsPrimitive(primitive); + const instance = new Temporal.PlainYearMonth(2000, 5, calendar); + assert.throws(TypeError, () => instance.with({ year: 2005 }), "bad return from mergeFields() throws"); + assert.sameValue(calendar.yearMonthFromFieldsCallCount, 0, "yearMonthFromFields() never called"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..23f00d76a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: > + Calendar.mergeFields method is called with null-prototype fields objects +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckMergeFieldsPrototypePollution(); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +instance.with({ year: 2019 }); +assert.sameValue(calendar.mergeFieldsCallCount, 1, "mergeFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..11b0ae41f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/constructor-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.with({month: 1})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copies-merge-fields-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copies-merge-fields-object.js new file mode 100644 index 0000000000..795e2f4778 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copies-merge-fields-object.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: The object returned from mergeFields() is copied before being passed to monthDayFromFields(). +info: | + sec-temporal.plainyearmonth.prototype.with steps 13–15: + 13. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialYearMonth_). + 14. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»). + 15. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get month", + "get month.valueOf", + "call month.valueOf", + "get monthCode", + "get monthCode.toString", + "call monthCode.toString", + "get year", + "get year.valueOf", + "call year.valueOf", +]; + +const calendar = TemporalHelpers.calendarMergeFieldsGetters(); +const yearmonth = new Temporal.PlainYearMonth(2000, 5, calendar); +yearmonth.with({ year: 2004 }); + +assert.compareArray(calendar.mergeFieldsReturnOperations, expected, "getters called on mergeFields return"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copy-properties-not-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copy-properties-not-undefined.js new file mode 100644 index 0000000000..ada7ba2178 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/copy-properties-not-undefined.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: PreparePartialTemporalFields copies only defined properties of source object +info: | + 4. For each value _property_ of _fieldNames_, do + a. Let _value_ be ? Get(_fields_, _property_). + b. If _value_ is not *undefined*, then + ... + iii. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainYearMonth = new Temporal.PlainYearMonth(2001, 9); + +TemporalHelpers.assertPlainYearMonth(plainYearMonth.with({ month: 11, year: undefined }), + 2001, 11, "M11", + "only the properties that are present and defined in the plain object are copied" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/duplicate-calendar-fields.js new file mode 100644 index 0000000000..4b11d1d737 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/duplicate-calendar-fields.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +for (const extra_fields of [['foo', 'foo'], ['monthCode'], ['month'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + + assert.throws(RangeError, () => ym.with({month: 1})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..1b056a39c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/infinity-throws-rangeerror.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Throws if any value in the property bag is Infinity or -Infinity +esid: sec-temporal.plainyearmonth.prototype.with +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2000, 5); + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month"].forEach((prop) => { + ["constrain", "reject"].forEach((overflow) => { + assert.throws(RangeError, () => instance.with({ [prop]: inf }, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.with({ [prop]: obj }, { overflow })); + assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value"); + }); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/length.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/length.js new file mode 100644 index 0000000000..7f8f2278ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: Temporal.PlainYearMonth.prototype.with.length is 1 +info: | + Every built-in function object, including constructors, has a "length" property whose value is + an integer. Unless otherwise specified, this value is equal to the largest number of named + arguments shown in the subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form + «...name») are not included in the default argument count. + + Unless otherwise specified, the "length" property of a built-in function object has the + attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.with, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/name.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/name.js new file mode 100644 index 0000000000..052ec04c0d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Temporal.PlainYearMonth.prototype.with.name is "with". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainYearMonth.prototype.with, "name", { + value: "with", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/not-a-constructor.js new file mode 100644 index 0000000000..7c8699125d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: > + Temporal.PlainYearMonth.prototype.with does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainYearMonth.prototype.with(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainYearMonth.prototype.with), false, + "isConstructor(Temporal.PlainYearMonth.prototype.with)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-object.js new file mode 100644 index 0000000000..bc0a3991e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-object.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainYearMonth(2019, 10); + +const result1 = instance.with({ year: 2020 }, {}); +TemporalHelpers.assertPlainYearMonth( + result1, 2020, 10, "M10", + "options may be an empty plain object" +); + +const result2 = instance.with({ year: 2020 }, () => {}); +TemporalHelpers.assertPlainYearMonth( + result2, 2020, 10, "M10", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-undefined.js new file mode 100644 index 0000000000..5544585218 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-undefined.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 2); +const fields = { month: 13 }; + +const explicit = yearmonth.with(fields, undefined); +assert.sameValue(explicit.month, 12, "default overflow is constrain"); + +const implicit = yearmonth.with(fields); +assert.sameValue(implicit.month, 12, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js new file mode 100644 index 0000000000..9c4072a17a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/options-wrong-type.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "2021-01", + Symbol(), + 1, + 2n, +]; + +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}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/order-of-operations.js new file mode 100644 index 0000000000..de2a5849d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/order-of-operations.js @@ -0,0 +1,74 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: Properties on an object passed to with() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // RejectObjectWithCalendarOrTimeZone + "get fields.calendar", + "get fields.timeZone", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + "getOwnPropertyDescriptor options.extra", + "get options.extra", + // lookup + "get this.calendar.fields", + "get this.calendar.mergeFields", + "get this.calendar.yearMonthFromFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.month", + "call this.calendar.month", + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + // PrepareTemporalFields on argument + "get fields.month", + "get fields.month.valueOf", + "call fields.month.valueOf", + "get fields.monthCode", + "get fields.monthCode.toString", + "call fields.monthCode.toString", + "get fields.year", + "get fields.year.valueOf", + "call fields.year.valueOf", + // CalendarMergeFields + "call this.calendar.mergeFields", + // CalendarYearMonthFromFields + "call this.calendar.yearMonthFromFields", + // inside Calendar.p.yearMonthFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +const fields = TemporalHelpers.propertyBagObserver(actual, { + year: 1.7, + month: 1.7, + monthCode: "M01", +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { + overflow: "constrain", + extra: "property", +}, "options"); + +instance.with(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js new file mode 100644 index 0000000000..0b0fe17833 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-invalid-string.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: RangeError thrown when overflow option not one of the allowed string values +info: | + sec-getoption step 10: + 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.with step 16: + 16. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); + +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}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-undefined.js new file mode 100644 index 0000000000..a4060fe96a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-undefined.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Fallback value for overflow option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.with step 16: + 16. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +const explicit = yearmonth.with({ month: 15 }, { overflow: undefined }); +TemporalHelpers.assertPlainYearMonth(explicit, 2000, 12, "M12", "default overflow is constrain"); +const implicit = yearmonth.with({ month: 15 }, {}); +TemporalHelpers.assertPlainYearMonth(implicit, 2000, 12, "M12", "default overflow is constrain"); +const lambda = yearmonth.with({ month: 15 }, () => {}); +TemporalHelpers.assertPlainYearMonth(lambda, 2000, 12, "M12", "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-wrong-type.js new file mode 100644 index 0000000000..6003269773 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/overflow-wrong-type.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Type conversions for overflow option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-totemporaloverflow step 1: + 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*). + sec-temporal-isoyearmonthfromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plainyearmonth.prototype.with step 16: + 16. Return ? YearMonthFromFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const yearmonth = new Temporal.PlainYearMonth(2000, 5); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => yearmonth.with({ month: 8 }, { overflow }), + (result, descr) => TemporalHelpers.assertPlainYearMonth(result, 2000, 8, "M08", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/prop-desc.js new file mode 100644 index 0000000000..4fb0f4541b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: The "with" property of Temporal.PlainYearMonth.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainYearMonth.prototype.with, + "function", + "`typeof PlainYearMonth.prototype.with` is `function`" +); + +verifyProperty(Temporal.PlainYearMonth.prototype, "with", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/proto-in-calendar-fields.js new file mode 100644 index 0000000000..b24f66a0f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/proto-in-calendar-fields.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plainyearmonth.prototype.with +description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']); +const ym = new Temporal.PlainYearMonth(2023, 5, calendar); + +assert.throws(RangeError, () => ym.with({month: 1})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/subclassing-ignored.js new file mode 100644 index 0000000000..1a7e7899da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/with/subclassing-ignored.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth.prototype.with +description: Objects of a subclass are never created as return values for with() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainYearMonth, + [2000, 5], + "with", + [{ month: 11 }], + (result) => TemporalHelpers.assertPlainYearMonth(result, 2000, 11, "M11"), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/branding.js new file mode 100644 index 0000000000..7edf70a33b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.year +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const year = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "year").get; + +assert.sameValue(typeof year, "function"); + +assert.throws(TypeError, () => year.call(undefined), "undefined"); +assert.throws(TypeError, () => year.call(null), "null"); +assert.throws(TypeError, () => year.call(true), "true"); +assert.throws(TypeError, () => year.call(""), "empty string"); +assert.throws(TypeError, () => year.call(Symbol()), "symbol"); +assert.throws(TypeError, () => year.call(1), "1"); +assert.throws(TypeError, () => year.call({}), "plain object"); +assert.throws(TypeError, () => year.call(Temporal.PlainYearMonth), "Temporal.PlainYearMonth"); +assert.throws(TypeError, () => year.call(Temporal.PlainYearMonth.prototype), "Temporal.PlainYearMonth.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..94ffaec418 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/builtin-calendar-no-observable-calls.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plainyearmonth.prototype.year +description: > + Calling the method on an instance constructed with a builtin calendar causes + no observable lookups or calls to calendar methods. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const yearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "year"); +Object.defineProperty(Temporal.Calendar.prototype, "year", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("year should not be looked up"); + }, +}); + +const instance = new Temporal.PlainYearMonth(2000, 5, "iso8601", 1); +instance.year; + +Object.defineProperty(Temporal.Calendar.prototype, "year", yearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/custom.js new file mode 100644 index 0000000000..35d879d280 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/custom.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.year +description: Custom calendar tests for year(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + year(...args) { + ++calls; + assert.compareArray(args, [instance], "year arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const instance = new Temporal.PlainYearMonth(1830, 8, calendar); +const result = instance.year; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/prop-desc.js new file mode 100644 index 0000000000..01acf1b0ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.year +description: The "year" property of Temporal.PlainYearMonth.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainYearMonth.prototype, "year"); +assert.sameValue(typeof descriptor.get, "function"); +assert.sameValue(descriptor.set, undefined); +assert.sameValue(descriptor.enumerable, false); +assert.sameValue(descriptor.configurable, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/validate-calendar-value.js new file mode 100644 index 0000000000..81ee25a1af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/prototype/year/validate-calendar-value.js @@ -0,0 +1,54 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plainyearmonth.prototype.year +description: Validate result returned from calendar year() method +features: [Temporal] +---*/ + +const badResults = [ + [undefined, TypeError], + [Infinity, RangeError], + [-Infinity, RangeError], + [Symbol("foo"), TypeError], + [7n, TypeError], + [NaN, RangeError], + ["string", TypeError], + [{}, TypeError], + [null, TypeError], + [true, TypeError], + [false, TypeError], + [7.1, RangeError], + [-0.1, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + year() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.throws(error, () => instance.year, `${typeof result} ${String(result)} not converted to integer`); +}); + +const preservedResults = [ + -7, +]; + +preservedResults.forEach(result => { + const calendar = new class extends Temporal.Calendar { + year() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainYearMonth(1981, 12, calendar); + assert.sameValue(instance.year, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/refisoday-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/refisoday-undefined.js new file mode 100644 index 0000000000..57b7d16f12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/refisoday-undefined.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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.plainyearmonth +description: referenceISODay argument defaults to 1 if not given +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const args = [2000, 5, calendar]; + +const dateExplicit = new Temporal.PlainYearMonth(...args, undefined); +assert.sameValue(dateExplicit.getISOFields().isoDay, 1, "default referenceISODay is 1"); + +const dateImplicit = new Temporal.PlainYearMonth(...args); +assert.sameValue(dateImplicit.getISOFields().isoDay, 1, "default referenceISODay is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/subclass.js b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/subclass.js new file mode 100644 index 0000000000..6b7dc1d850 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainYearMonth/subclass.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// 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: Test for Temporal.PlainYearMonth subclassing. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomPlainYearMonth extends Temporal.PlainYearMonth { +} + +const instance = new CustomPlainYearMonth(2000, 5); +TemporalHelpers.assertPlainYearMonth(instance, 2000, 5, "M05"); +assert.sameValue(Object.getPrototypeOf(instance), CustomPlainYearMonth.prototype, "Instance of CustomPlainYearMonth"); +assert(instance instanceof CustomPlainYearMonth, "Instance of CustomPlainYearMonth"); +assert(instance instanceof Temporal.PlainYearMonth, "Instance of Temporal.PlainYearMonth"); + +reportCompare(0, 0); |